@envctrl/cli 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -626,6 +626,14 @@ import path8 from "path";
626
626
  function resolveConfigPath(cwd, dir = ".envctrl", file = "config.json") {
627
627
  return path8.join(cwd, dir, file);
628
628
  }
629
+ async function readConfig(cwd, dir = ".envctrl", file = "config.json") {
630
+ try {
631
+ const raw = await fs9.readFile(resolveConfigPath(cwd, dir, file), "utf8");
632
+ return JSON.parse(raw);
633
+ } catch {
634
+ return null;
635
+ }
636
+ }
629
637
  async function writeConfig(cwd, config, dir = ".envctrl", file = "config.json") {
630
638
  const configDir = path8.join(cwd, dir);
631
639
  await fs9.mkdir(configDir, { recursive: true });
@@ -943,6 +951,145 @@ var BlacklistBaseCommand = class extends BaseCommand {
943
951
  }
944
952
  };
945
953
 
954
+ // src/commands/create/index.ts
955
+ import fs13 from "fs/promises";
956
+ import os4 from "os";
957
+ import path13 from "path";
958
+ import { createInterface } from "readline/promises";
959
+ async function listExistingEnvironments(cwd) {
960
+ const files = listEnvFiles(cwd, ".env.*", [".env.keys"]);
961
+ const names = files.map((f) => parseEnvironmentFromFilename(path13.basename(f))).filter((e) => e !== void 0);
962
+ return [...new Set(names)];
963
+ }
964
+ async function buildExampleContent(unencryptedPath) {
965
+ let raw = "";
966
+ try {
967
+ raw = await fs13.readFile(unencryptedPath, "utf8");
968
+ } catch {
969
+ return "";
970
+ }
971
+ const entries = parseEnvContent(raw);
972
+ const lines = Object.keys(entries).map((k) => `${k}=`);
973
+ return lines.length > 0 ? lines.join("\n") + "\n" : "";
974
+ }
975
+ var CreateCommand = class {
976
+ /** @inheritdoc */
977
+ async execute(options, context) {
978
+ const { environment, cwd } = { ...options, cwd: context.cwd };
979
+ try {
980
+ if (environment === "example") {
981
+ return await this.createExample(options.from, cwd);
982
+ }
983
+ const existing = await listExistingEnvironments(cwd);
984
+ if (existing.includes(environment)) {
985
+ return {
986
+ success: false,
987
+ error: `Environment "${environment}" already exists. Use "envctrl switch ${environment}" to activate it.`
988
+ };
989
+ }
990
+ return await this.createEnvironment(environment, cwd);
991
+ } catch (err) {
992
+ return {
993
+ success: false,
994
+ error: err instanceof Error ? err.message : String(err)
995
+ };
996
+ }
997
+ }
998
+ async createExample(from, cwd) {
999
+ const existing = await listExistingEnvironments(cwd);
1000
+ let base = from;
1001
+ if (!base) {
1002
+ if (existing.length === 0) {
1003
+ return {
1004
+ success: false,
1005
+ error: 'No environments found. Create one first with "envctrl create <environment>".'
1006
+ };
1007
+ }
1008
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1009
+ try {
1010
+ base = await rl.question(
1011
+ `Choose a base environment [${existing.join(", ")}]: `
1012
+ );
1013
+ } finally {
1014
+ rl.close();
1015
+ }
1016
+ }
1017
+ if (!existing.includes(base)) {
1018
+ return {
1019
+ success: false,
1020
+ error: `Environment "${base}" does not exist. Available: ${existing.join(", ")}`
1021
+ };
1022
+ }
1023
+ const pair = buildEnvFilePair(base, cwd);
1024
+ const content = await buildExampleContent(pair.unencrypted);
1025
+ const examplePath = path13.resolve(cwd, ".env.example");
1026
+ await fs13.writeFile(examplePath, content, "utf8");
1027
+ return {
1028
+ success: true,
1029
+ data: {
1030
+ environment: "example",
1031
+ createdFiles: [examplePath],
1032
+ isExample: true,
1033
+ baseEnvironment: base
1034
+ },
1035
+ message: `Created .env.example from "${base}" (${Object.keys(parseEnvContent(content)).length} keys)`
1036
+ };
1037
+ }
1038
+ async createEnvironment(environment, cwd) {
1039
+ const pair = buildEnvFilePair(environment, cwd);
1040
+ const created = [];
1041
+ await fs13.writeFile(pair.unencrypted, "", "utf8");
1042
+ created.push(pair.unencrypted);
1043
+ setKeyValue("_ENVCTRL_INIT", "1", pair.encrypted);
1044
+ created.push(pair.encrypted);
1045
+ const config = await readConfig(cwd) ?? { environment };
1046
+ await writeConfig(cwd, { ...config, environment });
1047
+ const localUnencrypted = path13.resolve(cwd, ".env.local.unencrypted");
1048
+ const localEncrypted = path13.resolve(cwd, ".env.local");
1049
+ const localExists = await fs13.access(localUnencrypted).then(() => true).catch(() => false);
1050
+ if (localExists) {
1051
+ await syncUnencryptedToEncrypted("local", cwd);
1052
+ } else {
1053
+ const encryptedLocalExists = await fs13.access(localEncrypted).then(() => true).catch(() => false);
1054
+ if (!encryptedLocalExists) {
1055
+ if (os4.platform() === "win32") {
1056
+ await fs13.copyFile(pair.encrypted, localEncrypted);
1057
+ } else {
1058
+ await fs13.symlink(pair.encrypted, localEncrypted);
1059
+ }
1060
+ created.push(localEncrypted);
1061
+ }
1062
+ }
1063
+ const lines = [
1064
+ `Created environment: ${environment}`,
1065
+ "Files:",
1066
+ ...created.map((f) => ` ${f}`)
1067
+ ];
1068
+ if (localExists) {
1069
+ lines.push(`Updated: ${localEncrypted}`);
1070
+ }
1071
+ return {
1072
+ success: true,
1073
+ data: { environment, createdFiles: created, isExample: false },
1074
+ message: lines.join("\n")
1075
+ };
1076
+ }
1077
+ };
1078
+ var CreateBaseCommand = class extends BaseCommand {
1079
+ /** @inheritdoc */
1080
+ register(program2) {
1081
+ program2.command("create <environment>").description(
1082
+ 'Create a new environment or generate .env.example (use "example" as the environment name)'
1083
+ ).option("--from <env>", "base environment for .env.example generation").action(async (environment, opts) => {
1084
+ await this.dispatch(
1085
+ new CreateCommand(),
1086
+ { environment, from: opts.from },
1087
+ this.buildContext(program2)
1088
+ );
1089
+ });
1090
+ }
1091
+ };
1092
+
946
1093
  // src/index.ts
947
1094
  var _require = createRequire2(import.meta.url);
948
1095
  var { version } = _require("../package.json");
@@ -950,6 +1097,7 @@ var program = new Command();
950
1097
  program.name("envctrl").description("Encrypted environment file manager built on dotenvx").version(version).addHelpText("beforeAll", `envctrl v${version}
951
1098
  `).option("-q, --quiet", "suppress output", false);
952
1099
  new InitBaseCommand().register(program);
1100
+ new CreateBaseCommand().register(program);
953
1101
  new ListBaseCommand().register(program);
954
1102
  new SwitchBaseCommand().register(program);
955
1103
  new KeystoreBaseCommand().register(program);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/switch/index.ts","../src/base-command.ts","../src/utils/env-files.ts","../src/utils/dotenvx.ts","../src/commands/switch/sync.ts","../src/commands/keystore/create.ts","../src/utils/platform.ts","../src/commands/keystore/registry.ts","../src/commands/keystore/list.ts","../src/commands/keystore/delete.ts","../src/commands/keystore/index.ts","../src/commands/set/index.ts","../src/commands/encrypt/index.ts","../src/commands/init/index.ts","../src/commands/init/workspace.ts","../src/utils/build-env.ts","../src/utils/config.ts","../src/commands/list/index.ts","../src/utils/blacklist.ts","../src/commands/rm/index.ts","../src/commands/blacklist/index.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { Command } from 'commander';\nimport { SwitchBaseCommand } from './commands/switch/index.js';\nimport { KeystoreBaseCommand } from './commands/keystore/index.js';\nimport { SetBaseCommand } from './commands/set/index.js';\nimport { EncryptBaseCommand } from './commands/encrypt/index.js';\nimport { InitBaseCommand } from './commands/init/index.js';\nimport { ListBaseCommand } from './commands/list/index.js';\nimport { RmBaseCommand } from './commands/rm/index.js';\nimport { BlacklistBaseCommand } from './commands/blacklist/index.js';\n\nconst _require = createRequire(import.meta.url);\nconst { version } = _require('../package.json') as { version: string };\n\nconst program = new Command();\n\nprogram\n .name('envctrl')\n .description('Encrypted environment file manager built on dotenvx')\n .version(version)\n .addHelpText('beforeAll', `envctrl v${version}\\n`)\n .option('-q, --quiet', 'suppress output', false);\n\nnew InitBaseCommand().register(program);\nnew ListBaseCommand().register(program);\nnew SwitchBaseCommand().register(program);\nnew KeystoreBaseCommand().register(program);\nnew SetBaseCommand().register(program);\nnew EncryptBaseCommand().register(program);\nnew RmBaseCommand().register(program);\nnew BlacklistBaseCommand().register(program);\n\nprogram.parseAsync(process.argv);\n","import fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, ISubCommand, SwitchResult } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { buildEnvFilePair } from '../../utils/env-files.js';\nimport { setKeyValue } from '../../utils/dotenvx.js';\nimport { syncUnencryptedToEncrypted } from './sync.js';\n\n/** Options parsed by Commander for the `switch` subcommand. */\ninterface SwitchOptions {\n environment: string;\n}\n\n/**\n * Switches the active environment.\n *\n * Creates `.env.[env].unencrypted` and `.env.[env]` if they do not exist,\n * syncs keys from the unencrypted source into the encrypted file, and\n * points `.env` at the encrypted file via symlink (POSIX) or copy (Windows).\n */\nexport class SwitchCommand implements ISubCommand<SwitchOptions, SwitchResult> {\n /** @inheritdoc */\n async execute(\n options: SwitchOptions,\n context: CommandContext,\n ): Promise<CommandResult<SwitchResult>> {\n const { environment, cwd } = { ...options, cwd: context.cwd };\n const pair = buildEnvFilePair(environment, cwd);\n const created: string[] = [];\n\n try {\n try {\n await fs.access(pair.unencrypted);\n } catch {\n await fs.writeFile(pair.unencrypted, '', 'utf8');\n created.push(pair.unencrypted);\n }\n\n const encryptedExists = await fs\n .access(pair.encrypted)\n .then(() => true)\n .catch(() => false);\n\n await syncUnencryptedToEncrypted(environment, cwd);\n\n if (!encryptedExists) {\n const stillMissing = await fs\n .access(pair.encrypted)\n .then(() => false)\n .catch(() => true);\n\n if (stillMissing) {\n setKeyValue('_ENVCTRL_INIT', '1', pair.encrypted);\n created.push(pair.encrypted);\n } else {\n created.push(pair.encrypted);\n }\n }\n\n const activePath = path.resolve(cwd, '.env');\n\n try {\n await fs.unlink(activePath);\n } catch {}\n\n if (os.platform() === 'win32') {\n await fs.copyFile(pair.encrypted, activePath);\n } else {\n await fs.symlink(pair.encrypted, activePath);\n }\n\n const lines = [`Switched to: ${environment}`];\n if (created.length > 0) {\n lines.push('Created:', ...created.map((f) => ` ${f}`));\n }\n\n return {\n success: true,\n data: { environment, created, activePath },\n message: lines.join('\\n'),\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `switch [environment]` command onto the Commander program. */\nexport class SwitchBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('switch <environment>')\n .description('Create, sync, and activate a named environment (.env.[env])')\n .action(async (environment: string) => {\n await this.dispatch(new SwitchCommand(), { environment }, this.buildContext(program));\n });\n }\n}\n","import type { Command } from 'commander';\nimport type { CommandContext, CommandResult, ISubCommand } from '@envctrl/types';\n\n/**\n * Abstract base for all top-level CLI commands.\n *\n * Subclasses implement {@link register} to attach their Commander subcommand\n * to the program. The {@link dispatch} helper handles uniform result\n * printing and process exit on failure.\n */\nexport abstract class BaseCommand {\n /**\n * Attaches this command's Commander definition onto `program`.\n *\n * @param program - The root Commander program instance\n */\n abstract register(program: Command): void;\n\n /**\n * Executes a subcommand and handles the result.\n *\n * Prints the error message to stderr and exits with code 1 on failure.\n * Prints `result.message` to stdout on success when `context.quiet` is false.\n *\n * @param cmd - The subcommand to execute\n * @param options - Parsed options from Commander\n * @param context - Injected runtime context\n */\n protected async dispatch<TOptions, TResult>(\n cmd: ISubCommand<TOptions, TResult>,\n options: TOptions,\n context: CommandContext,\n ): Promise<void> {\n const result: CommandResult<TResult> = await cmd.execute(options, context);\n\n if (!result.success) {\n process.stderr.write(`error: ${result.error ?? 'unknown error'}\\n`);\n process.exit(1);\n }\n\n if (!context.quiet && result.message !== undefined) {\n process.stdout.write(result.message + '\\n');\n }\n }\n\n /**\n * Builds a {@link CommandContext} from the Commander program's global options.\n *\n * @param program - The root Commander program instance\n */\n protected buildContext(program: Command): CommandContext {\n const opts = program.opts<{ quiet?: boolean }>();\n return {\n cwd: process.cwd(),\n quiet: opts.quiet ?? false,\n };\n }\n}\n","import path from 'node:path';\nimport type { EnvFilePair, EnvironmentName } from '@envctrl/types';\n\nconst RESERVED_ENV_NAMES = new Set(['keys', 'example']);\n\n/**\n * Derives the environment name from a `.env.*` filename, stripping `.unencrypted`\n * and `.local` suffixes. Returns `undefined` for reserved filenames like\n * `.env.keys` and `.env.example`.\n */\nexport function parseEnvironmentFromFilename(filename: string): EnvironmentName | undefined {\n const base = path.basename(filename);\n\n if (!base.startsWith('.env.')) {\n return undefined;\n }\n\n const withoutPrefix = base.slice('.env.'.length);\n\n if (!withoutPrefix || RESERVED_ENV_NAMES.has(withoutPrefix)) {\n return undefined;\n }\n\n let name = withoutPrefix.endsWith('.unencrypted')\n ? withoutPrefix.slice(0, -'.unencrypted'.length)\n : withoutPrefix;\n\n if (name.endsWith('.local')) {\n name = name.slice(0, -'.local'.length);\n }\n\n if (!name || RESERVED_ENV_NAMES.has(name)) {\n return undefined;\n }\n\n return name;\n}\n\n/**\n * Builds the {@link EnvFilePair} for a given environment name and working directory.\n *\n * @param environment - The environment name, e.g. `\"production\"`\n * @param cwd - The working directory that will contain the env files\n */\nexport function buildEnvFilePair(environment: EnvironmentName, cwd: string): EnvFilePair {\n return {\n environment,\n unencrypted: path.resolve(cwd, `.env.${environment}.unencrypted`),\n encrypted: path.resolve(cwd, `.env.${environment}`),\n };\n}\n\n/**\n * Parses KEY=VALUE pairs from a plaintext `.env` file string.\n *\n * Skips blank lines and comment lines starting with `#`.\n *\n * @param content - Raw file content\n */\nexport function parseEnvContent(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n\n if (!trimmed || trimmed.startsWith('#')) {\n continue;\n }\n\n const eqIdx = trimmed.indexOf('=');\n if (eqIdx === -1) {\n continue;\n }\n\n const key = trimmed.slice(0, eqIdx).trim();\n const value = trimmed.slice(eqIdx + 1).trim();\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Writes or updates a single `KEY=VALUE` line in a plaintext env file string.\n *\n * If the key already exists its line is replaced in-place; otherwise the\n * entry is appended.\n *\n * @param content - Current raw file content\n * @param key - The environment variable name\n * @param value - The new value\n */\nexport function upsertEnvLine(content: string, key: string, value: string): string {\n const lines = content.split('\\n');\n const pattern = new RegExp(`^${key}\\\\s*=`);\n let replaced = false;\n\n const updated = lines.map((line) => {\n if (pattern.test(line)) {\n replaced = true;\n return `${key}=${value}`;\n }\n return line;\n });\n\n if (!replaced) {\n if (updated[updated.length - 1] !== '') {\n updated.push(`${key}=${value}`);\n } else {\n updated.splice(updated.length - 1, 0, `${key}=${value}`);\n }\n }\n\n return updated.join('\\n');\n}\n","import { createRequire } from 'node:module';\nimport path from 'node:path';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport * as dotenvx from '@dotenvx/dotenvx';\nimport type { DotenvxEncryptResult, DotenvxSetResult } from '@envctrl/types';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Resolves the path to the dotenvx CLI entry script from the installed package.\n *\n * Reads the `bin` field from the package's own `package.json` to avoid\n * hardcoding the path, which can change across dotenvx versions.\n */\nfunction resolveDotenvxBin(): string {\n const require = createRequire(import.meta.url);\n const pkgJsonPath = require.resolve('@dotenvx/dotenvx/package.json');\n const pkgJson = require('@dotenvx/dotenvx/package.json') as {\n bin: Record<string, string>;\n };\n const binRelPath = pkgJson.bin['dotenvx'];\n return path.resolve(path.dirname(pkgJsonPath), binRelPath);\n}\n\n/**\n * Sets a single key-value pair in an encrypted env file using the dotenvx JS API.\n *\n * @param key - The environment variable name\n * @param value - The value to set\n * @param encryptedFilePath - Absolute path to the target `.env.[env]` file\n * @param keysFilePath - Optional path to the `.env.keys` file\n */\nexport function setKeyValue(\n key: string,\n value: string,\n encryptedFilePath: string,\n keysFilePath?: string,\n): DotenvxSetResult {\n const output = dotenvx.set(key, value, {\n path: encryptedFilePath,\n encrypt: true,\n quiet: true,\n ...(keysFilePath ? { envKeysFile: keysFilePath } : {}),\n });\n\n return {\n changedFilepaths: output.changedFilepaths,\n unchangedFilepaths: output.unchangedFilepaths,\n };\n}\n\n/**\n * Encrypts an existing plaintext env file in-place using the dotenvx CLI.\n *\n * Spawns the bundled `dotenvx encrypt -f <filePath>` process. The CLI\n * handles creating or updating the corresponding `.env.keys` entry.\n *\n * @param filePath - Absolute path to the plaintext `.env.*` file to encrypt\n */\nexport async function encryptFile(filePath: string): Promise<DotenvxEncryptResult> {\n const bin = resolveDotenvxBin();\n await execFileAsync(process.execPath, [bin, 'encrypt', '-f', filePath]);\n\n return {\n changedFilepaths: [filePath],\n unchangedFilepaths: [],\n };\n}\n\n/**\n * Lists env files in a directory using the dotenvx JS API.\n *\n * @param directory - Directory to scan\n * @param include - Glob pattern(s) to include\n * @param exclude - Glob pattern(s) to exclude\n */\nexport function listEnvFiles(\n directory: string,\n include: string | string[],\n exclude: string | string[],\n): string[] {\n return dotenvx.ls(directory, include, exclude);\n}\n","import fs from 'node:fs/promises';\nimport { parseEnvContent, buildEnvFilePair } from '../../utils/env-files.js';\nimport { setKeyValue } from '../../utils/dotenvx.js';\nimport type { EnvironmentName } from '@envctrl/types';\n\n/**\n * Syncs all keys from the unencrypted file into the encrypted file.\n *\n * Reads the plaintext `.env.[env].unencrypted` file and calls dotenvx `set`\n * for each key so the encrypted counterpart stays in sync.\n *\n * @param environment - The environment name\n * @param cwd - Working directory containing the env files\n */\nexport async function syncUnencryptedToEncrypted(\n environment: EnvironmentName,\n cwd: string,\n): Promise<void> {\n const pair = buildEnvFilePair(environment, cwd);\n\n let content: string;\n try {\n content = await fs.readFile(pair.unencrypted, 'utf8');\n } catch {\n return;\n }\n\n const entries = parseEnvContent(content);\n\n for (const [key, value] of Object.entries(entries)) {\n setKeyValue(key, value, pair.encrypted);\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { CommandContext, CommandResult, ISubCommand, KeystoreConfig } from '@envctrl/types';\nimport { resolveDefaultKeystorePath, resolveKeystoresRegistryPath } from '../../utils/platform.js';\nimport { readRegistry, writeRegistry } from './registry.js';\n\n/** Options parsed by Commander for `keystore create`. */\nexport interface KeystoreCreateOptions {\n keystorePath: string | undefined;\n name: string | undefined;\n}\n\n/**\n * Creates a new keystore directory and registers it in the global registry.\n *\n * If no path is provided, defaults to the platform-appropriate application\n * data directory. An empty `.env.keys` stub is written on first creation.\n */\nexport class KeystoreCreateSubCommand implements ISubCommand<\n KeystoreCreateOptions,\n KeystoreConfig\n> {\n /** @inheritdoc */\n async execute(\n options: KeystoreCreateOptions,\n _context: CommandContext,\n ): Promise<CommandResult<KeystoreConfig>> {\n const keystorePath = options.keystorePath ?? resolveDefaultKeystorePath();\n const name = options.name ?? path.basename(keystorePath);\n\n try {\n await fs.mkdir(keystorePath, { recursive: true });\n\n const keysFile = path.join(keystorePath, '.env.keys');\n try {\n await fs.access(keysFile);\n } catch {\n await fs.writeFile(keysFile, '# dotenvx keys\\n', 'utf8');\n }\n\n const registryPath = resolveKeystoresRegistryPath();\n await fs.mkdir(path.dirname(registryPath), { recursive: true });\n\n const registry = await readRegistry(registryPath);\n const exists = registry.some((e) => e.name === name || e.path === keystorePath);\n\n if (!exists) {\n registry.push({ name, path: keystorePath });\n await writeRegistry(registryPath, registry);\n }\n\n return {\n success: true,\n data: { path: keystorePath },\n message: `Keystore created at: ${keystorePath}`,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n","import os from 'node:os';\nimport path from 'node:path';\n\n/**\n * Resolves the envctrl application data root directory for the current platform.\n *\n * - Linux: `$XDG_DATA_HOME/envctrl` or `~/.local/share/envctrl`\n * - macOS: `~/Library/Application Support/envctrl`\n * - Windows: `%APPDATA%\\envctrl`\n */\nfunction resolveAppDataRoot(): string {\n const platform = os.platform();\n const home = os.homedir();\n\n if (platform === 'win32') {\n const appData = process.env['APPDATA'] ?? path.join(home, 'AppData', 'Roaming');\n return path.join(appData, 'envctrl');\n }\n\n if (platform === 'darwin') {\n return path.join(home, 'Library', 'Application Support', 'envctrl');\n }\n\n const xdgDataHome = process.env['XDG_DATA_HOME'] ?? path.join(home, '.local', 'share');\n return path.join(xdgDataHome, 'envctrl');\n}\n\n/**\n * Resolves the default keystore directory.\n *\n * Placed inside a `keystores/default` subdirectory of the app data root\n * so that the registry JSON file at the root level is never deleted when\n * the default keystore is removed.\n */\nexport function resolveDefaultKeystorePath(): string {\n return path.join(resolveAppDataRoot(), 'keystores', 'default');\n}\n\n/**\n * Returns the path to the global keystores registry JSON file.\n *\n * Stored at the app data root, outside any individual keystore directory,\n * so it survives keystore deletion.\n */\nexport function resolveKeystoresRegistryPath(): string {\n return path.join(resolveAppDataRoot(), 'keystores.json');\n}\n\n/** Returns the path to the blacklist JSON file. */\nexport function resolveBlacklistPath(): string {\n return path.join(resolveAppDataRoot(), 'blacklist.json');\n}\n","import fs from 'node:fs/promises';\nimport type { KeystoreEntry } from '@envctrl/types';\n\n/**\n * Reads the keystores registry JSON file.\n *\n * Returns an empty array if the file does not exist yet.\n *\n * @param registryPath - Absolute path to the `keystores.json` file\n */\nexport async function readRegistry(registryPath: string): Promise<KeystoreEntry[]> {\n try {\n const raw = await fs.readFile(registryPath, 'utf8');\n return JSON.parse(raw) as KeystoreEntry[];\n } catch {\n return [];\n }\n}\n\n/**\n * Writes the keystores registry to disk.\n *\n * @param registryPath - Absolute path to the `keystores.json` file\n * @param entries - Array of keystore entries to persist\n */\nexport async function writeRegistry(registryPath: string, entries: KeystoreEntry[]): Promise<void> {\n await fs.writeFile(registryPath, JSON.stringify(entries, null, 2) + '\\n', 'utf8');\n}\n","import type { CommandContext, CommandResult, ISubCommand, KeystoreEntry } from '@envctrl/types';\nimport { resolveKeystoresRegistryPath } from '../../utils/platform.js';\nimport { readRegistry } from './registry.js';\n\n/**\n * Lists all registered keystores from the global registry.\n *\n * Returns an empty array if no keystores have been created yet.\n */\nexport class KeystoreListSubCommand implements ISubCommand<Record<string, never>, KeystoreEntry[]> {\n /** @inheritdoc */\n async execute(\n _options: Record<string, never>,\n _context: CommandContext,\n ): Promise<CommandResult<KeystoreEntry[]>> {\n try {\n const registryPath = resolveKeystoresRegistryPath();\n const entries = await readRegistry(registryPath);\n\n let message: string;\n if (entries.length === 0) {\n message = 'No keystores registered.';\n } else {\n const maxLen = Math.max(...entries.map((e) => e.name.length));\n message = entries.map((e) => `${e.name.padEnd(maxLen)} ${e.path}`).join('\\n');\n }\n\n return { success: true, data: entries, message };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n","import fs from 'node:fs/promises';\nimport type { CommandContext, CommandResult, ISubCommand, KeystoreEntry } from '@envctrl/types';\nimport { resolveKeystoresRegistryPath } from '../../utils/platform.js';\nimport { readRegistry, writeRegistry } from './registry.js';\n\n/** Options parsed by Commander for `keystore delete`. */\nexport interface KeystoreDeleteOptions {\n name: string;\n force: boolean;\n}\n\n/**\n * Deletes a named keystore directory and removes its entry from the registry.\n *\n * Requires `--force` flag to skip the confirmation guard. Without it,\n * the command exits early with a descriptive error.\n */\nexport class KeystoreDeleteSubCommand implements ISubCommand<KeystoreDeleteOptions, KeystoreEntry> {\n /** @inheritdoc */\n async execute(\n options: KeystoreDeleteOptions,\n _context: CommandContext,\n ): Promise<CommandResult<KeystoreEntry>> {\n const { name, force } = options;\n\n try {\n const registryPath = resolveKeystoresRegistryPath();\n const registry = await readRegistry(registryPath);\n const entry = registry.find((e) => e.name === name);\n\n if (!entry) {\n return {\n success: false,\n error: `keystore \"${name}\" not found in registry`,\n };\n }\n\n if (!force) {\n return {\n success: false,\n error: `pass --force to confirm deletion of keystore \"${name}\" at ${entry.path}`,\n };\n }\n\n const updated = registry.filter((e) => e.name !== name);\n await writeRegistry(registryPath, updated);\n\n await fs.rm(entry.path, { recursive: true, force: true });\n\n return {\n success: true,\n data: entry,\n message: `Deleted keystore: ${entry.name} (${entry.path})`,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n","import type { Command } from 'commander';\nimport { BaseCommand } from '../../base-command.js';\nimport { KeystoreCreateSubCommand } from './create.js';\nimport { KeystoreListSubCommand } from './list.js';\nimport { KeystoreDeleteSubCommand } from './delete.js';\n\n/** Registers the `keystore` command group onto the Commander program. */\nexport class KeystoreBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n const keystoreCmd = program\n .command('keystore')\n .description('Manage keystore directories for dotenvx private keys');\n\n keystoreCmd\n .command('create [path]')\n .description('Create a new keystore (defaults to platform app data folder)')\n .option('-n, --name <name>', 'name for the keystore entry in the registry')\n .action(async (keystorePath: string | undefined, opts: { name?: string }) => {\n await this.dispatch(\n new KeystoreCreateSubCommand(),\n { keystorePath, name: opts.name },\n this.buildContext(program),\n );\n });\n\n keystoreCmd\n .command('list')\n .description('List all registered keystores')\n .action(async () => {\n await this.dispatch(new KeystoreListSubCommand(), {}, this.buildContext(program));\n });\n\n keystoreCmd\n .command('delete <name>')\n .description('Delete a named keystore and remove it from the registry')\n .option('--force', 'skip confirmation and delete immediately', false)\n .action(async (name: string, opts: { force: boolean }) => {\n await this.dispatch(\n new KeystoreDeleteSubCommand(),\n { name, force: opts.force },\n this.buildContext(program),\n );\n });\n }\n}\n","import fs from 'node:fs/promises';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, ISubCommand, SetResult } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { buildEnvFilePair, upsertEnvLine } from '../../utils/env-files.js';\nimport { setKeyValue } from '../../utils/dotenvx.js';\n\n/** Options parsed by Commander for the `set` subcommand. */\ninterface SetOptions {\n environment: string;\n key: string;\n value: string;\n}\n\n/**\n * Sets a single environment variable in both the unencrypted and encrypted files.\n *\n * Writes the key to the plaintext `.env.[env].unencrypted` file first to\n * maintain human-readable source of truth, then calls dotenvx `set` to\n * write and encrypt the value in `.env.[env]`.\n */\nexport class SetCommand implements ISubCommand<SetOptions, SetResult> {\n /** @inheritdoc */\n async execute(options: SetOptions, context: CommandContext): Promise<CommandResult<SetResult>> {\n const { environment, key, value } = options;\n const pair = buildEnvFilePair(environment, context.cwd);\n\n try {\n let existingContent = '';\n try {\n existingContent = await fs.readFile(pair.unencrypted, 'utf8');\n } catch {}\n\n const updatedContent = upsertEnvLine(existingContent, key, value);\n await fs.writeFile(pair.unencrypted, updatedContent, 'utf8');\n\n const result = setKeyValue(key, value, pair.encrypted);\n const changed = result.changedFilepaths.length > 0;\n\n return {\n success: true,\n data: { environment, key, changed },\n message: `Set ${key} in ${environment}`,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `set <environment> <key> <value>` command onto the Commander program. */\nexport class SetBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('set <environment> <key> <value>')\n .description('Set an environment variable and sync it to the encrypted file')\n .action(async (environment: string, key: string, value: string) => {\n await this.dispatch(\n new SetCommand(),\n { environment, key, value },\n this.buildContext(program),\n );\n });\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, EncryptResult, ISubCommand } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { parseEnvironmentFromFilename } from '../../utils/env-files.js';\nimport { listEnvFiles, encryptFile } from '../../utils/dotenvx.js';\n\n/** Options parsed by Commander for the `encrypt` subcommand. */\ninterface EncryptOptions {\n files: string[];\n}\n\n/**\n * Encrypts existing plaintext `.env.*` files using dotenvx, backing up each file's\n * content to `.env.[env].unencrypted` before encrypting in-place.\n * Defaults to all `.env.*` files in the working directory when no files are specified.\n */\nexport class EncryptCommand implements ISubCommand<EncryptOptions, EncryptResult> {\n /** @inheritdoc */\n async execute(\n options: EncryptOptions,\n context: CommandContext,\n ): Promise<CommandResult<EncryptResult>> {\n const { cwd } = context;\n\n try {\n const targets =\n options.files.length > 0\n ? options.files.map((f) => path.resolve(cwd, f))\n : listEnvFiles(cwd, '.env.*', ['.env.keys', '*.unencrypted']);\n\n const changedFiles: string[] = [];\n const unchangedFiles: string[] = [];\n\n for (const filePath of targets) {\n const basename = path.basename(filePath);\n const environment = parseEnvironmentFromFilename(basename);\n\n if (!environment) {\n unchangedFiles.push(filePath);\n continue;\n }\n\n const unencryptedPath = path.resolve(\n path.dirname(filePath),\n `.env.${environment}.unencrypted`,\n );\n\n try {\n const content = await fs.readFile(filePath, 'utf8');\n\n try {\n await fs.access(unencryptedPath);\n } catch {\n await fs.writeFile(unencryptedPath, content, 'utf8');\n }\n\n const result = await encryptFile(filePath);\n changedFiles.push(...result.changedFilepaths);\n } catch {\n unchangedFiles.push(filePath);\n }\n }\n\n const lines: string[] = [\n ...changedFiles.map((f) => `Encrypted: ${f}`),\n ...unchangedFiles.map((f) => `Unchanged: ${f}`),\n ];\n\n return {\n success: true,\n data: { changedFiles, unchangedFiles },\n message: lines.length > 0 ? lines.join('\\n') : 'No files processed.',\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `encrypt [files...]` command onto the Commander program. */\nexport class EncryptBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('encrypt [files...]')\n .description('Encrypt plaintext .env.* files and create .unencrypted backups')\n .action(async (files: string[]) => {\n await this.dispatch(new EncryptCommand(), { files }, this.buildContext(program));\n });\n }\n}\n","import fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, InitResult, ISubCommand } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { resolveDefaultKeystorePath, resolveKeystoresRegistryPath } from '../../utils/platform.js';\nimport { listEnvFiles } from '../../utils/dotenvx.js';\nimport { readRegistry, writeRegistry } from '../keystore/registry.js';\nimport { findWorkspaceRoot, scanWorkspacePackages } from './workspace.js';\nimport { detectBuildEnvironment } from '../../utils/build-env.js';\nimport { writeConfig } from '../../utils/config.js';\n\n/** Options parsed by Commander for the `init` subcommand. */\ninterface InitOptions {\n workspace: string | undefined;\n name: string | undefined;\n keystore: string | undefined;\n /** Override the config directory name (default: `.envctrl`). */\n configDir: string | undefined;\n /** Override the config file name (default: `config.json`). */\n configFile: string | undefined;\n}\n\n/**\n * Initialises envctrl for an existing workspace or monorepo by creating a shared keystore,\n * symlinking `.env.keys` into every package directory, and writing a `.envctrl/config.json`\n * that records the active environment.\n *\n * When a recognised CI/CD provider (Vercel, Netlify, Railway) is detected via environment\n * variables, the environment is automatically resolved from the provider context instead of\n * defaulting to `\"development\"`.\n */\nexport class InitCommand implements ISubCommand<InitOptions, InitResult> {\n /** @inheritdoc */\n async execute(options: InitOptions, context: CommandContext): Promise<CommandResult<InitResult>> {\n const startDir = options.workspace\n ? path.resolve(context.cwd, options.workspace)\n : context.cwd;\n\n const configDir = options.configDir ?? '.envctrl';\n const configFile = options.configFile ?? 'config.json';\n\n try {\n const workspaceRoot = await findWorkspaceRoot(startDir);\n const packages = await scanWorkspacePackages(workspaceRoot);\n\n const keystorePath = options.keystore ?? resolveDefaultKeystorePath();\n const keystoreName = options.name ?? path.basename(workspaceRoot);\n\n await fs.mkdir(keystorePath, { recursive: true });\n\n const keysFile = path.join(keystorePath, '.env.keys');\n try {\n await fs.access(keysFile);\n } catch {\n await fs.writeFile(keysFile, '# dotenvx keys\\n', 'utf8');\n }\n\n const registryPath = resolveKeystoresRegistryPath();\n await fs.mkdir(path.dirname(registryPath), { recursive: true });\n const registry = await readRegistry(registryPath);\n const alreadyRegistered = registry.some(\n (e) => e.name === keystoreName || e.path === keystorePath,\n );\n if (!alreadyRegistered) {\n registry.push({ name: keystoreName, path: keystorePath });\n await writeRegistry(registryPath, registry);\n }\n\n const linkTargets = [\n workspaceRoot,\n ...packages.map((p) => path.resolve(workspaceRoot, p.path)),\n ];\n\n const keysLinked: string[] = [];\n\n for (const dir of linkTargets) {\n const envFiles = listEnvFiles(dir, '.env.*', ['.env.keys']);\n if (envFiles.length === 0) continue;\n\n const linkPath = path.join(dir, '.env.keys');\n try {\n await fs.access(linkPath);\n } catch {\n if (os.platform() === 'win32') {\n await fs.copyFile(keysFile, linkPath);\n } else {\n await fs.symlink(keysFile, linkPath);\n }\n keysLinked.push(linkPath);\n }\n }\n\n const buildEnv = detectBuildEnvironment();\n const environment = buildEnv.environment ?? 'development';\n const autoDetected = buildEnv.provider !== null;\n\n const configPath = await writeConfig(\n context.cwd,\n { environment },\n configDir,\n configFile,\n );\n\n const lines = [`Workspace: ${workspaceRoot}`, `Keystore: ${keystorePath}`];\n if (packages.length > 0) {\n lines.push('Packages:');\n for (const p of packages) lines.push(` ${p.name} (${p.path})`);\n }\n if (keysLinked.length > 0) {\n lines.push('Linked .env.keys:');\n for (const l of keysLinked) lines.push(` ${l}`);\n }\n lines.push(\n `Config: ${configPath}`,\n `Environment: ${environment}${autoDetected ? ` (auto-detected from ${buildEnv.provider})` : ''}`,\n );\n\n return {\n success: true,\n data: { workspaceRoot, packages, keystorePath, keysLinked, configPath, environment, autoDetected },\n message: lines.join('\\n'),\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `init [workspace]` command onto the Commander program. */\nexport class InitBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('init [workspace]')\n .description(\n 'Scan the workspace or monorepo and link packages to a shared keystore',\n )\n .option('-n, --name <name>', 'name for the keystore entry in the registry')\n .option('-k, --keystore <path>', 'custom keystore directory path')\n .option('--config-dir <dir>', 'config directory name (default: .envctrl)')\n .option('--config-file <file>', 'config file name (default: config.json)')\n .action(\n async (\n workspace: string | undefined,\n opts: { name?: string; keystore?: string; configDir?: string; configFile?: string },\n ) => {\n await this.dispatch(\n new InitCommand(),\n {\n workspace,\n name: opts.name,\n keystore: opts.keystore,\n configDir: opts.configDir,\n configFile: opts.configFile,\n },\n this.buildContext(program),\n );\n },\n );\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { WorkspacePackage } from '@envctrl/types';\n\n/**\n * Traverses up from `startDir` to find the workspace root.\n *\n * A directory is considered the workspace root if it contains\n * `pnpm-workspace.yaml` or a `package.json` with a `workspaces` field.\n * Falls back to `startDir` if no root is found.\n */\nexport async function findWorkspaceRoot(startDir: string): Promise<string> {\n let dir = startDir;\n\n while (true) {\n try {\n await fs.access(path.join(dir, 'pnpm-workspace.yaml'));\n return dir;\n } catch {}\n\n try {\n const raw = await fs.readFile(path.join(dir, 'package.json'), 'utf8');\n const pkg = JSON.parse(raw) as { workspaces?: unknown };\n if (pkg.workspaces) return dir;\n } catch {}\n\n const parent = path.dirname(dir);\n if (parent === dir) return startDir;\n dir = parent;\n }\n}\n\n/**\n * Reads workspace package glob patterns from `pnpm-workspace.yaml` or\n * the `workspaces` field in `package.json`.\n */\nasync function readWorkspacePatterns(workspaceRoot: string): Promise<string[]> {\n try {\n const raw = await fs.readFile(path.join(workspaceRoot, 'pnpm-workspace.yaml'), 'utf8');\n const patterns: string[] = [];\n let inPackages = false;\n\n for (const line of raw.split('\\n')) {\n if (/^packages\\s*:/.test(line)) {\n inPackages = true;\n continue;\n }\n if (inPackages) {\n const match = line.match(/^\\s+-\\s+['\"]?([^'\"]+)['\"]?/);\n if (match) {\n patterns.push(match[1].trim());\n } else if (line.trim() && !line.startsWith('#')) {\n break;\n }\n }\n }\n\n if (patterns.length > 0) return patterns;\n } catch {}\n\n try {\n const raw = await fs.readFile(path.join(workspaceRoot, 'package.json'), 'utf8');\n const pkg = JSON.parse(raw) as {\n workspaces?: string[] | { packages: string[] };\n };\n if (Array.isArray(pkg.workspaces)) return pkg.workspaces;\n if (pkg.workspaces?.packages) return pkg.workspaces.packages;\n } catch {}\n\n return [];\n}\n\n/**\n * Expands a single workspace glob pattern (supporting one trailing `*`) into\n * matching subdirectory paths under `workspaceRoot`.\n */\nasync function expandPattern(workspaceRoot: string, pattern: string): Promise<string[]> {\n if (!pattern.includes('*')) {\n return [path.resolve(workspaceRoot, pattern)];\n }\n\n const starIndex = pattern.indexOf('*');\n const baseRelative = pattern.slice(0, starIndex).replace(/\\/$/, '');\n const suffix = pattern.slice(starIndex + 1);\n const baseDir = path.resolve(workspaceRoot, baseRelative);\n\n try {\n const entries = await fs.readdir(baseDir, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => path.join(baseDir, e.name + suffix));\n } catch {\n return [];\n }\n}\n\n/**\n * Scans `workspaceRoot` for all packages by expanding workspace glob patterns\n * and filtering directories that contain a `package.json`.\n */\nexport async function scanWorkspacePackages(workspaceRoot: string): Promise<WorkspacePackage[]> {\n const patterns = await readWorkspacePatterns(workspaceRoot);\n const packages: WorkspacePackage[] = [];\n\n for (const pattern of patterns) {\n const dirs = await expandPattern(workspaceRoot, pattern);\n\n for (const dir of dirs) {\n try {\n const raw = await fs.readFile(path.join(dir, 'package.json'), 'utf8');\n const pkg = JSON.parse(raw) as { name?: string };\n if (pkg.name) {\n packages.push({\n name: pkg.name,\n path: path.relative(workspaceRoot, dir),\n });\n }\n } catch {}\n }\n }\n\n return packages;\n}\n","/** Known CI/CD providers that supply their own environment context. */\nexport type BuildProvider = 'vercel' | 'netlify' | 'railway';\n\n/** Result of probing the current process environment for a CI/CD context. */\nexport interface DetectedBuildEnv {\n /** The provider that was identified, or `null` when no provider is detected. */\n readonly provider: BuildProvider | null;\n /**\n * The canonical environment name derived from the provider's own variables.\n * `null` when no provider is detected.\n */\n readonly environment: 'production' | 'development' | null;\n}\n\n/**\n * Inspects `process.env` for well-known CI/CD provider variables and maps\n * them to a canonical `production` / `development` environment name.\n *\n * - **Vercel** – `VERCEL=1`; `VERCEL_ENV` is `production` | `preview` | `development`\n * - **Netlify** – `NETLIFY=true`; `CONTEXT` is `production` | `deploy-preview` | `branch-deploy` | `dev`\n * - **Railway** – `RAILWAY_ENVIRONMENT_NAME` holds the environment name directly\n */\nexport function detectBuildEnvironment(): DetectedBuildEnv {\n if (process.env['VERCEL'] === '1') {\n const vercelEnv = process.env['VERCEL_ENV'];\n return {\n provider: 'vercel',\n environment: vercelEnv === 'production' ? 'production' : 'development',\n };\n }\n\n if (process.env['NETLIFY'] === 'true') {\n const context = process.env['CONTEXT'];\n return {\n provider: 'netlify',\n environment: context === 'production' ? 'production' : 'development',\n };\n }\n\n if (process.env['RAILWAY_ENVIRONMENT_NAME'] !== undefined) {\n const railwayEnv = process.env['RAILWAY_ENVIRONMENT_NAME'];\n return {\n provider: 'railway',\n environment: railwayEnv === 'production' ? 'production' : 'development',\n };\n }\n\n return { provider: null, environment: null };\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { EnvctrlConfig } from '@envctrl/types';\n\n/**\n * Returns the absolute path to the envctrl config file.\n *\n * @param cwd - Base directory (typically the project root).\n * @param dir - Config directory name relative to `cwd`. Defaults to `.envctrl`.\n * @param file - Config file name inside `dir`. Defaults to `config.json`.\n */\nexport function resolveConfigPath(\n cwd: string,\n dir = '.envctrl',\n file = 'config.json',\n): string {\n return path.join(cwd, dir, file);\n}\n\n/**\n * Reads and parses the envctrl config file.\n * Returns `null` when the file does not exist or cannot be parsed.\n *\n * @param cwd - Base directory (typically the project root).\n * @param dir - Config directory name relative to `cwd`. Defaults to `.envctrl`.\n * @param file - Config file name inside `dir`. Defaults to `config.json`.\n */\nexport async function readConfig(\n cwd: string,\n dir = '.envctrl',\n file = 'config.json',\n): Promise<EnvctrlConfig | null> {\n try {\n const raw = await fs.readFile(resolveConfigPath(cwd, dir, file), 'utf8');\n return JSON.parse(raw) as EnvctrlConfig;\n } catch {\n return null;\n }\n}\n\n/**\n * Writes `config` as JSON, creating the config directory if needed.\n *\n * @param cwd - Base directory (typically the project root).\n * @param config - Configuration object to persist.\n * @param dir - Config directory name relative to `cwd`. Defaults to `.envctrl`.\n * @param file - Config file name inside `dir`. Defaults to `config.json`.\n * @returns The absolute path of the written file.\n */\nexport async function writeConfig(\n cwd: string,\n config: EnvctrlConfig,\n dir = '.envctrl',\n file = 'config.json',\n): Promise<string> {\n const configDir = path.join(cwd, dir);\n await fs.mkdir(configDir, { recursive: true });\n const configPath = resolveConfigPath(cwd, dir, file);\n await fs.writeFile(configPath, JSON.stringify(config, null, 2) + '\\n', 'utf8');\n return configPath;\n}\n","import path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, EnvironmentName, ISubCommand, ListResult } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { listEnvFiles } from '../../utils/dotenvx.js';\nimport { readBlacklist } from '../../utils/blacklist.js';\nimport { parseEnvironmentFromFilename } from '../../utils/env-files.js';\n\n/**\n * Lists all unique environment names discovered in the working directory by\n * scanning `.env.*` files, normalising `.local` and `.unencrypted` suffixes,\n * and filtering out blacklisted names.\n */\nexport class ListCommand implements ISubCommand<Record<string, never>, ListResult> {\n /** @inheritdoc */\n async execute(\n _options: Record<string, never>,\n context: CommandContext,\n ): Promise<CommandResult<ListResult>> {\n try {\n const [files, blacklist] = await Promise.all([\n Promise.resolve(listEnvFiles(context.cwd, '.env.*', ['.env.keys'])),\n readBlacklist(),\n ]);\n const blacklisted = new Set(blacklist);\n const names = files\n .map((f) => parseEnvironmentFromFilename(path.basename(f)))\n .filter((e): e is EnvironmentName => e !== undefined && !blacklisted.has(e));\n const environments = [...new Set(names)].sort();\n\n const message =\n environments.length > 0 ? environments.join('\\n') : 'No environments found.';\n\n return { success: true, data: { environments }, message };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `list` command onto the Commander program. */\nexport class ListBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('list')\n .description('List all environment names discovered in the working directory')\n .action(async () => {\n await this.dispatch(new ListCommand(), {}, this.buildContext(program));\n });\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { EnvironmentName } from '@envctrl/types';\nimport { resolveBlacklistPath } from './platform.js';\n\n/** Reads the blacklist from disk, returning an empty array if it does not exist. */\nexport async function readBlacklist(): Promise<EnvironmentName[]> {\n try {\n const raw = await fs.readFile(resolveBlacklistPath(), 'utf8');\n return JSON.parse(raw) as EnvironmentName[];\n } catch {\n return [];\n }\n}\n\n/** Writes the blacklist to disk. */\nexport async function writeBlacklist(entries: EnvironmentName[]): Promise<void> {\n const filePath = resolveBlacklistPath();\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, JSON.stringify(entries, null, 2) + '\\n', 'utf8');\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, EnvironmentName, ISubCommand, RemoveResult } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { listEnvFiles } from '../../utils/dotenvx.js';\nimport { parseEnvironmentFromFilename } from '../../utils/env-files.js';\n\n/** Options parsed by Commander for the `rm` subcommand. */\ninterface RmOptions {\n environment: EnvironmentName;\n all: boolean;\n force: boolean;\n}\n\n/**\n * Removes environment files from the working directory.\n *\n * Without `--force`, performs a dry run listing files that would be deleted.\n * With `-a`, includes all associated file variants (`.local`, `.unencrypted`).\n * With `--force`, permanently deletes the resolved files.\n */\nexport class RmCommand implements ISubCommand<RmOptions, RemoveResult> {\n /** @inheritdoc */\n async execute(options: RmOptions, context: CommandContext): Promise<CommandResult<RemoveResult>> {\n const { environment, all, force } = options;\n\n try {\n const allFiles = listEnvFiles(context.cwd, '.env.*', ['.env.keys']);\n const candidates = allFiles.filter((f) => {\n const name = parseEnvironmentFromFilename(path.basename(f));\n return name === environment;\n });\n\n if (!all) {\n const primary = path.resolve(context.cwd, `.env.${environment}`);\n const subset = candidates.filter((f) => f === primary);\n return buildResult(environment, subset, force);\n }\n\n return buildResult(environment, candidates, force);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\nasync function buildResult(\n environment: EnvironmentName,\n files: string[],\n force: boolean,\n): Promise<CommandResult<RemoveResult>> {\n if (!force) {\n const preview = files.length > 0\n ? `Would delete:\\n${files.map((f) => ` ${f}`).join('\\n')}\\n\\nPass --force to confirm deletion.`\n : `No files found for environment: ${environment}`;\n\n return {\n success: true,\n data: { environment, deletedFiles: [] },\n message: preview,\n };\n }\n\n const deleted: string[] = [];\n for (const f of files) {\n try {\n await fs.rm(f, { force: true });\n deleted.push(f);\n } catch {}\n }\n\n const message =\n deleted.length > 0\n ? `Deleted:\\n${deleted.map((f) => ` ${f}`).join('\\n')}`\n : `No files found for environment: ${environment}`;\n\n return {\n success: true,\n data: { environment, deletedFiles: deleted },\n message,\n };\n}\n\n/** Registers the `rm <environment>` command onto the Commander program. */\nexport class RmBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('rm <environment>')\n .description('Remove environment files from the working directory')\n .option('-a, --all', 'include all associated file variants (.local, .unencrypted)', false)\n .option('--force', 'actually delete files (default is dry run)', false)\n .action(async (environment: string, opts: { all: boolean; force: boolean }) => {\n await this.dispatch(\n new RmCommand(),\n { environment, all: opts.all, force: opts.force },\n this.buildContext(program),\n );\n });\n }\n}\n","import type { Command } from 'commander';\nimport type { BlacklistResult, CommandContext, CommandResult, EnvironmentName, ISubCommand } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { readBlacklist, writeBlacklist } from '../../utils/blacklist.js';\n\n/** Options parsed by Commander for `blacklist add`. */\ninterface BlacklistAddOptions {\n environment: EnvironmentName;\n}\n\n/** Options parsed by Commander for `blacklist rm`. */\ninterface BlacklistRmOptions {\n environment: EnvironmentName;\n}\n\n/**\n * Adds an environment name to the global blacklist, preventing it from\n * appearing in auto-detection results such as `envctrl list`.\n */\nexport class BlacklistAddSubCommand implements ISubCommand<BlacklistAddOptions, BlacklistResult> {\n /** @inheritdoc */\n async execute(\n options: BlacklistAddOptions,\n _context: CommandContext,\n ): Promise<CommandResult<BlacklistResult>> {\n const { environment } = options;\n\n try {\n const current = await readBlacklist();\n\n if (current.includes(environment)) {\n return {\n success: true,\n data: { environment, blacklisted: current },\n message: `Environment \"${environment}\" is already blacklisted.`,\n };\n }\n\n const updated = [...current, environment];\n await writeBlacklist(updated);\n\n return {\n success: true,\n data: { environment, blacklisted: updated },\n message: `Added \"${environment}\" to the blacklist.\\nBlacklisted environments:\\n${updated.map((e) => ` ${e}`).join('\\n')}`,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/**\n * Removes an environment name from the global blacklist, restoring it to\n * auto-detection results such as `envctrl list`.\n */\nexport class BlacklistRmSubCommand implements ISubCommand<BlacklistRmOptions, BlacklistResult> {\n /** @inheritdoc */\n async execute(\n options: BlacklistRmOptions,\n _context: CommandContext,\n ): Promise<CommandResult<BlacklistResult>> {\n const { environment } = options;\n\n try {\n const current = await readBlacklist();\n\n if (!current.includes(environment)) {\n return {\n success: false,\n error: `Environment \"${environment}\" is not in the blacklist.`,\n };\n }\n\n const updated = current.filter((e) => e !== environment);\n await writeBlacklist(updated);\n\n const message =\n updated.length > 0\n ? `Removed \"${environment}\" from the blacklist.\\nBlacklisted environments:\\n${updated.map((e) => ` ${e}`).join('\\n')}`\n : `Removed \"${environment}\" from the blacklist.\\nBlacklist is now empty.`;\n\n return {\n success: true,\n data: { environment, blacklisted: updated },\n message,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `blacklist` command group onto the Commander program. */\nexport class BlacklistBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n const blacklist = program\n .command('blacklist')\n .description('Manage the environment auto-detection blacklist');\n\n blacklist\n .command('add <environment>')\n .description('Exclude an environment from auto-detection')\n .action(async (environment: string) => {\n await this.dispatch(\n new BlacklistAddSubCommand(),\n { environment },\n this.buildContext(program),\n );\n });\n\n blacklist\n .command('rm <environment>')\n .description('Re-include an environment in auto-detection')\n .action(async (environment: string) => {\n await this.dispatch(\n new BlacklistRmSubCommand(),\n { environment },\n this.buildContext(program),\n );\n });\n }\n}\n"],"mappings":"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","names":["createRequire","fs","path","program","path","require","fs","path","program","fs","path","os","path","fs","path","fs","fs","fs","program","fs","fs","program","fs","path","path","fs","program","fs","os","path","fs","path","fs","path","path","fs","path","fs","os","program","path","fs","path","fs","path","path","program","fs","path","path","fs","program","program","createRequire"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/switch/index.ts","../src/base-command.ts","../src/utils/env-files.ts","../src/utils/dotenvx.ts","../src/commands/switch/sync.ts","../src/commands/keystore/create.ts","../src/utils/platform.ts","../src/commands/keystore/registry.ts","../src/commands/keystore/list.ts","../src/commands/keystore/delete.ts","../src/commands/keystore/index.ts","../src/commands/set/index.ts","../src/commands/encrypt/index.ts","../src/commands/init/index.ts","../src/commands/init/workspace.ts","../src/utils/build-env.ts","../src/utils/config.ts","../src/commands/list/index.ts","../src/utils/blacklist.ts","../src/commands/rm/index.ts","../src/commands/blacklist/index.ts","../src/commands/create/index.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { Command } from 'commander';\nimport { SwitchBaseCommand } from './commands/switch/index.js';\nimport { KeystoreBaseCommand } from './commands/keystore/index.js';\nimport { SetBaseCommand } from './commands/set/index.js';\nimport { EncryptBaseCommand } from './commands/encrypt/index.js';\nimport { InitBaseCommand } from './commands/init/index.js';\nimport { ListBaseCommand } from './commands/list/index.js';\nimport { RmBaseCommand } from './commands/rm/index.js';\nimport { BlacklistBaseCommand } from './commands/blacklist/index.js';\nimport { CreateBaseCommand } from './commands/create/index.js';\n\nconst _require = createRequire(import.meta.url);\nconst { version } = _require('../package.json') as { version: string };\n\nconst program = new Command();\n\nprogram\n .name('envctrl')\n .description('Encrypted environment file manager built on dotenvx')\n .version(version)\n .addHelpText('beforeAll', `envctrl v${version}\\n`)\n .option('-q, --quiet', 'suppress output', false);\n\nnew InitBaseCommand().register(program);\nnew CreateBaseCommand().register(program);\nnew ListBaseCommand().register(program);\nnew SwitchBaseCommand().register(program);\nnew KeystoreBaseCommand().register(program);\nnew SetBaseCommand().register(program);\nnew EncryptBaseCommand().register(program);\nnew RmBaseCommand().register(program);\nnew BlacklistBaseCommand().register(program);\n\nprogram.parseAsync(process.argv);\n","import fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, ISubCommand, SwitchResult } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { buildEnvFilePair } from '../../utils/env-files.js';\nimport { setKeyValue } from '../../utils/dotenvx.js';\nimport { syncUnencryptedToEncrypted } from './sync.js';\n\n/** Options parsed by Commander for the `switch` subcommand. */\ninterface SwitchOptions {\n environment: string;\n}\n\n/**\n * Switches the active environment.\n *\n * Creates `.env.[env].unencrypted` and `.env.[env]` if they do not exist,\n * syncs keys from the unencrypted source into the encrypted file, and\n * points `.env` at the encrypted file via symlink (POSIX) or copy (Windows).\n */\nexport class SwitchCommand implements ISubCommand<SwitchOptions, SwitchResult> {\n /** @inheritdoc */\n async execute(\n options: SwitchOptions,\n context: CommandContext,\n ): Promise<CommandResult<SwitchResult>> {\n const { environment, cwd } = { ...options, cwd: context.cwd };\n const pair = buildEnvFilePair(environment, cwd);\n const created: string[] = [];\n\n try {\n try {\n await fs.access(pair.unencrypted);\n } catch {\n await fs.writeFile(pair.unencrypted, '', 'utf8');\n created.push(pair.unencrypted);\n }\n\n const encryptedExists = await fs\n .access(pair.encrypted)\n .then(() => true)\n .catch(() => false);\n\n await syncUnencryptedToEncrypted(environment, cwd);\n\n if (!encryptedExists) {\n const stillMissing = await fs\n .access(pair.encrypted)\n .then(() => false)\n .catch(() => true);\n\n if (stillMissing) {\n setKeyValue('_ENVCTRL_INIT', '1', pair.encrypted);\n created.push(pair.encrypted);\n } else {\n created.push(pair.encrypted);\n }\n }\n\n const activePath = path.resolve(cwd, '.env');\n\n try {\n await fs.unlink(activePath);\n } catch {}\n\n if (os.platform() === 'win32') {\n await fs.copyFile(pair.encrypted, activePath);\n } else {\n await fs.symlink(pair.encrypted, activePath);\n }\n\n const lines = [`Switched to: ${environment}`];\n if (created.length > 0) {\n lines.push('Created:', ...created.map((f) => ` ${f}`));\n }\n\n return {\n success: true,\n data: { environment, created, activePath },\n message: lines.join('\\n'),\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `switch [environment]` command onto the Commander program. */\nexport class SwitchBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('switch <environment>')\n .description('Create, sync, and activate a named environment (.env.[env])')\n .action(async (environment: string) => {\n await this.dispatch(new SwitchCommand(), { environment }, this.buildContext(program));\n });\n }\n}\n","import type { Command } from 'commander';\nimport type { CommandContext, CommandResult, ISubCommand } from '@envctrl/types';\n\n/**\n * Abstract base for all top-level CLI commands.\n *\n * Subclasses implement {@link register} to attach their Commander subcommand\n * to the program. The {@link dispatch} helper handles uniform result\n * printing and process exit on failure.\n */\nexport abstract class BaseCommand {\n /**\n * Attaches this command's Commander definition onto `program`.\n *\n * @param program - The root Commander program instance\n */\n abstract register(program: Command): void;\n\n /**\n * Executes a subcommand and handles the result.\n *\n * Prints the error message to stderr and exits with code 1 on failure.\n * Prints `result.message` to stdout on success when `context.quiet` is false.\n *\n * @param cmd - The subcommand to execute\n * @param options - Parsed options from Commander\n * @param context - Injected runtime context\n */\n protected async dispatch<TOptions, TResult>(\n cmd: ISubCommand<TOptions, TResult>,\n options: TOptions,\n context: CommandContext,\n ): Promise<void> {\n const result: CommandResult<TResult> = await cmd.execute(options, context);\n\n if (!result.success) {\n process.stderr.write(`error: ${result.error ?? 'unknown error'}\\n`);\n process.exit(1);\n }\n\n if (!context.quiet && result.message !== undefined) {\n process.stdout.write(result.message + '\\n');\n }\n }\n\n /**\n * Builds a {@link CommandContext} from the Commander program's global options.\n *\n * @param program - The root Commander program instance\n */\n protected buildContext(program: Command): CommandContext {\n const opts = program.opts<{ quiet?: boolean }>();\n return {\n cwd: process.cwd(),\n quiet: opts.quiet ?? false,\n };\n }\n}\n","import path from 'node:path';\nimport type { EnvFilePair, EnvironmentName } from '@envctrl/types';\n\nconst RESERVED_ENV_NAMES = new Set(['keys', 'example']);\n\n/**\n * Derives the environment name from a `.env.*` filename, stripping `.unencrypted`\n * and `.local` suffixes. Returns `undefined` for reserved filenames like\n * `.env.keys` and `.env.example`.\n */\nexport function parseEnvironmentFromFilename(filename: string): EnvironmentName | undefined {\n const base = path.basename(filename);\n\n if (!base.startsWith('.env.')) {\n return undefined;\n }\n\n const withoutPrefix = base.slice('.env.'.length);\n\n if (!withoutPrefix || RESERVED_ENV_NAMES.has(withoutPrefix)) {\n return undefined;\n }\n\n let name = withoutPrefix.endsWith('.unencrypted')\n ? withoutPrefix.slice(0, -'.unencrypted'.length)\n : withoutPrefix;\n\n if (name.endsWith('.local')) {\n name = name.slice(0, -'.local'.length);\n }\n\n if (!name || RESERVED_ENV_NAMES.has(name)) {\n return undefined;\n }\n\n return name;\n}\n\n/**\n * Builds the {@link EnvFilePair} for a given environment name and working directory.\n *\n * @param environment - The environment name, e.g. `\"production\"`\n * @param cwd - The working directory that will contain the env files\n */\nexport function buildEnvFilePair(environment: EnvironmentName, cwd: string): EnvFilePair {\n return {\n environment,\n unencrypted: path.resolve(cwd, `.env.${environment}.unencrypted`),\n encrypted: path.resolve(cwd, `.env.${environment}`),\n };\n}\n\n/**\n * Parses KEY=VALUE pairs from a plaintext `.env` file string.\n *\n * Skips blank lines and comment lines starting with `#`.\n *\n * @param content - Raw file content\n */\nexport function parseEnvContent(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n\n if (!trimmed || trimmed.startsWith('#')) {\n continue;\n }\n\n const eqIdx = trimmed.indexOf('=');\n if (eqIdx === -1) {\n continue;\n }\n\n const key = trimmed.slice(0, eqIdx).trim();\n const value = trimmed.slice(eqIdx + 1).trim();\n result[key] = value;\n }\n\n return result;\n}\n\n/**\n * Writes or updates a single `KEY=VALUE` line in a plaintext env file string.\n *\n * If the key already exists its line is replaced in-place; otherwise the\n * entry is appended.\n *\n * @param content - Current raw file content\n * @param key - The environment variable name\n * @param value - The new value\n */\nexport function upsertEnvLine(content: string, key: string, value: string): string {\n const lines = content.split('\\n');\n const pattern = new RegExp(`^${key}\\\\s*=`);\n let replaced = false;\n\n const updated = lines.map((line) => {\n if (pattern.test(line)) {\n replaced = true;\n return `${key}=${value}`;\n }\n return line;\n });\n\n if (!replaced) {\n if (updated[updated.length - 1] !== '') {\n updated.push(`${key}=${value}`);\n } else {\n updated.splice(updated.length - 1, 0, `${key}=${value}`);\n }\n }\n\n return updated.join('\\n');\n}\n","import { createRequire } from 'node:module';\nimport path from 'node:path';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport * as dotenvx from '@dotenvx/dotenvx';\nimport type { DotenvxEncryptResult, DotenvxSetResult } from '@envctrl/types';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Resolves the path to the dotenvx CLI entry script from the installed package.\n *\n * Reads the `bin` field from the package's own `package.json` to avoid\n * hardcoding the path, which can change across dotenvx versions.\n */\nfunction resolveDotenvxBin(): string {\n const require = createRequire(import.meta.url);\n const pkgJsonPath = require.resolve('@dotenvx/dotenvx/package.json');\n const pkgJson = require('@dotenvx/dotenvx/package.json') as {\n bin: Record<string, string>;\n };\n const binRelPath = pkgJson.bin['dotenvx'];\n return path.resolve(path.dirname(pkgJsonPath), binRelPath);\n}\n\n/**\n * Sets a single key-value pair in an encrypted env file using the dotenvx JS API.\n *\n * @param key - The environment variable name\n * @param value - The value to set\n * @param encryptedFilePath - Absolute path to the target `.env.[env]` file\n * @param keysFilePath - Optional path to the `.env.keys` file\n */\nexport function setKeyValue(\n key: string,\n value: string,\n encryptedFilePath: string,\n keysFilePath?: string,\n): DotenvxSetResult {\n const output = dotenvx.set(key, value, {\n path: encryptedFilePath,\n encrypt: true,\n quiet: true,\n ...(keysFilePath ? { envKeysFile: keysFilePath } : {}),\n });\n\n return {\n changedFilepaths: output.changedFilepaths,\n unchangedFilepaths: output.unchangedFilepaths,\n };\n}\n\n/**\n * Encrypts an existing plaintext env file in-place using the dotenvx CLI.\n *\n * Spawns the bundled `dotenvx encrypt -f <filePath>` process. The CLI\n * handles creating or updating the corresponding `.env.keys` entry.\n *\n * @param filePath - Absolute path to the plaintext `.env.*` file to encrypt\n */\nexport async function encryptFile(filePath: string): Promise<DotenvxEncryptResult> {\n const bin = resolveDotenvxBin();\n await execFileAsync(process.execPath, [bin, 'encrypt', '-f', filePath]);\n\n return {\n changedFilepaths: [filePath],\n unchangedFilepaths: [],\n };\n}\n\n/**\n * Lists env files in a directory using the dotenvx JS API.\n *\n * @param directory - Directory to scan\n * @param include - Glob pattern(s) to include\n * @param exclude - Glob pattern(s) to exclude\n */\nexport function listEnvFiles(\n directory: string,\n include: string | string[],\n exclude: string | string[],\n): string[] {\n return dotenvx.ls(directory, include, exclude);\n}\n","import fs from 'node:fs/promises';\nimport { parseEnvContent, buildEnvFilePair } from '../../utils/env-files.js';\nimport { setKeyValue } from '../../utils/dotenvx.js';\nimport type { EnvironmentName } from '@envctrl/types';\n\n/**\n * Syncs all keys from the unencrypted file into the encrypted file.\n *\n * Reads the plaintext `.env.[env].unencrypted` file and calls dotenvx `set`\n * for each key so the encrypted counterpart stays in sync.\n *\n * @param environment - The environment name\n * @param cwd - Working directory containing the env files\n */\nexport async function syncUnencryptedToEncrypted(\n environment: EnvironmentName,\n cwd: string,\n): Promise<void> {\n const pair = buildEnvFilePair(environment, cwd);\n\n let content: string;\n try {\n content = await fs.readFile(pair.unencrypted, 'utf8');\n } catch {\n return;\n }\n\n const entries = parseEnvContent(content);\n\n for (const [key, value] of Object.entries(entries)) {\n setKeyValue(key, value, pair.encrypted);\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { CommandContext, CommandResult, ISubCommand, KeystoreConfig } from '@envctrl/types';\nimport { resolveDefaultKeystorePath, resolveKeystoresRegistryPath } from '../../utils/platform.js';\nimport { readRegistry, writeRegistry } from './registry.js';\n\n/** Options parsed by Commander for `keystore create`. */\nexport interface KeystoreCreateOptions {\n keystorePath: string | undefined;\n name: string | undefined;\n}\n\n/**\n * Creates a new keystore directory and registers it in the global registry.\n *\n * If no path is provided, defaults to the platform-appropriate application\n * data directory. An empty `.env.keys` stub is written on first creation.\n */\nexport class KeystoreCreateSubCommand implements ISubCommand<\n KeystoreCreateOptions,\n KeystoreConfig\n> {\n /** @inheritdoc */\n async execute(\n options: KeystoreCreateOptions,\n _context: CommandContext,\n ): Promise<CommandResult<KeystoreConfig>> {\n const keystorePath = options.keystorePath ?? resolveDefaultKeystorePath();\n const name = options.name ?? path.basename(keystorePath);\n\n try {\n await fs.mkdir(keystorePath, { recursive: true });\n\n const keysFile = path.join(keystorePath, '.env.keys');\n try {\n await fs.access(keysFile);\n } catch {\n await fs.writeFile(keysFile, '# dotenvx keys\\n', 'utf8');\n }\n\n const registryPath = resolveKeystoresRegistryPath();\n await fs.mkdir(path.dirname(registryPath), { recursive: true });\n\n const registry = await readRegistry(registryPath);\n const exists = registry.some((e) => e.name === name || e.path === keystorePath);\n\n if (!exists) {\n registry.push({ name, path: keystorePath });\n await writeRegistry(registryPath, registry);\n }\n\n return {\n success: true,\n data: { path: keystorePath },\n message: `Keystore created at: ${keystorePath}`,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n","import os from 'node:os';\nimport path from 'node:path';\n\n/**\n * Resolves the envctrl application data root directory for the current platform.\n *\n * - Linux: `$XDG_DATA_HOME/envctrl` or `~/.local/share/envctrl`\n * - macOS: `~/Library/Application Support/envctrl`\n * - Windows: `%APPDATA%\\envctrl`\n */\nfunction resolveAppDataRoot(): string {\n const platform = os.platform();\n const home = os.homedir();\n\n if (platform === 'win32') {\n const appData = process.env['APPDATA'] ?? path.join(home, 'AppData', 'Roaming');\n return path.join(appData, 'envctrl');\n }\n\n if (platform === 'darwin') {\n return path.join(home, 'Library', 'Application Support', 'envctrl');\n }\n\n const xdgDataHome = process.env['XDG_DATA_HOME'] ?? path.join(home, '.local', 'share');\n return path.join(xdgDataHome, 'envctrl');\n}\n\n/**\n * Resolves the default keystore directory.\n *\n * Placed inside a `keystores/default` subdirectory of the app data root\n * so that the registry JSON file at the root level is never deleted when\n * the default keystore is removed.\n */\nexport function resolveDefaultKeystorePath(): string {\n return path.join(resolveAppDataRoot(), 'keystores', 'default');\n}\n\n/**\n * Returns the path to the global keystores registry JSON file.\n *\n * Stored at the app data root, outside any individual keystore directory,\n * so it survives keystore deletion.\n */\nexport function resolveKeystoresRegistryPath(): string {\n return path.join(resolveAppDataRoot(), 'keystores.json');\n}\n\n/** Returns the path to the blacklist JSON file. */\nexport function resolveBlacklistPath(): string {\n return path.join(resolveAppDataRoot(), 'blacklist.json');\n}\n","import fs from 'node:fs/promises';\nimport type { KeystoreEntry } from '@envctrl/types';\n\n/**\n * Reads the keystores registry JSON file.\n *\n * Returns an empty array if the file does not exist yet.\n *\n * @param registryPath - Absolute path to the `keystores.json` file\n */\nexport async function readRegistry(registryPath: string): Promise<KeystoreEntry[]> {\n try {\n const raw = await fs.readFile(registryPath, 'utf8');\n return JSON.parse(raw) as KeystoreEntry[];\n } catch {\n return [];\n }\n}\n\n/**\n * Writes the keystores registry to disk.\n *\n * @param registryPath - Absolute path to the `keystores.json` file\n * @param entries - Array of keystore entries to persist\n */\nexport async function writeRegistry(registryPath: string, entries: KeystoreEntry[]): Promise<void> {\n await fs.writeFile(registryPath, JSON.stringify(entries, null, 2) + '\\n', 'utf8');\n}\n","import type { CommandContext, CommandResult, ISubCommand, KeystoreEntry } from '@envctrl/types';\nimport { resolveKeystoresRegistryPath } from '../../utils/platform.js';\nimport { readRegistry } from './registry.js';\n\n/**\n * Lists all registered keystores from the global registry.\n *\n * Returns an empty array if no keystores have been created yet.\n */\nexport class KeystoreListSubCommand implements ISubCommand<Record<string, never>, KeystoreEntry[]> {\n /** @inheritdoc */\n async execute(\n _options: Record<string, never>,\n _context: CommandContext,\n ): Promise<CommandResult<KeystoreEntry[]>> {\n try {\n const registryPath = resolveKeystoresRegistryPath();\n const entries = await readRegistry(registryPath);\n\n let message: string;\n if (entries.length === 0) {\n message = 'No keystores registered.';\n } else {\n const maxLen = Math.max(...entries.map((e) => e.name.length));\n message = entries.map((e) => `${e.name.padEnd(maxLen)} ${e.path}`).join('\\n');\n }\n\n return { success: true, data: entries, message };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n","import fs from 'node:fs/promises';\nimport type { CommandContext, CommandResult, ISubCommand, KeystoreEntry } from '@envctrl/types';\nimport { resolveKeystoresRegistryPath } from '../../utils/platform.js';\nimport { readRegistry, writeRegistry } from './registry.js';\n\n/** Options parsed by Commander for `keystore delete`. */\nexport interface KeystoreDeleteOptions {\n name: string;\n force: boolean;\n}\n\n/**\n * Deletes a named keystore directory and removes its entry from the registry.\n *\n * Requires `--force` flag to skip the confirmation guard. Without it,\n * the command exits early with a descriptive error.\n */\nexport class KeystoreDeleteSubCommand implements ISubCommand<KeystoreDeleteOptions, KeystoreEntry> {\n /** @inheritdoc */\n async execute(\n options: KeystoreDeleteOptions,\n _context: CommandContext,\n ): Promise<CommandResult<KeystoreEntry>> {\n const { name, force } = options;\n\n try {\n const registryPath = resolveKeystoresRegistryPath();\n const registry = await readRegistry(registryPath);\n const entry = registry.find((e) => e.name === name);\n\n if (!entry) {\n return {\n success: false,\n error: `keystore \"${name}\" not found in registry`,\n };\n }\n\n if (!force) {\n return {\n success: false,\n error: `pass --force to confirm deletion of keystore \"${name}\" at ${entry.path}`,\n };\n }\n\n const updated = registry.filter((e) => e.name !== name);\n await writeRegistry(registryPath, updated);\n\n await fs.rm(entry.path, { recursive: true, force: true });\n\n return {\n success: true,\n data: entry,\n message: `Deleted keystore: ${entry.name} (${entry.path})`,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n","import type { Command } from 'commander';\nimport { BaseCommand } from '../../base-command.js';\nimport { KeystoreCreateSubCommand } from './create.js';\nimport { KeystoreListSubCommand } from './list.js';\nimport { KeystoreDeleteSubCommand } from './delete.js';\n\n/** Registers the `keystore` command group onto the Commander program. */\nexport class KeystoreBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n const keystoreCmd = program\n .command('keystore')\n .description('Manage keystore directories for dotenvx private keys');\n\n keystoreCmd\n .command('create [path]')\n .description('Create a new keystore (defaults to platform app data folder)')\n .option('-n, --name <name>', 'name for the keystore entry in the registry')\n .action(async (keystorePath: string | undefined, opts: { name?: string }) => {\n await this.dispatch(\n new KeystoreCreateSubCommand(),\n { keystorePath, name: opts.name },\n this.buildContext(program),\n );\n });\n\n keystoreCmd\n .command('list')\n .description('List all registered keystores')\n .action(async () => {\n await this.dispatch(new KeystoreListSubCommand(), {}, this.buildContext(program));\n });\n\n keystoreCmd\n .command('delete <name>')\n .description('Delete a named keystore and remove it from the registry')\n .option('--force', 'skip confirmation and delete immediately', false)\n .action(async (name: string, opts: { force: boolean }) => {\n await this.dispatch(\n new KeystoreDeleteSubCommand(),\n { name, force: opts.force },\n this.buildContext(program),\n );\n });\n }\n}\n","import fs from 'node:fs/promises';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, ISubCommand, SetResult } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { buildEnvFilePair, upsertEnvLine } from '../../utils/env-files.js';\nimport { setKeyValue } from '../../utils/dotenvx.js';\n\n/** Options parsed by Commander for the `set` subcommand. */\ninterface SetOptions {\n environment: string;\n key: string;\n value: string;\n}\n\n/**\n * Sets a single environment variable in both the unencrypted and encrypted files.\n *\n * Writes the key to the plaintext `.env.[env].unencrypted` file first to\n * maintain human-readable source of truth, then calls dotenvx `set` to\n * write and encrypt the value in `.env.[env]`.\n */\nexport class SetCommand implements ISubCommand<SetOptions, SetResult> {\n /** @inheritdoc */\n async execute(options: SetOptions, context: CommandContext): Promise<CommandResult<SetResult>> {\n const { environment, key, value } = options;\n const pair = buildEnvFilePair(environment, context.cwd);\n\n try {\n let existingContent = '';\n try {\n existingContent = await fs.readFile(pair.unencrypted, 'utf8');\n } catch {}\n\n const updatedContent = upsertEnvLine(existingContent, key, value);\n await fs.writeFile(pair.unencrypted, updatedContent, 'utf8');\n\n const result = setKeyValue(key, value, pair.encrypted);\n const changed = result.changedFilepaths.length > 0;\n\n return {\n success: true,\n data: { environment, key, changed },\n message: `Set ${key} in ${environment}`,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `set <environment> <key> <value>` command onto the Commander program. */\nexport class SetBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('set <environment> <key> <value>')\n .description('Set an environment variable and sync it to the encrypted file')\n .action(async (environment: string, key: string, value: string) => {\n await this.dispatch(\n new SetCommand(),\n { environment, key, value },\n this.buildContext(program),\n );\n });\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, EncryptResult, ISubCommand } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { parseEnvironmentFromFilename } from '../../utils/env-files.js';\nimport { listEnvFiles, encryptFile } from '../../utils/dotenvx.js';\n\n/** Options parsed by Commander for the `encrypt` subcommand. */\ninterface EncryptOptions {\n files: string[];\n}\n\n/**\n * Encrypts existing plaintext `.env.*` files using dotenvx, backing up each file's\n * content to `.env.[env].unencrypted` before encrypting in-place.\n * Defaults to all `.env.*` files in the working directory when no files are specified.\n */\nexport class EncryptCommand implements ISubCommand<EncryptOptions, EncryptResult> {\n /** @inheritdoc */\n async execute(\n options: EncryptOptions,\n context: CommandContext,\n ): Promise<CommandResult<EncryptResult>> {\n const { cwd } = context;\n\n try {\n const targets =\n options.files.length > 0\n ? options.files.map((f) => path.resolve(cwd, f))\n : listEnvFiles(cwd, '.env.*', ['.env.keys', '*.unencrypted']);\n\n const changedFiles: string[] = [];\n const unchangedFiles: string[] = [];\n\n for (const filePath of targets) {\n const basename = path.basename(filePath);\n const environment = parseEnvironmentFromFilename(basename);\n\n if (!environment) {\n unchangedFiles.push(filePath);\n continue;\n }\n\n const unencryptedPath = path.resolve(\n path.dirname(filePath),\n `.env.${environment}.unencrypted`,\n );\n\n try {\n const content = await fs.readFile(filePath, 'utf8');\n\n try {\n await fs.access(unencryptedPath);\n } catch {\n await fs.writeFile(unencryptedPath, content, 'utf8');\n }\n\n const result = await encryptFile(filePath);\n changedFiles.push(...result.changedFilepaths);\n } catch {\n unchangedFiles.push(filePath);\n }\n }\n\n const lines: string[] = [\n ...changedFiles.map((f) => `Encrypted: ${f}`),\n ...unchangedFiles.map((f) => `Unchanged: ${f}`),\n ];\n\n return {\n success: true,\n data: { changedFiles, unchangedFiles },\n message: lines.length > 0 ? lines.join('\\n') : 'No files processed.',\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `encrypt [files...]` command onto the Commander program. */\nexport class EncryptBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('encrypt [files...]')\n .description('Encrypt plaintext .env.* files and create .unencrypted backups')\n .action(async (files: string[]) => {\n await this.dispatch(new EncryptCommand(), { files }, this.buildContext(program));\n });\n }\n}\n","import fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, InitResult, ISubCommand } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { resolveDefaultKeystorePath, resolveKeystoresRegistryPath } from '../../utils/platform.js';\nimport { listEnvFiles } from '../../utils/dotenvx.js';\nimport { readRegistry, writeRegistry } from '../keystore/registry.js';\nimport { findWorkspaceRoot, scanWorkspacePackages } from './workspace.js';\nimport { detectBuildEnvironment } from '../../utils/build-env.js';\nimport { writeConfig } from '../../utils/config.js';\n\n/** Options parsed by Commander for the `init` subcommand. */\ninterface InitOptions {\n workspace: string | undefined;\n name: string | undefined;\n keystore: string | undefined;\n /** Override the config directory name (default: `.envctrl`). */\n configDir: string | undefined;\n /** Override the config file name (default: `config.json`). */\n configFile: string | undefined;\n}\n\n/**\n * Initialises envctrl for an existing workspace or monorepo by creating a shared keystore,\n * symlinking `.env.keys` into every package directory, and writing a `.envctrl/config.json`\n * that records the active environment.\n *\n * When a recognised CI/CD provider (Vercel, Netlify, Railway) is detected via environment\n * variables, the environment is automatically resolved from the provider context instead of\n * defaulting to `\"development\"`.\n */\nexport class InitCommand implements ISubCommand<InitOptions, InitResult> {\n /** @inheritdoc */\n async execute(options: InitOptions, context: CommandContext): Promise<CommandResult<InitResult>> {\n const startDir = options.workspace\n ? path.resolve(context.cwd, options.workspace)\n : context.cwd;\n\n const configDir = options.configDir ?? '.envctrl';\n const configFile = options.configFile ?? 'config.json';\n\n try {\n const workspaceRoot = await findWorkspaceRoot(startDir);\n const packages = await scanWorkspacePackages(workspaceRoot);\n\n const keystorePath = options.keystore ?? resolveDefaultKeystorePath();\n const keystoreName = options.name ?? path.basename(workspaceRoot);\n\n await fs.mkdir(keystorePath, { recursive: true });\n\n const keysFile = path.join(keystorePath, '.env.keys');\n try {\n await fs.access(keysFile);\n } catch {\n await fs.writeFile(keysFile, '# dotenvx keys\\n', 'utf8');\n }\n\n const registryPath = resolveKeystoresRegistryPath();\n await fs.mkdir(path.dirname(registryPath), { recursive: true });\n const registry = await readRegistry(registryPath);\n const alreadyRegistered = registry.some(\n (e) => e.name === keystoreName || e.path === keystorePath,\n );\n if (!alreadyRegistered) {\n registry.push({ name: keystoreName, path: keystorePath });\n await writeRegistry(registryPath, registry);\n }\n\n const linkTargets = [\n workspaceRoot,\n ...packages.map((p) => path.resolve(workspaceRoot, p.path)),\n ];\n\n const keysLinked: string[] = [];\n\n for (const dir of linkTargets) {\n const envFiles = listEnvFiles(dir, '.env.*', ['.env.keys']);\n if (envFiles.length === 0) continue;\n\n const linkPath = path.join(dir, '.env.keys');\n try {\n await fs.access(linkPath);\n } catch {\n if (os.platform() === 'win32') {\n await fs.copyFile(keysFile, linkPath);\n } else {\n await fs.symlink(keysFile, linkPath);\n }\n keysLinked.push(linkPath);\n }\n }\n\n const buildEnv = detectBuildEnvironment();\n const environment = buildEnv.environment ?? 'development';\n const autoDetected = buildEnv.provider !== null;\n\n const configPath = await writeConfig(\n context.cwd,\n { environment },\n configDir,\n configFile,\n );\n\n const lines = [`Workspace: ${workspaceRoot}`, `Keystore: ${keystorePath}`];\n if (packages.length > 0) {\n lines.push('Packages:');\n for (const p of packages) lines.push(` ${p.name} (${p.path})`);\n }\n if (keysLinked.length > 0) {\n lines.push('Linked .env.keys:');\n for (const l of keysLinked) lines.push(` ${l}`);\n }\n lines.push(\n `Config: ${configPath}`,\n `Environment: ${environment}${autoDetected ? ` (auto-detected from ${buildEnv.provider})` : ''}`,\n );\n\n return {\n success: true,\n data: { workspaceRoot, packages, keystorePath, keysLinked, configPath, environment, autoDetected },\n message: lines.join('\\n'),\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `init [workspace]` command onto the Commander program. */\nexport class InitBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('init [workspace]')\n .description(\n 'Scan the workspace or monorepo and link packages to a shared keystore',\n )\n .option('-n, --name <name>', 'name for the keystore entry in the registry')\n .option('-k, --keystore <path>', 'custom keystore directory path')\n .option('--config-dir <dir>', 'config directory name (default: .envctrl)')\n .option('--config-file <file>', 'config file name (default: config.json)')\n .action(\n async (\n workspace: string | undefined,\n opts: { name?: string; keystore?: string; configDir?: string; configFile?: string },\n ) => {\n await this.dispatch(\n new InitCommand(),\n {\n workspace,\n name: opts.name,\n keystore: opts.keystore,\n configDir: opts.configDir,\n configFile: opts.configFile,\n },\n this.buildContext(program),\n );\n },\n );\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { WorkspacePackage } from '@envctrl/types';\n\n/**\n * Traverses up from `startDir` to find the workspace root.\n *\n * A directory is considered the workspace root if it contains\n * `pnpm-workspace.yaml` or a `package.json` with a `workspaces` field.\n * Falls back to `startDir` if no root is found.\n */\nexport async function findWorkspaceRoot(startDir: string): Promise<string> {\n let dir = startDir;\n\n while (true) {\n try {\n await fs.access(path.join(dir, 'pnpm-workspace.yaml'));\n return dir;\n } catch {}\n\n try {\n const raw = await fs.readFile(path.join(dir, 'package.json'), 'utf8');\n const pkg = JSON.parse(raw) as { workspaces?: unknown };\n if (pkg.workspaces) return dir;\n } catch {}\n\n const parent = path.dirname(dir);\n if (parent === dir) return startDir;\n dir = parent;\n }\n}\n\n/**\n * Reads workspace package glob patterns from `pnpm-workspace.yaml` or\n * the `workspaces` field in `package.json`.\n */\nasync function readWorkspacePatterns(workspaceRoot: string): Promise<string[]> {\n try {\n const raw = await fs.readFile(path.join(workspaceRoot, 'pnpm-workspace.yaml'), 'utf8');\n const patterns: string[] = [];\n let inPackages = false;\n\n for (const line of raw.split('\\n')) {\n if (/^packages\\s*:/.test(line)) {\n inPackages = true;\n continue;\n }\n if (inPackages) {\n const match = line.match(/^\\s+-\\s+['\"]?([^'\"]+)['\"]?/);\n if (match) {\n patterns.push(match[1].trim());\n } else if (line.trim() && !line.startsWith('#')) {\n break;\n }\n }\n }\n\n if (patterns.length > 0) return patterns;\n } catch {}\n\n try {\n const raw = await fs.readFile(path.join(workspaceRoot, 'package.json'), 'utf8');\n const pkg = JSON.parse(raw) as {\n workspaces?: string[] | { packages: string[] };\n };\n if (Array.isArray(pkg.workspaces)) return pkg.workspaces;\n if (pkg.workspaces?.packages) return pkg.workspaces.packages;\n } catch {}\n\n return [];\n}\n\n/**\n * Expands a single workspace glob pattern (supporting one trailing `*`) into\n * matching subdirectory paths under `workspaceRoot`.\n */\nasync function expandPattern(workspaceRoot: string, pattern: string): Promise<string[]> {\n if (!pattern.includes('*')) {\n return [path.resolve(workspaceRoot, pattern)];\n }\n\n const starIndex = pattern.indexOf('*');\n const baseRelative = pattern.slice(0, starIndex).replace(/\\/$/, '');\n const suffix = pattern.slice(starIndex + 1);\n const baseDir = path.resolve(workspaceRoot, baseRelative);\n\n try {\n const entries = await fs.readdir(baseDir, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => path.join(baseDir, e.name + suffix));\n } catch {\n return [];\n }\n}\n\n/**\n * Scans `workspaceRoot` for all packages by expanding workspace glob patterns\n * and filtering directories that contain a `package.json`.\n */\nexport async function scanWorkspacePackages(workspaceRoot: string): Promise<WorkspacePackage[]> {\n const patterns = await readWorkspacePatterns(workspaceRoot);\n const packages: WorkspacePackage[] = [];\n\n for (const pattern of patterns) {\n const dirs = await expandPattern(workspaceRoot, pattern);\n\n for (const dir of dirs) {\n try {\n const raw = await fs.readFile(path.join(dir, 'package.json'), 'utf8');\n const pkg = JSON.parse(raw) as { name?: string };\n if (pkg.name) {\n packages.push({\n name: pkg.name,\n path: path.relative(workspaceRoot, dir),\n });\n }\n } catch {}\n }\n }\n\n return packages;\n}\n","/** Known CI/CD providers that supply their own environment context. */\nexport type BuildProvider = 'vercel' | 'netlify' | 'railway';\n\n/** Result of probing the current process environment for a CI/CD context. */\nexport interface DetectedBuildEnv {\n /** The provider that was identified, or `null` when no provider is detected. */\n readonly provider: BuildProvider | null;\n /**\n * The canonical environment name derived from the provider's own variables.\n * `null` when no provider is detected.\n */\n readonly environment: 'production' | 'development' | null;\n}\n\n/**\n * Inspects `process.env` for well-known CI/CD provider variables and maps\n * them to a canonical `production` / `development` environment name.\n *\n * - **Vercel** – `VERCEL=1`; `VERCEL_ENV` is `production` | `preview` | `development`\n * - **Netlify** – `NETLIFY=true`; `CONTEXT` is `production` | `deploy-preview` | `branch-deploy` | `dev`\n * - **Railway** – `RAILWAY_ENVIRONMENT_NAME` holds the environment name directly\n */\nexport function detectBuildEnvironment(): DetectedBuildEnv {\n if (process.env['VERCEL'] === '1') {\n const vercelEnv = process.env['VERCEL_ENV'];\n return {\n provider: 'vercel',\n environment: vercelEnv === 'production' ? 'production' : 'development',\n };\n }\n\n if (process.env['NETLIFY'] === 'true') {\n const context = process.env['CONTEXT'];\n return {\n provider: 'netlify',\n environment: context === 'production' ? 'production' : 'development',\n };\n }\n\n if (process.env['RAILWAY_ENVIRONMENT_NAME'] !== undefined) {\n const railwayEnv = process.env['RAILWAY_ENVIRONMENT_NAME'];\n return {\n provider: 'railway',\n environment: railwayEnv === 'production' ? 'production' : 'development',\n };\n }\n\n return { provider: null, environment: null };\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { EnvctrlConfig } from '@envctrl/types';\n\n/**\n * Returns the absolute path to the envctrl config file.\n *\n * @param cwd - Base directory (typically the project root).\n * @param dir - Config directory name relative to `cwd`. Defaults to `.envctrl`.\n * @param file - Config file name inside `dir`. Defaults to `config.json`.\n */\nexport function resolveConfigPath(\n cwd: string,\n dir = '.envctrl',\n file = 'config.json',\n): string {\n return path.join(cwd, dir, file);\n}\n\n/**\n * Reads and parses the envctrl config file.\n * Returns `null` when the file does not exist or cannot be parsed.\n *\n * @param cwd - Base directory (typically the project root).\n * @param dir - Config directory name relative to `cwd`. Defaults to `.envctrl`.\n * @param file - Config file name inside `dir`. Defaults to `config.json`.\n */\nexport async function readConfig(\n cwd: string,\n dir = '.envctrl',\n file = 'config.json',\n): Promise<EnvctrlConfig | null> {\n try {\n const raw = await fs.readFile(resolveConfigPath(cwd, dir, file), 'utf8');\n return JSON.parse(raw) as EnvctrlConfig;\n } catch {\n return null;\n }\n}\n\n/**\n * Writes `config` as JSON, creating the config directory if needed.\n *\n * @param cwd - Base directory (typically the project root).\n * @param config - Configuration object to persist.\n * @param dir - Config directory name relative to `cwd`. Defaults to `.envctrl`.\n * @param file - Config file name inside `dir`. Defaults to `config.json`.\n * @returns The absolute path of the written file.\n */\nexport async function writeConfig(\n cwd: string,\n config: EnvctrlConfig,\n dir = '.envctrl',\n file = 'config.json',\n): Promise<string> {\n const configDir = path.join(cwd, dir);\n await fs.mkdir(configDir, { recursive: true });\n const configPath = resolveConfigPath(cwd, dir, file);\n await fs.writeFile(configPath, JSON.stringify(config, null, 2) + '\\n', 'utf8');\n return configPath;\n}\n","import path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, EnvironmentName, ISubCommand, ListResult } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { listEnvFiles } from '../../utils/dotenvx.js';\nimport { readBlacklist } from '../../utils/blacklist.js';\nimport { parseEnvironmentFromFilename } from '../../utils/env-files.js';\n\n/**\n * Lists all unique environment names discovered in the working directory by\n * scanning `.env.*` files, normalising `.local` and `.unencrypted` suffixes,\n * and filtering out blacklisted names.\n */\nexport class ListCommand implements ISubCommand<Record<string, never>, ListResult> {\n /** @inheritdoc */\n async execute(\n _options: Record<string, never>,\n context: CommandContext,\n ): Promise<CommandResult<ListResult>> {\n try {\n const [files, blacklist] = await Promise.all([\n Promise.resolve(listEnvFiles(context.cwd, '.env.*', ['.env.keys'])),\n readBlacklist(),\n ]);\n const blacklisted = new Set(blacklist);\n const names = files\n .map((f) => parseEnvironmentFromFilename(path.basename(f)))\n .filter((e): e is EnvironmentName => e !== undefined && !blacklisted.has(e));\n const environments = [...new Set(names)].sort();\n\n const message =\n environments.length > 0 ? environments.join('\\n') : 'No environments found.';\n\n return { success: true, data: { environments }, message };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `list` command onto the Commander program. */\nexport class ListBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('list')\n .description('List all environment names discovered in the working directory')\n .action(async () => {\n await this.dispatch(new ListCommand(), {}, this.buildContext(program));\n });\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { EnvironmentName } from '@envctrl/types';\nimport { resolveBlacklistPath } from './platform.js';\n\n/** Reads the blacklist from disk, returning an empty array if it does not exist. */\nexport async function readBlacklist(): Promise<EnvironmentName[]> {\n try {\n const raw = await fs.readFile(resolveBlacklistPath(), 'utf8');\n return JSON.parse(raw) as EnvironmentName[];\n } catch {\n return [];\n }\n}\n\n/** Writes the blacklist to disk. */\nexport async function writeBlacklist(entries: EnvironmentName[]): Promise<void> {\n const filePath = resolveBlacklistPath();\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, JSON.stringify(entries, null, 2) + '\\n', 'utf8');\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport type { Command } from 'commander';\nimport type { CommandContext, CommandResult, EnvironmentName, ISubCommand, RemoveResult } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { listEnvFiles } from '../../utils/dotenvx.js';\nimport { parseEnvironmentFromFilename } from '../../utils/env-files.js';\n\n/** Options parsed by Commander for the `rm` subcommand. */\ninterface RmOptions {\n environment: EnvironmentName;\n all: boolean;\n force: boolean;\n}\n\n/**\n * Removes environment files from the working directory.\n *\n * Without `--force`, performs a dry run listing files that would be deleted.\n * With `-a`, includes all associated file variants (`.local`, `.unencrypted`).\n * With `--force`, permanently deletes the resolved files.\n */\nexport class RmCommand implements ISubCommand<RmOptions, RemoveResult> {\n /** @inheritdoc */\n async execute(options: RmOptions, context: CommandContext): Promise<CommandResult<RemoveResult>> {\n const { environment, all, force } = options;\n\n try {\n const allFiles = listEnvFiles(context.cwd, '.env.*', ['.env.keys']);\n const candidates = allFiles.filter((f) => {\n const name = parseEnvironmentFromFilename(path.basename(f));\n return name === environment;\n });\n\n if (!all) {\n const primary = path.resolve(context.cwd, `.env.${environment}`);\n const subset = candidates.filter((f) => f === primary);\n return buildResult(environment, subset, force);\n }\n\n return buildResult(environment, candidates, force);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\nasync function buildResult(\n environment: EnvironmentName,\n files: string[],\n force: boolean,\n): Promise<CommandResult<RemoveResult>> {\n if (!force) {\n const preview = files.length > 0\n ? `Would delete:\\n${files.map((f) => ` ${f}`).join('\\n')}\\n\\nPass --force to confirm deletion.`\n : `No files found for environment: ${environment}`;\n\n return {\n success: true,\n data: { environment, deletedFiles: [] },\n message: preview,\n };\n }\n\n const deleted: string[] = [];\n for (const f of files) {\n try {\n await fs.rm(f, { force: true });\n deleted.push(f);\n } catch {}\n }\n\n const message =\n deleted.length > 0\n ? `Deleted:\\n${deleted.map((f) => ` ${f}`).join('\\n')}`\n : `No files found for environment: ${environment}`;\n\n return {\n success: true,\n data: { environment, deletedFiles: deleted },\n message,\n };\n}\n\n/** Registers the `rm <environment>` command onto the Commander program. */\nexport class RmBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('rm <environment>')\n .description('Remove environment files from the working directory')\n .option('-a, --all', 'include all associated file variants (.local, .unencrypted)', false)\n .option('--force', 'actually delete files (default is dry run)', false)\n .action(async (environment: string, opts: { all: boolean; force: boolean }) => {\n await this.dispatch(\n new RmCommand(),\n { environment, all: opts.all, force: opts.force },\n this.buildContext(program),\n );\n });\n }\n}\n","import type { Command } from 'commander';\nimport type { BlacklistResult, CommandContext, CommandResult, EnvironmentName, ISubCommand } from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { readBlacklist, writeBlacklist } from '../../utils/blacklist.js';\n\n/** Options parsed by Commander for `blacklist add`. */\ninterface BlacklistAddOptions {\n environment: EnvironmentName;\n}\n\n/** Options parsed by Commander for `blacklist rm`. */\ninterface BlacklistRmOptions {\n environment: EnvironmentName;\n}\n\n/**\n * Adds an environment name to the global blacklist, preventing it from\n * appearing in auto-detection results such as `envctrl list`.\n */\nexport class BlacklistAddSubCommand implements ISubCommand<BlacklistAddOptions, BlacklistResult> {\n /** @inheritdoc */\n async execute(\n options: BlacklistAddOptions,\n _context: CommandContext,\n ): Promise<CommandResult<BlacklistResult>> {\n const { environment } = options;\n\n try {\n const current = await readBlacklist();\n\n if (current.includes(environment)) {\n return {\n success: true,\n data: { environment, blacklisted: current },\n message: `Environment \"${environment}\" is already blacklisted.`,\n };\n }\n\n const updated = [...current, environment];\n await writeBlacklist(updated);\n\n return {\n success: true,\n data: { environment, blacklisted: updated },\n message: `Added \"${environment}\" to the blacklist.\\nBlacklisted environments:\\n${updated.map((e) => ` ${e}`).join('\\n')}`,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/**\n * Removes an environment name from the global blacklist, restoring it to\n * auto-detection results such as `envctrl list`.\n */\nexport class BlacklistRmSubCommand implements ISubCommand<BlacklistRmOptions, BlacklistResult> {\n /** @inheritdoc */\n async execute(\n options: BlacklistRmOptions,\n _context: CommandContext,\n ): Promise<CommandResult<BlacklistResult>> {\n const { environment } = options;\n\n try {\n const current = await readBlacklist();\n\n if (!current.includes(environment)) {\n return {\n success: false,\n error: `Environment \"${environment}\" is not in the blacklist.`,\n };\n }\n\n const updated = current.filter((e) => e !== environment);\n await writeBlacklist(updated);\n\n const message =\n updated.length > 0\n ? `Removed \"${environment}\" from the blacklist.\\nBlacklisted environments:\\n${updated.map((e) => ` ${e}`).join('\\n')}`\n : `Removed \"${environment}\" from the blacklist.\\nBlacklist is now empty.`;\n\n return {\n success: true,\n data: { environment, blacklisted: updated },\n message,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n}\n\n/** Registers the `blacklist` command group onto the Commander program. */\nexport class BlacklistBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n const blacklist = program\n .command('blacklist')\n .description('Manage the environment auto-detection blacklist');\n\n blacklist\n .command('add <environment>')\n .description('Exclude an environment from auto-detection')\n .action(async (environment: string) => {\n await this.dispatch(\n new BlacklistAddSubCommand(),\n { environment },\n this.buildContext(program),\n );\n });\n\n blacklist\n .command('rm <environment>')\n .description('Re-include an environment in auto-detection')\n .action(async (environment: string) => {\n await this.dispatch(\n new BlacklistRmSubCommand(),\n { environment },\n this.buildContext(program),\n );\n });\n }\n}\n","import fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { createInterface } from 'node:readline/promises';\nimport type { Command } from 'commander';\nimport type {\n CommandContext,\n CommandResult,\n CreateResult,\n EnvironmentName,\n ISubCommand,\n} from '@envctrl/types';\nimport { BaseCommand } from '../../base-command.js';\nimport { listEnvFiles, setKeyValue } from '../../utils/dotenvx.js';\nimport { parseEnvContent, parseEnvironmentFromFilename, buildEnvFilePair } from '../../utils/env-files.js';\nimport { readConfig, writeConfig } from '../../utils/config.js';\nimport { syncUnencryptedToEncrypted } from '../switch/sync.js';\n\n/** Options parsed by Commander for the `create` subcommand. */\ninterface CreateOptions {\n environment: EnvironmentName;\n /** Base environment to derive `.env.example` keys from (only used when environment is `\"example\"`). */\n from: string | undefined;\n}\n\n/**\n * Returns the list of currently existing environment names by scanning `.env.*` files\n * in `cwd`, excluding `.env.keys` and `.env.example`.\n */\nasync function listExistingEnvironments(cwd: string): Promise<EnvironmentName[]> {\n const files = listEnvFiles(cwd, '.env.*', ['.env.keys']);\n const names = files\n .map((f) => parseEnvironmentFromFilename(path.basename(f)))\n .filter((e): e is EnvironmentName => e !== undefined);\n return [...new Set(names)];\n}\n\n/**\n * Reads keys from an unencrypted env file and returns a `.env.example`-style\n * string with each key set to an empty value.\n */\nasync function buildExampleContent(unencryptedPath: string): Promise<string> {\n let raw = '';\n try {\n raw = await fs.readFile(unencryptedPath, 'utf8');\n } catch {\n return '';\n }\n const entries = parseEnvContent(raw);\n const lines = Object.keys(entries).map((k) => `${k}=`);\n return lines.length > 0 ? lines.join('\\n') + '\\n' : '';\n}\n\n/**\n * Creates environments or generates a `.env.example` file.\n *\n * - `example`: Writes `.env.example` with key names (empty values) copied from a base\n * environment. If `--from` is omitted the user is prompted interactively.\n * - existing environment: Rejected with an error.\n * - new environment: Creates `.env.<env>.unencrypted` and the encrypted `.env.<env>`,\n * records the environment in `.envctrl/config.json`, and re-encrypts `.env.local`\n * from `.env.local.unencrypted` if present.\n */\nexport class CreateCommand implements ISubCommand<CreateOptions, CreateResult> {\n /** @inheritdoc */\n async execute(\n options: CreateOptions,\n context: CommandContext,\n ): Promise<CommandResult<CreateResult>> {\n const { environment, cwd } = { ...options, cwd: context.cwd };\n\n try {\n if (environment === 'example') {\n return await this.createExample(options.from, cwd);\n }\n\n const existing = await listExistingEnvironments(cwd);\n if (existing.includes(environment)) {\n return {\n success: false,\n error: `Environment \"${environment}\" already exists. Use \"envctrl switch ${environment}\" to activate it.`,\n };\n }\n\n return await this.createEnvironment(environment, cwd);\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n private async createExample(\n from: string | undefined,\n cwd: string,\n ): Promise<CommandResult<CreateResult>> {\n const existing = await listExistingEnvironments(cwd);\n\n let base = from;\n if (!base) {\n if (existing.length === 0) {\n return {\n success: false,\n error: 'No environments found. Create one first with \"envctrl create <environment>\".',\n };\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n base = await rl.question(\n `Choose a base environment [${existing.join(', ')}]: `,\n );\n } finally {\n rl.close();\n }\n }\n\n if (!existing.includes(base)) {\n return {\n success: false,\n error: `Environment \"${base}\" does not exist. Available: ${existing.join(', ')}`,\n };\n }\n\n const pair = buildEnvFilePair(base, cwd);\n const content = await buildExampleContent(pair.unencrypted);\n const examplePath = path.resolve(cwd, '.env.example');\n await fs.writeFile(examplePath, content, 'utf8');\n\n return {\n success: true,\n data: {\n environment: 'example',\n createdFiles: [examplePath],\n isExample: true,\n baseEnvironment: base,\n },\n message: `Created .env.example from \"${base}\" (${Object.keys(parseEnvContent(content)).length} keys)`,\n };\n }\n\n private async createEnvironment(\n environment: EnvironmentName,\n cwd: string,\n ): Promise<CommandResult<CreateResult>> {\n const pair = buildEnvFilePair(environment, cwd);\n const created: string[] = [];\n\n await fs.writeFile(pair.unencrypted, '', 'utf8');\n created.push(pair.unencrypted);\n\n setKeyValue('_ENVCTRL_INIT', '1', pair.encrypted);\n created.push(pair.encrypted);\n\n const config = (await readConfig(cwd)) ?? { environment };\n await writeConfig(cwd, { ...config, environment });\n\n const localUnencrypted = path.resolve(cwd, '.env.local.unencrypted');\n const localEncrypted = path.resolve(cwd, '.env.local');\n const localExists = await fs\n .access(localUnencrypted)\n .then(() => true)\n .catch(() => false);\n\n if (localExists) {\n await syncUnencryptedToEncrypted('local', cwd);\n } else {\n const encryptedLocalExists = await fs\n .access(localEncrypted)\n .then(() => true)\n .catch(() => false);\n\n if (!encryptedLocalExists) {\n if (os.platform() === 'win32') {\n await fs.copyFile(pair.encrypted, localEncrypted);\n } else {\n await fs.symlink(pair.encrypted, localEncrypted);\n }\n created.push(localEncrypted);\n }\n }\n\n const lines = [\n `Created environment: ${environment}`,\n 'Files:',\n ...created.map((f) => ` ${f}`),\n ];\n if (localExists) {\n lines.push(`Updated: ${localEncrypted}`);\n }\n\n return {\n success: true,\n data: { environment, createdFiles: created, isExample: false },\n message: lines.join('\\n'),\n };\n }\n}\n\n/** Registers the `create <environment>` command onto the Commander program. */\nexport class CreateBaseCommand extends BaseCommand {\n /** @inheritdoc */\n register(program: Command): void {\n program\n .command('create <environment>')\n .description(\n 'Create a new environment or generate .env.example (use \"example\" as the environment name)',\n )\n .option('--from <env>', 'base environment for .env.example generation')\n .action(async (environment: string, opts: { from?: string }) => {\n await this.dispatch(\n new CreateCommand(),\n { environment, from: opts.from },\n this.buildContext(program),\n );\n });\n }\n}\n"],"mappings":";;;AAAA,SAAS,iBAAAA,sBAAqB;AAC9B,SAAS,eAAe;;;ACDxB,OAAOC,SAAQ;AACf,OAAO,QAAQ;AACf,OAAOC,WAAU;;;ACQV,IAAe,cAAf,MAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBhC,MAAgB,SACd,KACA,SACA,SACe;AACf,UAAM,SAAiC,MAAM,IAAI,QAAQ,SAAS,OAAO;AAEzE,QAAI,CAAC,OAAO,SAAS;AACnB,cAAQ,OAAO,MAAM,UAAU,OAAO,SAAS,eAAe;AAAA,CAAI;AAClE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,QAAI,CAAC,QAAQ,SAAS,OAAO,YAAY,QAAW;AAClD,cAAQ,OAAO,MAAM,OAAO,UAAU,IAAI;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,aAAaC,UAAkC;AACvD,UAAM,OAAOA,SAAQ,KAA0B;AAC/C,WAAO;AAAA,MACL,KAAK,QAAQ,IAAI;AAAA,MACjB,OAAO,KAAK,SAAS;AAAA,IACvB;AAAA,EACF;AACF;;;ACzDA,OAAO,UAAU;AAGjB,IAAM,qBAAqB,oBAAI,IAAI,CAAC,QAAQ,SAAS,CAAC;AAO/C,SAAS,6BAA6B,UAA+C;AAC1F,QAAM,OAAO,KAAK,SAAS,QAAQ;AAEnC,MAAI,CAAC,KAAK,WAAW,OAAO,GAAG;AAC7B,WAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,KAAK,MAAM,QAAQ,MAAM;AAE/C,MAAI,CAAC,iBAAiB,mBAAmB,IAAI,aAAa,GAAG;AAC3D,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,cAAc,SAAS,cAAc,IAC5C,cAAc,MAAM,GAAG,CAAC,eAAe,MAAM,IAC7C;AAEJ,MAAI,KAAK,SAAS,QAAQ,GAAG;AAC3B,WAAO,KAAK,MAAM,GAAG,CAAC,SAAS,MAAM;AAAA,EACvC;AAEA,MAAI,CAAC,QAAQ,mBAAmB,IAAI,IAAI,GAAG;AACzC,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAQO,SAAS,iBAAiB,aAA8B,KAA0B;AACvF,SAAO;AAAA,IACL;AAAA,IACA,aAAa,KAAK,QAAQ,KAAK,QAAQ,WAAW,cAAc;AAAA,IAChE,WAAW,KAAK,QAAQ,KAAK,QAAQ,WAAW,EAAE;AAAA,EACpD;AACF;AASO,SAAS,gBAAgB,SAAyC;AACvE,QAAM,SAAiC,CAAC;AAExC,aAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,UAAM,UAAU,KAAK,KAAK;AAE1B,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,GAAG;AACvC;AAAA,IACF;AAEA,UAAM,QAAQ,QAAQ,QAAQ,GAAG;AACjC,QAAI,UAAU,IAAI;AAChB;AAAA,IACF;AAEA,UAAM,MAAM,QAAQ,MAAM,GAAG,KAAK,EAAE,KAAK;AACzC,UAAM,QAAQ,QAAQ,MAAM,QAAQ,CAAC,EAAE,KAAK;AAC5C,WAAO,GAAG,IAAI;AAAA,EAChB;AAEA,SAAO;AACT;AAYO,SAAS,cAAc,SAAiB,KAAa,OAAuB;AACjF,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,UAAU,IAAI,OAAO,IAAI,GAAG,OAAO;AACzC,MAAI,WAAW;AAEf,QAAM,UAAU,MAAM,IAAI,CAAC,SAAS;AAClC,QAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,iBAAW;AACX,aAAO,GAAG,GAAG,IAAI,KAAK;AAAA,IACxB;AACA,WAAO;AAAA,EACT,CAAC;AAED,MAAI,CAAC,UAAU;AACb,QAAI,QAAQ,QAAQ,SAAS,CAAC,MAAM,IAAI;AACtC,cAAQ,KAAK,GAAG,GAAG,IAAI,KAAK,EAAE;AAAA,IAChC,OAAO;AACL,cAAQ,OAAO,QAAQ,SAAS,GAAG,GAAG,GAAG,GAAG,IAAI,KAAK,EAAE;AAAA,IACzD;AAAA,EACF;AAEA,SAAO,QAAQ,KAAK,IAAI;AAC1B;;;AClHA,SAAS,qBAAqB;AAC9B,OAAOC,WAAU;AACjB,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,YAAY,aAAa;AAGzB,IAAM,gBAAgB,UAAU,QAAQ;AAQxC,SAAS,oBAA4B;AACnC,QAAMC,WAAU,cAAc,YAAY,GAAG;AAC7C,QAAM,cAAcA,SAAQ,QAAQ,+BAA+B;AACnE,QAAM,UAAUA,SAAQ,+BAA+B;AAGvD,QAAM,aAAa,QAAQ,IAAI,SAAS;AACxC,SAAOD,MAAK,QAAQA,MAAK,QAAQ,WAAW,GAAG,UAAU;AAC3D;AAUO,SAAS,YACd,KACA,OACA,mBACA,cACkB;AAClB,QAAM,SAAiB,YAAI,KAAK,OAAO;AAAA,IACrC,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,IACP,GAAI,eAAe,EAAE,aAAa,aAAa,IAAI,CAAC;AAAA,EACtD,CAAC;AAED,SAAO;AAAA,IACL,kBAAkB,OAAO;AAAA,IACzB,oBAAoB,OAAO;AAAA,EAC7B;AACF;AAUA,eAAsB,YAAY,UAAiD;AACjF,QAAM,MAAM,kBAAkB;AAC9B,QAAM,cAAc,QAAQ,UAAU,CAAC,KAAK,WAAW,MAAM,QAAQ,CAAC;AAEtE,SAAO;AAAA,IACL,kBAAkB,CAAC,QAAQ;AAAA,IAC3B,oBAAoB,CAAC;AAAA,EACvB;AACF;AASO,SAAS,aACd,WACA,SACA,SACU;AACV,SAAe,WAAG,WAAW,SAAS,OAAO;AAC/C;;;ACnFA,OAAO,QAAQ;AAcf,eAAsB,2BACpB,aACA,KACe;AACf,QAAM,OAAO,iBAAiB,aAAa,GAAG;AAE9C,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,GAAG,SAAS,KAAK,aAAa,MAAM;AAAA,EACtD,QAAQ;AACN;AAAA,EACF;AAEA,QAAM,UAAU,gBAAgB,OAAO;AAEvC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,gBAAY,KAAK,OAAO,KAAK,SAAS;AAAA,EACxC;AACF;;;AJVO,IAAM,gBAAN,MAAwE;AAAA;AAAA,EAE7E,MAAM,QACJ,SACA,SACsC;AACtC,UAAM,EAAE,aAAa,IAAI,IAAI,EAAE,GAAG,SAAS,KAAK,QAAQ,IAAI;AAC5D,UAAM,OAAO,iBAAiB,aAAa,GAAG;AAC9C,UAAM,UAAoB,CAAC;AAE3B,QAAI;AACF,UAAI;AACF,cAAME,IAAG,OAAO,KAAK,WAAW;AAAA,MAClC,QAAQ;AACN,cAAMA,IAAG,UAAU,KAAK,aAAa,IAAI,MAAM;AAC/C,gBAAQ,KAAK,KAAK,WAAW;AAAA,MAC/B;AAEA,YAAM,kBAAkB,MAAMA,IAC3B,OAAO,KAAK,SAAS,EACrB,KAAK,MAAM,IAAI,EACf,MAAM,MAAM,KAAK;AAEpB,YAAM,2BAA2B,aAAa,GAAG;AAEjD,UAAI,CAAC,iBAAiB;AACpB,cAAM,eAAe,MAAMA,IACxB,OAAO,KAAK,SAAS,EACrB,KAAK,MAAM,KAAK,EAChB,MAAM,MAAM,IAAI;AAEnB,YAAI,cAAc;AAChB,sBAAY,iBAAiB,KAAK,KAAK,SAAS;AAChD,kBAAQ,KAAK,KAAK,SAAS;AAAA,QAC7B,OAAO;AACL,kBAAQ,KAAK,KAAK,SAAS;AAAA,QAC7B;AAAA,MACF;AAEA,YAAM,aAAaC,MAAK,QAAQ,KAAK,MAAM;AAE3C,UAAI;AACF,cAAMD,IAAG,OAAO,UAAU;AAAA,MAC5B,QAAQ;AAAA,MAAC;AAET,UAAI,GAAG,SAAS,MAAM,SAAS;AAC7B,cAAMA,IAAG,SAAS,KAAK,WAAW,UAAU;AAAA,MAC9C,OAAO;AACL,cAAMA,IAAG,QAAQ,KAAK,WAAW,UAAU;AAAA,MAC7C;AAEA,YAAM,QAAQ,CAAC,gBAAgB,WAAW,EAAE;AAC5C,UAAI,QAAQ,SAAS,GAAG;AACtB,cAAM,KAAK,YAAY,GAAG,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;AAAA,MACxD;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,EAAE,aAAa,SAAS,WAAW;AAAA,QACzC,SAAS,MAAM,KAAK,IAAI;AAAA,MAC1B;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,oBAAN,cAAgC,YAAY;AAAA;AAAA,EAEjD,SAASE,UAAwB;AAC/B,IAAAA,SACG,QAAQ,sBAAsB,EAC9B,YAAY,6DAA6D,EACzE,OAAO,OAAO,gBAAwB;AACrC,YAAM,KAAK,SAAS,IAAI,cAAc,GAAG,EAAE,YAAY,GAAG,KAAK,aAAaA,QAAO,CAAC;AAAA,IACtF,CAAC;AAAA,EACL;AACF;;;AKvGA,OAAOC,SAAQ;AACf,OAAOC,WAAU;;;ACDjB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AASjB,SAAS,qBAA6B;AACpC,QAAM,WAAWD,IAAG,SAAS;AAC7B,QAAM,OAAOA,IAAG,QAAQ;AAExB,MAAI,aAAa,SAAS;AACxB,UAAM,UAAU,QAAQ,IAAI,SAAS,KAAKC,MAAK,KAAK,MAAM,WAAW,SAAS;AAC9E,WAAOA,MAAK,KAAK,SAAS,SAAS;AAAA,EACrC;AAEA,MAAI,aAAa,UAAU;AACzB,WAAOA,MAAK,KAAK,MAAM,WAAW,uBAAuB,SAAS;AAAA,EACpE;AAEA,QAAM,cAAc,QAAQ,IAAI,eAAe,KAAKA,MAAK,KAAK,MAAM,UAAU,OAAO;AACrF,SAAOA,MAAK,KAAK,aAAa,SAAS;AACzC;AASO,SAAS,6BAAqC;AACnD,SAAOA,MAAK,KAAK,mBAAmB,GAAG,aAAa,SAAS;AAC/D;AAQO,SAAS,+BAAuC;AACrD,SAAOA,MAAK,KAAK,mBAAmB,GAAG,gBAAgB;AACzD;AAGO,SAAS,uBAA+B;AAC7C,SAAOA,MAAK,KAAK,mBAAmB,GAAG,gBAAgB;AACzD;;;ACnDA,OAAOC,SAAQ;AAUf,eAAsB,aAAa,cAAgD;AACjF,MAAI;AACF,UAAM,MAAM,MAAMA,IAAG,SAAS,cAAc,MAAM;AAClD,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAQA,eAAsB,cAAc,cAAsB,SAAyC;AACjG,QAAMA,IAAG,UAAU,cAAc,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI,MAAM,MAAM;AAClF;;;AFTO,IAAM,2BAAN,MAGL;AAAA;AAAA,EAEA,MAAM,QACJ,SACA,UACwC;AACxC,UAAM,eAAe,QAAQ,gBAAgB,2BAA2B;AACxE,UAAM,OAAO,QAAQ,QAAQC,MAAK,SAAS,YAAY;AAEvD,QAAI;AACF,YAAMC,IAAG,MAAM,cAAc,EAAE,WAAW,KAAK,CAAC;AAEhD,YAAM,WAAWD,MAAK,KAAK,cAAc,WAAW;AACpD,UAAI;AACF,cAAMC,IAAG,OAAO,QAAQ;AAAA,MAC1B,QAAQ;AACN,cAAMA,IAAG,UAAU,UAAU,oBAAoB,MAAM;AAAA,MACzD;AAEA,YAAM,eAAe,6BAA6B;AAClD,YAAMA,IAAG,MAAMD,MAAK,QAAQ,YAAY,GAAG,EAAE,WAAW,KAAK,CAAC;AAE9D,YAAM,WAAW,MAAM,aAAa,YAAY;AAChD,YAAM,SAAS,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,SAAS,YAAY;AAE9E,UAAI,CAAC,QAAQ;AACX,iBAAS,KAAK,EAAE,MAAM,MAAM,aAAa,CAAC;AAC1C,cAAM,cAAc,cAAc,QAAQ;AAAA,MAC5C;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,EAAE,MAAM,aAAa;AAAA,QAC3B,SAAS,wBAAwB,YAAY;AAAA,MAC/C;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;;;AGtDO,IAAM,yBAAN,MAA4F;AAAA;AAAA,EAEjG,MAAM,QACJ,UACA,UACyC;AACzC,QAAI;AACF,YAAM,eAAe,6BAA6B;AAClD,YAAM,UAAU,MAAM,aAAa,YAAY;AAE/C,UAAI;AACJ,UAAI,QAAQ,WAAW,GAAG;AACxB,kBAAU;AAAA,MACZ,OAAO;AACL,cAAM,SAAS,KAAK,IAAI,GAAG,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK,MAAM,CAAC;AAC5D,kBAAU,QAAQ,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,OAAO,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,IAAI;AAAA,MAC/E;AAEA,aAAO,EAAE,SAAS,MAAM,MAAM,SAAS,QAAQ;AAAA,IACjD,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;;;ACnCA,OAAOE,SAAQ;AAiBR,IAAM,2BAAN,MAA4F;AAAA;AAAA,EAEjG,MAAM,QACJ,SACA,UACuC;AACvC,UAAM,EAAE,MAAM,MAAM,IAAI;AAExB,QAAI;AACF,YAAM,eAAe,6BAA6B;AAClD,YAAM,WAAW,MAAM,aAAa,YAAY;AAChD,YAAM,QAAQ,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAElD,UAAI,CAAC,OAAO;AACV,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,aAAa,IAAI;AAAA,QAC1B;AAAA,MACF;AAEA,UAAI,CAAC,OAAO;AACV,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,iDAAiD,IAAI,QAAQ,MAAM,IAAI;AAAA,QAChF;AAAA,MACF;AAEA,YAAM,UAAU,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,IAAI;AACtD,YAAM,cAAc,cAAc,OAAO;AAEzC,YAAMC,IAAG,GAAG,MAAM,MAAM,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAExD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM;AAAA,QACN,SAAS,qBAAqB,MAAM,IAAI,KAAK,MAAM,IAAI;AAAA,MACzD;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;;;ACtDO,IAAM,sBAAN,cAAkC,YAAY;AAAA;AAAA,EAEnD,SAASC,UAAwB;AAC/B,UAAM,cAAcA,SACjB,QAAQ,UAAU,EAClB,YAAY,sDAAsD;AAErE,gBACG,QAAQ,eAAe,EACvB,YAAY,8DAA8D,EAC1E,OAAO,qBAAqB,6CAA6C,EACzE,OAAO,OAAO,cAAkC,SAA4B;AAC3E,YAAM,KAAK;AAAA,QACT,IAAI,yBAAyB;AAAA,QAC7B,EAAE,cAAc,MAAM,KAAK,KAAK;AAAA,QAChC,KAAK,aAAaA,QAAO;AAAA,MAC3B;AAAA,IACF,CAAC;AAEH,gBACG,QAAQ,MAAM,EACd,YAAY,+BAA+B,EAC3C,OAAO,YAAY;AAClB,YAAM,KAAK,SAAS,IAAI,uBAAuB,GAAG,CAAC,GAAG,KAAK,aAAaA,QAAO,CAAC;AAAA,IAClF,CAAC;AAEH,gBACG,QAAQ,eAAe,EACvB,YAAY,yDAAyD,EACrE,OAAO,WAAW,4CAA4C,KAAK,EACnE,OAAO,OAAO,MAAc,SAA6B;AACxD,YAAM,KAAK;AAAA,QACT,IAAI,yBAAyB;AAAA,QAC7B,EAAE,MAAM,OAAO,KAAK,MAAM;AAAA,QAC1B,KAAK,aAAaA,QAAO;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACL;AACF;;;AC7CA,OAAOC,SAAQ;AAqBR,IAAM,aAAN,MAA+D;AAAA;AAAA,EAEpE,MAAM,QAAQ,SAAqB,SAA4D;AAC7F,UAAM,EAAE,aAAa,KAAK,MAAM,IAAI;AACpC,UAAM,OAAO,iBAAiB,aAAa,QAAQ,GAAG;AAEtD,QAAI;AACF,UAAI,kBAAkB;AACtB,UAAI;AACF,0BAAkB,MAAMC,IAAG,SAAS,KAAK,aAAa,MAAM;AAAA,MAC9D,QAAQ;AAAA,MAAC;AAET,YAAM,iBAAiB,cAAc,iBAAiB,KAAK,KAAK;AAChE,YAAMA,IAAG,UAAU,KAAK,aAAa,gBAAgB,MAAM;AAE3D,YAAM,SAAS,YAAY,KAAK,OAAO,KAAK,SAAS;AACrD,YAAM,UAAU,OAAO,iBAAiB,SAAS;AAEjD,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,EAAE,aAAa,KAAK,QAAQ;AAAA,QAClC,SAAS,OAAO,GAAG,OAAO,WAAW;AAAA,MACvC;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,iBAAN,cAA6B,YAAY;AAAA;AAAA,EAE9C,SAASC,UAAwB;AAC/B,IAAAA,SACG,QAAQ,iCAAiC,EACzC,YAAY,+DAA+D,EAC3E,OAAO,OAAO,aAAqB,KAAa,UAAkB;AACjE,YAAM,KAAK;AAAA,QACT,IAAI,WAAW;AAAA,QACf,EAAE,aAAa,KAAK,MAAM;AAAA,QAC1B,KAAK,aAAaA,QAAO;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACL;AACF;;;ACpEA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAiBV,IAAM,iBAAN,MAA2E;AAAA;AAAA,EAEhF,MAAM,QACJ,SACA,SACuC;AACvC,UAAM,EAAE,IAAI,IAAI;AAEhB,QAAI;AACF,YAAM,UACJ,QAAQ,MAAM,SAAS,IACnB,QAAQ,MAAM,IAAI,CAAC,MAAMC,MAAK,QAAQ,KAAK,CAAC,CAAC,IAC7C,aAAa,KAAK,UAAU,CAAC,aAAa,eAAe,CAAC;AAEhE,YAAM,eAAyB,CAAC;AAChC,YAAM,iBAA2B,CAAC;AAElC,iBAAW,YAAY,SAAS;AAC9B,cAAM,WAAWA,MAAK,SAAS,QAAQ;AACvC,cAAM,cAAc,6BAA6B,QAAQ;AAEzD,YAAI,CAAC,aAAa;AAChB,yBAAe,KAAK,QAAQ;AAC5B;AAAA,QACF;AAEA,cAAM,kBAAkBA,MAAK;AAAA,UAC3BA,MAAK,QAAQ,QAAQ;AAAA,UACrB,QAAQ,WAAW;AAAA,QACrB;AAEA,YAAI;AACF,gBAAM,UAAU,MAAMC,IAAG,SAAS,UAAU,MAAM;AAElD,cAAI;AACF,kBAAMA,IAAG,OAAO,eAAe;AAAA,UACjC,QAAQ;AACN,kBAAMA,IAAG,UAAU,iBAAiB,SAAS,MAAM;AAAA,UACrD;AAEA,gBAAM,SAAS,MAAM,YAAY,QAAQ;AACzC,uBAAa,KAAK,GAAG,OAAO,gBAAgB;AAAA,QAC9C,QAAQ;AACN,yBAAe,KAAK,QAAQ;AAAA,QAC9B;AAAA,MACF;AAEA,YAAM,QAAkB;AAAA,QACtB,GAAG,aAAa,IAAI,CAAC,MAAM,cAAc,CAAC,EAAE;AAAA,QAC5C,GAAG,eAAe,IAAI,CAAC,MAAM,cAAc,CAAC,EAAE;AAAA,MAChD;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,EAAE,cAAc,eAAe;AAAA,QACrC,SAAS,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAAA,MACjD;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,qBAAN,cAAiC,YAAY;AAAA;AAAA,EAElD,SAASC,UAAwB;AAC/B,IAAAA,SACG,QAAQ,oBAAoB,EAC5B,YAAY,gEAAgE,EAC5E,OAAO,OAAO,UAAoB;AACjC,YAAM,KAAK,SAAS,IAAI,eAAe,GAAG,EAAE,MAAM,GAAG,KAAK,aAAaA,QAAO,CAAC;AAAA,IACjF,CAAC;AAAA,EACL;AACF;;;AC/FA,OAAOC,UAAQ;AACf,OAAOC,SAAQ;AACf,OAAOC,WAAU;;;ACFjB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAUjB,eAAsB,kBAAkB,UAAmC;AACzE,MAAI,MAAM;AAEV,SAAO,MAAM;AACX,QAAI;AACF,YAAMD,IAAG,OAAOC,MAAK,KAAK,KAAK,qBAAqB,CAAC;AACrD,aAAO;AAAA,IACT,QAAQ;AAAA,IAAC;AAET,QAAI;AACF,YAAM,MAAM,MAAMD,IAAG,SAASC,MAAK,KAAK,KAAK,cAAc,GAAG,MAAM;AACpE,YAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,UAAI,IAAI,WAAY,QAAO;AAAA,IAC7B,QAAQ;AAAA,IAAC;AAET,UAAM,SAASA,MAAK,QAAQ,GAAG;AAC/B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACF;AAMA,eAAe,sBAAsB,eAA0C;AAC7E,MAAI;AACF,UAAM,MAAM,MAAMD,IAAG,SAASC,MAAK,KAAK,eAAe,qBAAqB,GAAG,MAAM;AACrF,UAAM,WAAqB,CAAC;AAC5B,QAAI,aAAa;AAEjB,eAAW,QAAQ,IAAI,MAAM,IAAI,GAAG;AAClC,UAAI,gBAAgB,KAAK,IAAI,GAAG;AAC9B,qBAAa;AACb;AAAA,MACF;AACA,UAAI,YAAY;AACd,cAAM,QAAQ,KAAK,MAAM,4BAA4B;AACrD,YAAI,OAAO;AACT,mBAAS,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC;AAAA,QAC/B,WAAW,KAAK,KAAK,KAAK,CAAC,KAAK,WAAW,GAAG,GAAG;AAC/C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,SAAS,SAAS,EAAG,QAAO;AAAA,EAClC,QAAQ;AAAA,EAAC;AAET,MAAI;AACF,UAAM,MAAM,MAAMD,IAAG,SAASC,MAAK,KAAK,eAAe,cAAc,GAAG,MAAM;AAC9E,UAAM,MAAM,KAAK,MAAM,GAAG;AAG1B,QAAI,MAAM,QAAQ,IAAI,UAAU,EAAG,QAAO,IAAI;AAC9C,QAAI,IAAI,YAAY,SAAU,QAAO,IAAI,WAAW;AAAA,EACtD,QAAQ;AAAA,EAAC;AAET,SAAO,CAAC;AACV;AAMA,eAAe,cAAc,eAAuB,SAAoC;AACtF,MAAI,CAAC,QAAQ,SAAS,GAAG,GAAG;AAC1B,WAAO,CAACA,MAAK,QAAQ,eAAe,OAAO,CAAC;AAAA,EAC9C;AAEA,QAAM,YAAY,QAAQ,QAAQ,GAAG;AACrC,QAAM,eAAe,QAAQ,MAAM,GAAG,SAAS,EAAE,QAAQ,OAAO,EAAE;AAClE,QAAM,SAAS,QAAQ,MAAM,YAAY,CAAC;AAC1C,QAAM,UAAUA,MAAK,QAAQ,eAAe,YAAY;AAExD,MAAI;AACF,UAAM,UAAU,MAAMD,IAAG,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AACjE,WAAO,QACJ,OAAO,CAAC,MAAM,EAAE,YAAY,KAAK,CAAC,EAAE,KAAK,WAAW,GAAG,CAAC,EACxD,IAAI,CAAC,MAAMC,MAAK,KAAK,SAAS,EAAE,OAAO,MAAM,CAAC;AAAA,EACnD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAMA,eAAsB,sBAAsB,eAAoD;AAC9F,QAAM,WAAW,MAAM,sBAAsB,aAAa;AAC1D,QAAM,WAA+B,CAAC;AAEtC,aAAW,WAAW,UAAU;AAC9B,UAAM,OAAO,MAAM,cAAc,eAAe,OAAO;AAEvD,eAAW,OAAO,MAAM;AACtB,UAAI;AACF,cAAM,MAAM,MAAMD,IAAG,SAASC,MAAK,KAAK,KAAK,cAAc,GAAG,MAAM;AACpE,cAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,YAAI,IAAI,MAAM;AACZ,mBAAS,KAAK;AAAA,YACZ,MAAM,IAAI;AAAA,YACV,MAAMA,MAAK,SAAS,eAAe,GAAG;AAAA,UACxC,CAAC;AAAA,QACH;AAAA,MACF,QAAQ;AAAA,MAAC;AAAA,IACX;AAAA,EACF;AAEA,SAAO;AACT;;;ACpGO,SAAS,yBAA2C;AACzD,MAAI,QAAQ,IAAI,QAAQ,MAAM,KAAK;AACjC,UAAM,YAAY,QAAQ,IAAI,YAAY;AAC1C,WAAO;AAAA,MACL,UAAU;AAAA,MACV,aAAa,cAAc,eAAe,eAAe;AAAA,IAC3D;AAAA,EACF;AAEA,MAAI,QAAQ,IAAI,SAAS,MAAM,QAAQ;AACrC,UAAM,UAAU,QAAQ,IAAI,SAAS;AACrC,WAAO;AAAA,MACL,UAAU;AAAA,MACV,aAAa,YAAY,eAAe,eAAe;AAAA,IACzD;AAAA,EACF;AAEA,MAAI,QAAQ,IAAI,0BAA0B,MAAM,QAAW;AACzD,UAAM,aAAa,QAAQ,IAAI,0BAA0B;AACzD,WAAO;AAAA,MACL,UAAU;AAAA,MACV,aAAa,eAAe,eAAe,eAAe;AAAA,IAC5D;AAAA,EACF;AAEA,SAAO,EAAE,UAAU,MAAM,aAAa,KAAK;AAC7C;;;AChDA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAUV,SAAS,kBACd,KACA,MAAM,YACN,OAAO,eACC;AACR,SAAOA,MAAK,KAAK,KAAK,KAAK,IAAI;AACjC;AAUA,eAAsB,WACpB,KACA,MAAM,YACN,OAAO,eACwB;AAC/B,MAAI;AACF,UAAM,MAAM,MAAMD,IAAG,SAAS,kBAAkB,KAAK,KAAK,IAAI,GAAG,MAAM;AACvE,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAWA,eAAsB,YACpB,KACA,QACA,MAAM,YACN,OAAO,eACU;AACjB,QAAM,YAAYC,MAAK,KAAK,KAAK,GAAG;AACpC,QAAMD,IAAG,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC7C,QAAM,aAAa,kBAAkB,KAAK,KAAK,IAAI;AACnD,QAAMA,IAAG,UAAU,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,MAAM;AAC7E,SAAO;AACT;;;AH3BO,IAAM,cAAN,MAAkE;AAAA;AAAA,EAEvE,MAAM,QAAQ,SAAsB,SAA6D;AAC/F,UAAM,WAAW,QAAQ,YACrBE,MAAK,QAAQ,QAAQ,KAAK,QAAQ,SAAS,IAC3C,QAAQ;AAEZ,UAAM,YAAY,QAAQ,aAAa;AACvC,UAAM,aAAa,QAAQ,cAAc;AAEzC,QAAI;AACF,YAAM,gBAAgB,MAAM,kBAAkB,QAAQ;AACtD,YAAM,WAAW,MAAM,sBAAsB,aAAa;AAE1D,YAAM,eAAe,QAAQ,YAAY,2BAA2B;AACpE,YAAM,eAAe,QAAQ,QAAQA,MAAK,SAAS,aAAa;AAEhE,YAAMC,KAAG,MAAM,cAAc,EAAE,WAAW,KAAK,CAAC;AAEhD,YAAM,WAAWD,MAAK,KAAK,cAAc,WAAW;AACpD,UAAI;AACF,cAAMC,KAAG,OAAO,QAAQ;AAAA,MAC1B,QAAQ;AACN,cAAMA,KAAG,UAAU,UAAU,oBAAoB,MAAM;AAAA,MACzD;AAEA,YAAM,eAAe,6BAA6B;AAClD,YAAMA,KAAG,MAAMD,MAAK,QAAQ,YAAY,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9D,YAAM,WAAW,MAAM,aAAa,YAAY;AAChD,YAAM,oBAAoB,SAAS;AAAA,QACjC,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,SAAS;AAAA,MAC/C;AACA,UAAI,CAAC,mBAAmB;AACtB,iBAAS,KAAK,EAAE,MAAM,cAAc,MAAM,aAAa,CAAC;AACxD,cAAM,cAAc,cAAc,QAAQ;AAAA,MAC5C;AAEA,YAAM,cAAc;AAAA,QAClB;AAAA,QACA,GAAG,SAAS,IAAI,CAAC,MAAMA,MAAK,QAAQ,eAAe,EAAE,IAAI,CAAC;AAAA,MAC5D;AAEA,YAAM,aAAuB,CAAC;AAE9B,iBAAW,OAAO,aAAa;AAC7B,cAAM,WAAW,aAAa,KAAK,UAAU,CAAC,WAAW,CAAC;AAC1D,YAAI,SAAS,WAAW,EAAG;AAE3B,cAAM,WAAWA,MAAK,KAAK,KAAK,WAAW;AAC3C,YAAI;AACF,gBAAMC,KAAG,OAAO,QAAQ;AAAA,QAC1B,QAAQ;AACN,cAAIC,IAAG,SAAS,MAAM,SAAS;AAC7B,kBAAMD,KAAG,SAAS,UAAU,QAAQ;AAAA,UACtC,OAAO;AACL,kBAAMA,KAAG,QAAQ,UAAU,QAAQ;AAAA,UACrC;AACA,qBAAW,KAAK,QAAQ;AAAA,QAC1B;AAAA,MACF;AAEA,YAAM,WAAW,uBAAuB;AACxC,YAAM,cAAc,SAAS,eAAe;AAC5C,YAAM,eAAe,SAAS,aAAa;AAE3C,YAAM,aAAa,MAAM;AAAA,QACvB,QAAQ;AAAA,QACR,EAAE,YAAY;AAAA,QACd;AAAA,QACA;AAAA,MACF;AAEA,YAAM,QAAQ,CAAC,cAAc,aAAa,IAAI,cAAc,YAAY,EAAE;AAC1E,UAAI,SAAS,SAAS,GAAG;AACvB,cAAM,KAAK,WAAW;AACtB,mBAAW,KAAK,SAAU,OAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,IAAI,GAAG;AAAA,MAChE;AACA,UAAI,WAAW,SAAS,GAAG;AACzB,cAAM,KAAK,mBAAmB;AAC9B,mBAAW,KAAK,WAAY,OAAM,KAAK,KAAK,CAAC,EAAE;AAAA,MACjD;AACA,YAAM;AAAA,QACJ,cAAc,UAAU;AAAA,QACxB,gBAAgB,WAAW,GAAG,eAAe,wBAAwB,SAAS,QAAQ,MAAM,EAAE;AAAA,MAChG;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,EAAE,eAAe,UAAU,cAAc,YAAY,YAAY,aAAa,aAAa;AAAA,QACjG,SAAS,MAAM,KAAK,IAAI;AAAA,MAC1B;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,kBAAN,cAA8B,YAAY;AAAA;AAAA,EAE/C,SAASE,UAAwB;AAC/B,IAAAA,SACG,QAAQ,kBAAkB,EAC1B;AAAA,MACC;AAAA,IACF,EACC,OAAO,qBAAqB,6CAA6C,EACzE,OAAO,yBAAyB,gCAAgC,EAChE,OAAO,sBAAsB,2CAA2C,EACxE,OAAO,wBAAwB,yCAAyC,EACxE;AAAA,MACC,OACE,WACA,SACG;AACH,cAAM,KAAK;AAAA,UACT,IAAI,YAAY;AAAA,UAChB;AAAA,YACE;AAAA,YACA,MAAM,KAAK;AAAA,YACX,UAAU,KAAK;AAAA,YACf,WAAW,KAAK;AAAA,YAChB,YAAY,KAAK;AAAA,UACnB;AAAA,UACA,KAAK,aAAaA,QAAO;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AAAA,EACJ;AACF;;;AIrKA,OAAOC,YAAU;;;ACAjB,OAAOC,UAAQ;AACf,OAAOC,YAAU;AAKjB,eAAsB,gBAA4C;AAChE,MAAI;AACF,UAAM,MAAM,MAAMC,KAAG,SAAS,qBAAqB,GAAG,MAAM;AAC5D,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAGA,eAAsB,eAAe,SAA2C;AAC9E,QAAM,WAAW,qBAAqB;AACtC,QAAMA,KAAG,MAAMC,OAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D,QAAMD,KAAG,UAAU,UAAU,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI,MAAM,MAAM;AAC9E;;;ADPO,IAAM,cAAN,MAA4E;AAAA;AAAA,EAEjF,MAAM,QACJ,UACA,SACoC;AACpC,QAAI;AACF,YAAM,CAAC,OAAO,SAAS,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC3C,QAAQ,QAAQ,aAAa,QAAQ,KAAK,UAAU,CAAC,WAAW,CAAC,CAAC;AAAA,QAClE,cAAc;AAAA,MAChB,CAAC;AACD,YAAM,cAAc,IAAI,IAAI,SAAS;AACrC,YAAM,QAAQ,MACX,IAAI,CAAC,MAAM,6BAA6BE,OAAK,SAAS,CAAC,CAAC,CAAC,EACzD,OAAO,CAAC,MAA4B,MAAM,UAAa,CAAC,YAAY,IAAI,CAAC,CAAC;AAC7E,YAAM,eAAe,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,EAAE,KAAK;AAE9C,YAAM,UACJ,aAAa,SAAS,IAAI,aAAa,KAAK,IAAI,IAAI;AAEtD,aAAO,EAAE,SAAS,MAAM,MAAM,EAAE,aAAa,GAAG,QAAQ;AAAA,IAC1D,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,kBAAN,cAA8B,YAAY;AAAA;AAAA,EAE/C,SAASC,UAAwB;AAC/B,IAAAA,SACG,QAAQ,MAAM,EACd,YAAY,gEAAgE,EAC5E,OAAO,YAAY;AAClB,YAAM,KAAK,SAAS,IAAI,YAAY,GAAG,CAAC,GAAG,KAAK,aAAaA,QAAO,CAAC;AAAA,IACvE,CAAC;AAAA,EACL;AACF;;;AEtDA,OAAOC,UAAQ;AACf,OAAOC,YAAU;AAqBV,IAAM,YAAN,MAAgE;AAAA;AAAA,EAErE,MAAM,QAAQ,SAAoB,SAA+D;AAC/F,UAAM,EAAE,aAAa,KAAK,MAAM,IAAI;AAEpC,QAAI;AACF,YAAM,WAAW,aAAa,QAAQ,KAAK,UAAU,CAAC,WAAW,CAAC;AAClE,YAAM,aAAa,SAAS,OAAO,CAAC,MAAM;AACxC,cAAM,OAAO,6BAA6BC,OAAK,SAAS,CAAC,CAAC;AAC1D,eAAO,SAAS;AAAA,MAClB,CAAC;AAED,UAAI,CAAC,KAAK;AACR,cAAM,UAAUA,OAAK,QAAQ,QAAQ,KAAK,QAAQ,WAAW,EAAE;AAC/D,cAAM,SAAS,WAAW,OAAO,CAAC,MAAM,MAAM,OAAO;AACrD,eAAO,YAAY,aAAa,QAAQ,KAAK;AAAA,MAC/C;AAEA,aAAO,YAAY,aAAa,YAAY,KAAK;AAAA,IACnD,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAEA,eAAe,YACb,aACA,OACA,OACsC;AACtC,MAAI,CAAC,OAAO;AACV,UAAM,UAAU,MAAM,SAAS,IAC3B;AAAA,EAAkB,MAAM,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA,qCACvD,mCAAmC,WAAW;AAElD,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM,EAAE,aAAa,cAAc,CAAC,EAAE;AAAA,MACtC,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,UAAoB,CAAC;AAC3B,aAAW,KAAK,OAAO;AACrB,QAAI;AACF,YAAMC,KAAG,GAAG,GAAG,EAAE,OAAO,KAAK,CAAC;AAC9B,cAAQ,KAAK,CAAC;AAAA,IAChB,QAAQ;AAAA,IAAC;AAAA,EACX;AAEA,QAAM,UACJ,QAAQ,SAAS,IACb;AAAA,EAAa,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,KACpD,mCAAmC,WAAW;AAEpD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM,EAAE,aAAa,cAAc,QAAQ;AAAA,IAC3C;AAAA,EACF;AACF;AAGO,IAAM,gBAAN,cAA4B,YAAY;AAAA;AAAA,EAE7C,SAASC,UAAwB;AAC/B,IAAAA,SACG,QAAQ,kBAAkB,EAC1B,YAAY,qDAAqD,EACjE,OAAO,aAAa,+DAA+D,KAAK,EACxF,OAAO,WAAW,8CAA8C,KAAK,EACrE,OAAO,OAAO,aAAqB,SAA2C;AAC7E,YAAM,KAAK;AAAA,QACT,IAAI,UAAU;AAAA,QACd,EAAE,aAAa,KAAK,KAAK,KAAK,OAAO,KAAK,MAAM;AAAA,QAChD,KAAK,aAAaA,QAAO;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACL;AACF;;;ACrFO,IAAM,yBAAN,MAA0F;AAAA;AAAA,EAE/F,MAAM,QACJ,SACA,UACyC;AACzC,UAAM,EAAE,YAAY,IAAI;AAExB,QAAI;AACF,YAAM,UAAU,MAAM,cAAc;AAEpC,UAAI,QAAQ,SAAS,WAAW,GAAG;AACjC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,MAAM,EAAE,aAAa,aAAa,QAAQ;AAAA,UAC1C,SAAS,gBAAgB,WAAW;AAAA,QACtC;AAAA,MACF;AAEA,YAAM,UAAU,CAAC,GAAG,SAAS,WAAW;AACxC,YAAM,eAAe,OAAO;AAE5B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,EAAE,aAAa,aAAa,QAAQ;AAAA,QAC1C,SAAS,UAAU,WAAW;AAAA;AAAA,EAAmD,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,MAC1H;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAMO,IAAM,wBAAN,MAAwF;AAAA;AAAA,EAE7F,MAAM,QACJ,SACA,UACyC;AACzC,UAAM,EAAE,YAAY,IAAI;AAExB,QAAI;AACF,YAAM,UAAU,MAAM,cAAc;AAEpC,UAAI,CAAC,QAAQ,SAAS,WAAW,GAAG;AAClC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,gBAAgB,WAAW;AAAA,QACpC;AAAA,MACF;AAEA,YAAM,UAAU,QAAQ,OAAO,CAAC,MAAM,MAAM,WAAW;AACvD,YAAM,eAAe,OAAO;AAE5B,YAAM,UACJ,QAAQ,SAAS,IACb,YAAY,WAAW;AAAA;AAAA,EAAqD,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,KACnH,YAAY,WAAW;AAAA;AAE7B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,MAAM,EAAE,aAAa,aAAa,QAAQ;AAAA,QAC1C;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAGO,IAAM,uBAAN,cAAmC,YAAY;AAAA;AAAA,EAEpD,SAASC,UAAwB;AAC/B,UAAM,YAAYA,SACf,QAAQ,WAAW,EACnB,YAAY,iDAAiD;AAEhE,cACG,QAAQ,mBAAmB,EAC3B,YAAY,4CAA4C,EACxD,OAAO,OAAO,gBAAwB;AACrC,YAAM,KAAK;AAAA,QACT,IAAI,uBAAuB;AAAA,QAC3B,EAAE,YAAY;AAAA,QACd,KAAK,aAAaA,QAAO;AAAA,MAC3B;AAAA,IACF,CAAC;AAEH,cACG,QAAQ,kBAAkB,EAC1B,YAAY,6CAA6C,EACzD,OAAO,OAAO,gBAAwB;AACrC,YAAM,KAAK;AAAA,QACT,IAAI,sBAAsB;AAAA,QAC1B,EAAE,YAAY;AAAA,QACd,KAAK,aAAaA,QAAO;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACL;AACF;;;ACjIA,OAAOC,UAAQ;AACf,OAAOC,SAAQ;AACf,OAAOC,YAAU;AACjB,SAAS,uBAAuB;AA0BhC,eAAe,yBAAyB,KAAyC;AAC/E,QAAM,QAAQ,aAAa,KAAK,UAAU,CAAC,WAAW,CAAC;AACvD,QAAM,QAAQ,MACX,IAAI,CAAC,MAAM,6BAA6BC,OAAK,SAAS,CAAC,CAAC,CAAC,EACzD,OAAO,CAAC,MAA4B,MAAM,MAAS;AACtD,SAAO,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;AAC3B;AAMA,eAAe,oBAAoB,iBAA0C;AAC3E,MAAI,MAAM;AACV,MAAI;AACF,UAAM,MAAMC,KAAG,SAAS,iBAAiB,MAAM;AAAA,EACjD,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,UAAU,gBAAgB,GAAG;AACnC,QAAM,QAAQ,OAAO,KAAK,OAAO,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG;AACrD,SAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO;AACtD;AAYO,IAAM,gBAAN,MAAwE;AAAA;AAAA,EAE7E,MAAM,QACJ,SACA,SACsC;AACtC,UAAM,EAAE,aAAa,IAAI,IAAI,EAAE,GAAG,SAAS,KAAK,QAAQ,IAAI;AAE5D,QAAI;AACF,UAAI,gBAAgB,WAAW;AAC7B,eAAO,MAAM,KAAK,cAAc,QAAQ,MAAM,GAAG;AAAA,MACnD;AAEA,YAAM,WAAW,MAAM,yBAAyB,GAAG;AACnD,UAAI,SAAS,SAAS,WAAW,GAAG;AAClC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,gBAAgB,WAAW,yCAAyC,WAAW;AAAA,QACxF;AAAA,MACF;AAEA,aAAO,MAAM,KAAK,kBAAkB,aAAa,GAAG;AAAA,IACtD,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,cACZ,MACA,KACsC;AACtC,UAAM,WAAW,MAAM,yBAAyB,GAAG;AAEnD,QAAI,OAAO;AACX,QAAI,CAAC,MAAM;AACT,UAAI,SAAS,WAAW,GAAG;AACzB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO;AAAA,QACT;AAAA,MACF;AAEA,YAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,UAAI;AACF,eAAO,MAAM,GAAG;AAAA,UACd,8BAA8B,SAAS,KAAK,IAAI,CAAC;AAAA,QACnD;AAAA,MACF,UAAE;AACA,WAAG,MAAM;AAAA,MACX;AAAA,IACF;AAEA,QAAI,CAAC,SAAS,SAAS,IAAI,GAAG;AAC5B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,gBAAgB,IAAI,gCAAgC,SAAS,KAAK,IAAI,CAAC;AAAA,MAChF;AAAA,IACF;AAEA,UAAM,OAAO,iBAAiB,MAAM,GAAG;AACvC,UAAM,UAAU,MAAM,oBAAoB,KAAK,WAAW;AAC1D,UAAM,cAAcD,OAAK,QAAQ,KAAK,cAAc;AACpD,UAAMC,KAAG,UAAU,aAAa,SAAS,MAAM;AAE/C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,QACJ,aAAa;AAAA,QACb,cAAc,CAAC,WAAW;AAAA,QAC1B,WAAW;AAAA,QACX,iBAAiB;AAAA,MACnB;AAAA,MACA,SAAS,8BAA8B,IAAI,MAAM,OAAO,KAAK,gBAAgB,OAAO,CAAC,EAAE,MAAM;AAAA,IAC/F;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,aACA,KACsC;AACtC,UAAM,OAAO,iBAAiB,aAAa,GAAG;AAC9C,UAAM,UAAoB,CAAC;AAE3B,UAAMA,KAAG,UAAU,KAAK,aAAa,IAAI,MAAM;AAC/C,YAAQ,KAAK,KAAK,WAAW;AAE7B,gBAAY,iBAAiB,KAAK,KAAK,SAAS;AAChD,YAAQ,KAAK,KAAK,SAAS;AAE3B,UAAM,SAAU,MAAM,WAAW,GAAG,KAAM,EAAE,YAAY;AACxD,UAAM,YAAY,KAAK,EAAE,GAAG,QAAQ,YAAY,CAAC;AAEjD,UAAM,mBAAmBD,OAAK,QAAQ,KAAK,wBAAwB;AACnE,UAAM,iBAAiBA,OAAK,QAAQ,KAAK,YAAY;AACrD,UAAM,cAAc,MAAMC,KACvB,OAAO,gBAAgB,EACvB,KAAK,MAAM,IAAI,EACf,MAAM,MAAM,KAAK;AAEpB,QAAI,aAAa;AACf,YAAM,2BAA2B,SAAS,GAAG;AAAA,IAC/C,OAAO;AACL,YAAM,uBAAuB,MAAMA,KAChC,OAAO,cAAc,EACrB,KAAK,MAAM,IAAI,EACf,MAAM,MAAM,KAAK;AAEpB,UAAI,CAAC,sBAAsB;AACzB,YAAIC,IAAG,SAAS,MAAM,SAAS;AAC7B,gBAAMD,KAAG,SAAS,KAAK,WAAW,cAAc;AAAA,QAClD,OAAO;AACL,gBAAMA,KAAG,QAAQ,KAAK,WAAW,cAAc;AAAA,QACjD;AACA,gBAAQ,KAAK,cAAc;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,QAAQ;AAAA,MACZ,wBAAwB,WAAW;AAAA,MACnC;AAAA,MACA,GAAG,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AAAA,IAChC;AACA,QAAI,aAAa;AACf,YAAM,KAAK,YAAY,cAAc,EAAE;AAAA,IACzC;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM,EAAE,aAAa,cAAc,SAAS,WAAW,MAAM;AAAA,MAC7D,SAAS,MAAM,KAAK,IAAI;AAAA,IAC1B;AAAA,EACF;AACF;AAGO,IAAM,oBAAN,cAAgC,YAAY;AAAA;AAAA,EAEjD,SAASE,UAAwB;AAC/B,IAAAA,SACG,QAAQ,sBAAsB,EAC9B;AAAA,MACC;AAAA,IACF,EACC,OAAO,gBAAgB,8CAA8C,EACrE,OAAO,OAAO,aAAqB,SAA4B;AAC9D,YAAM,KAAK;AAAA,QACT,IAAI,cAAc;AAAA,QAClB,EAAE,aAAa,MAAM,KAAK,KAAK;AAAA,QAC/B,KAAK,aAAaA,QAAO;AAAA,MAC3B;AAAA,IACF,CAAC;AAAA,EACL;AACF;;;AtB9MA,IAAM,WAAWC,eAAc,YAAY,GAAG;AAC9C,IAAM,EAAE,QAAQ,IAAI,SAAS,iBAAiB;AAE9C,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,SAAS,EACd,YAAY,qDAAqD,EACjE,QAAQ,OAAO,EACf,YAAY,aAAa,YAAY,OAAO;AAAA,CAAI,EAChD,OAAO,eAAe,mBAAmB,KAAK;AAEjD,IAAI,gBAAgB,EAAE,SAAS,OAAO;AACtC,IAAI,kBAAkB,EAAE,SAAS,OAAO;AACxC,IAAI,gBAAgB,EAAE,SAAS,OAAO;AACtC,IAAI,kBAAkB,EAAE,SAAS,OAAO;AACxC,IAAI,oBAAoB,EAAE,SAAS,OAAO;AAC1C,IAAI,eAAe,EAAE,SAAS,OAAO;AACrC,IAAI,mBAAmB,EAAE,SAAS,OAAO;AACzC,IAAI,cAAc,EAAE,SAAS,OAAO;AACpC,IAAI,qBAAqB,EAAE,SAAS,OAAO;AAE3C,QAAQ,WAAW,QAAQ,IAAI;","names":["createRequire","fs","path","program","path","require","fs","path","program","fs","path","os","path","fs","path","fs","fs","fs","program","fs","fs","program","fs","path","path","fs","program","fs","os","path","fs","path","fs","path","path","fs","os","program","path","fs","path","fs","path","path","program","fs","path","path","fs","program","program","fs","os","path","path","fs","os","program","createRequire"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envctrl/cli",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -21,7 +21,7 @@
21
21
  "tsup": "^8.5.0",
22
22
  "typescript": "^5.8.0",
23
23
  "vitest": "^3.0.0",
24
- "@envctrl/types": "1.4.0"
24
+ "@envctrl/types": "1.5.0"
25
25
  },
26
26
  "scripts": {
27
27
  "build": "tsup",