@keynv/cli 0.1.0-rc.7 → 0.1.0-rc.9

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
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module';
3
3
  import 'crypto';
4
- import { readFileSync, existsSync, statSync, mkdirSync, writeFileSync, rmSync } from 'fs';
4
+ import { readFileSync, existsSync, statSync, writeFileSync, unlinkSync, mkdirSync, rmSync, readdirSync } from 'fs';
5
5
  import { homedir } from 'os';
6
- import { isAbsolute, resolve, join, dirname } from 'path';
6
+ import { isAbsolute, resolve, join, dirname, basename } from 'path';
7
7
  import { Entry } from '@napi-rs/keyring';
8
8
  import { styleText } from 'util';
9
9
  import j2, { stdin, stdout } from 'process';
@@ -1056,7 +1056,7 @@ var require_lib = __commonJS({
1056
1056
  var VERSION, AGENT;
1057
1057
  var init_version = __esm({
1058
1058
  "src/version.ts"() {
1059
- VERSION = "0.1.0-rc.7" ;
1059
+ VERSION = "0.1.0-rc.9" ;
1060
1060
  AGENT = `keynv-cli/${VERSION}`;
1061
1061
  }
1062
1062
  });
@@ -5716,6 +5716,137 @@ var init_format = __esm({
5716
5716
  "src/ui/format.ts"() {
5717
5717
  }
5718
5718
  });
5719
+ function parseEnvFile(content, filename) {
5720
+ const normalized = content.charCodeAt(0) === 65279 ? content.slice(1) : content;
5721
+ const lines = normalized.split(/\r?\n/);
5722
+ const entries = [];
5723
+ for (let i = 0; i < lines.length; i++) {
5724
+ const raw = lines[i] ?? "";
5725
+ const lineNo = i + 1;
5726
+ const trimmed = raw.trim();
5727
+ if (trimmed.length === 0) continue;
5728
+ if (trimmed.startsWith("#")) continue;
5729
+ let body = trimmed;
5730
+ if (body.startsWith("export ")) {
5731
+ body = body.slice("export ".length).trimStart();
5732
+ }
5733
+ const eq = body.indexOf("=");
5734
+ if (eq <= 0) {
5735
+ throw new EnvFileParseError(filename, lineNo, "expected 'KEY=value'");
5736
+ }
5737
+ const name = body.slice(0, eq).trim();
5738
+ if (!KEY_RE2.test(name)) {
5739
+ throw new EnvFileParseError(
5740
+ filename,
5741
+ lineNo,
5742
+ `invalid key '${name}' (must match /^[A-Za-z_][A-Za-z0-9_]*$/)`
5743
+ );
5744
+ }
5745
+ let valueRaw = body.slice(eq + 1);
5746
+ let value;
5747
+ const valueLeading = valueRaw.replace(/^\s+/, "");
5748
+ const firstCh = valueLeading.charAt(0);
5749
+ if (firstCh === '"' || firstCh === "'") {
5750
+ const close = valueLeading.lastIndexOf(firstCh);
5751
+ if (close === 0) {
5752
+ throw new EnvFileParseError(filename, lineNo, `unclosed ${firstCh} quote`);
5753
+ }
5754
+ const after = valueLeading.slice(close + 1).trim();
5755
+ if (after.length > 0) {
5756
+ throw new EnvFileParseError(
5757
+ filename,
5758
+ lineNo,
5759
+ `unexpected content after closing ${firstCh}`
5760
+ );
5761
+ }
5762
+ value = valueLeading.slice(1, close);
5763
+ } else {
5764
+ value = valueRaw.replace(/\s+$/, "");
5765
+ value = value.replace(/^\s+/, "");
5766
+ }
5767
+ entries.push({
5768
+ name,
5769
+ value,
5770
+ isAlias: parseAlias(value) !== null,
5771
+ line: lineNo
5772
+ });
5773
+ }
5774
+ return entries;
5775
+ }
5776
+ function findEnvFile(startDir) {
5777
+ let dir = resolve(startDir);
5778
+ for (let i = 0; i < 64; i++) {
5779
+ const candidate = join(dir, ENV_FILE_BASENAME);
5780
+ if (existsSync(candidate)) {
5781
+ try {
5782
+ if (statSync(candidate).isFile()) return candidate;
5783
+ } catch {
5784
+ }
5785
+ }
5786
+ const parent = dirname(dir);
5787
+ if (parent === dir) return null;
5788
+ dir = parent;
5789
+ }
5790
+ return null;
5791
+ }
5792
+ function loadEnvFile(opts) {
5793
+ if (opts.disabled) return null;
5794
+ const pickExplicit = opts.explicitPath ?? opts.envVarOverride;
5795
+ let path = null;
5796
+ if (pickExplicit !== void 0) {
5797
+ path = isAbsolute(pickExplicit) ? pickExplicit : resolve(opts.cwd, pickExplicit);
5798
+ if (!existsSync(path)) throw new EnvFileNotFoundError(path);
5799
+ } else {
5800
+ path = findEnvFile(opts.cwd);
5801
+ }
5802
+ if (path === null) return null;
5803
+ const stat = statSync(path);
5804
+ if (stat.size > MAX_FILE_BYTES) {
5805
+ throw new EnvFileTooLargeError(path, stat.size);
5806
+ }
5807
+ const content = readFileSync(path, "utf8");
5808
+ const entries = parseEnvFile(content, path);
5809
+ return { path, entries };
5810
+ }
5811
+ var MAX_FILE_BYTES, KEY_RE2, ENV_FILE_BASENAME, EnvFileParseError, EnvFileNotFoundError, EnvFileTooLargeError;
5812
+ var init_envFile = __esm({
5813
+ "src/exec/envFile.ts"() {
5814
+ init_dist();
5815
+ MAX_FILE_BYTES = 1e6;
5816
+ KEY_RE2 = /^[A-Za-z_][A-Za-z0-9_]*$/;
5817
+ ENV_FILE_BASENAME = ".keynv.env";
5818
+ EnvFileParseError = class extends Error {
5819
+ constructor(file, line, reason) {
5820
+ super(`${file}:${line}: ${reason}`);
5821
+ this.file = file;
5822
+ this.line = line;
5823
+ this.reason = reason;
5824
+ this.name = "EnvFileParseError";
5825
+ }
5826
+ file;
5827
+ line;
5828
+ reason;
5829
+ };
5830
+ EnvFileNotFoundError = class extends Error {
5831
+ constructor(path) {
5832
+ super(`env file not found: ${path}`);
5833
+ this.path = path;
5834
+ this.name = "EnvFileNotFoundError";
5835
+ }
5836
+ path;
5837
+ };
5838
+ EnvFileTooLargeError = class extends Error {
5839
+ constructor(path, bytes) {
5840
+ super(`env file ${path} is ${bytes} bytes (max ${MAX_FILE_BYTES})`);
5841
+ this.path = path;
5842
+ this.bytes = bytes;
5843
+ this.name = "EnvFileTooLargeError";
5844
+ }
5845
+ path;
5846
+ bytes;
5847
+ };
5848
+ }
5849
+ });
5719
5850
 
5720
5851
  // src/ui/helpers/tty.ts
5721
5852
  var tty_exports = {};
@@ -6095,7 +6226,7 @@ var require_src = __commonJS({
6095
6226
  var ESC2 = "\x1B";
6096
6227
  var CSI2 = `${ESC2}[`;
6097
6228
  var beep = "\x07";
6098
- var cursor2 = {
6229
+ var cursor = {
6099
6230
  to(x, y) {
6100
6231
  if (!y) return `${CSI2}${x + 1}G`;
6101
6232
  return `${CSI2}${y + 1};${x + 1}H`;
@@ -6134,13 +6265,13 @@ var require_src = __commonJS({
6134
6265
  lines(count) {
6135
6266
  let clear = "";
6136
6267
  for (let i = 0; i < count; i++)
6137
- clear += this.line + (i < count - 1 ? cursor2.up() : "");
6268
+ clear += this.line + (i < count - 1 ? cursor.up() : "");
6138
6269
  if (count)
6139
- clear += cursor2.left;
6270
+ clear += cursor.left;
6140
6271
  return clear;
6141
6272
  }
6142
6273
  };
6143
- module.exports = { cursor: cursor2, scroll, erase, beep };
6274
+ module.exports = { cursor, scroll, erase, beep };
6144
6275
  }
6145
6276
  });
6146
6277
  function d(r, t, s) {
@@ -6884,6 +7015,502 @@ ${c2}
6884
7015
  } }).prompt();
6885
7016
  }
6886
7017
  });
7018
+ function findProjectRoot(startDir) {
7019
+ let dir = resolve(startDir);
7020
+ for (let i = 0; i < 64; i++) {
7021
+ for (const marker of PROJECT_MARKERS) {
7022
+ const candidate = join(dir, marker);
7023
+ if (existsSync(candidate)) {
7024
+ return buildRoot(dir, marker);
7025
+ }
7026
+ }
7027
+ if (existsSync(join(dir, GIT_MARKER))) {
7028
+ return buildRoot(dir, GIT_MARKER);
7029
+ }
7030
+ const parent = dirname(dir);
7031
+ if (parent === dir) return null;
7032
+ dir = parent;
7033
+ }
7034
+ return null;
7035
+ }
7036
+ function buildRoot(dir, marker) {
7037
+ let suggestedName = basename(dir);
7038
+ let scripts = null;
7039
+ let invalid = false;
7040
+ if (marker === "package.json" || existsSync(join(dir, "package.json"))) {
7041
+ try {
7042
+ const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
7043
+ if (typeof pkg.name === "string" && pkg.name.length > 0) {
7044
+ suggestedName = pkg.name.replace(/^@[^/]+\//, "");
7045
+ }
7046
+ if (pkg.scripts && typeof pkg.scripts === "object") {
7047
+ scripts = Object.fromEntries(
7048
+ Object.entries(pkg.scripts).filter(
7049
+ ([, v2]) => typeof v2 === "string"
7050
+ )
7051
+ );
7052
+ }
7053
+ } catch {
7054
+ invalid = true;
7055
+ }
7056
+ }
7057
+ return { path: dir, suggestedName, marker, packageJsonScripts: scripts, packageJsonInvalid: invalid };
7058
+ }
7059
+ function findEnvFiles(rootDir) {
7060
+ let entries;
7061
+ try {
7062
+ entries = readdirSync(rootDir);
7063
+ } catch {
7064
+ return [];
7065
+ }
7066
+ const hits = [];
7067
+ for (const name of entries) {
7068
+ if (!ENV_GLOB.test(name)) continue;
7069
+ if (ENV_EXAMPLE.test(name)) continue;
7070
+ if (name === KEYNV_ENV_BASENAME) continue;
7071
+ const full = join(rootDir, name);
7072
+ try {
7073
+ if (!statSync(full).isFile()) continue;
7074
+ } catch {
7075
+ continue;
7076
+ }
7077
+ const suffixMatch = name.match(/^\.env\.(.+)$/);
7078
+ const suffix = suffixMatch ? suffixMatch[1] : null;
7079
+ hits.push({ path: full, name, suffix, suggestedEnv: suggestedEnvForSuffix(suffix) });
7080
+ }
7081
+ hits.sort((a, b2) => {
7082
+ if (a.suffix === null) return -1;
7083
+ if (b2.suffix === null) return 1;
7084
+ return a.name.localeCompare(b2.name);
7085
+ });
7086
+ return hits;
7087
+ }
7088
+ function suggestedEnvForSuffix(suffix) {
7089
+ if (suffix === null) return "dev";
7090
+ switch (suffix) {
7091
+ case "local":
7092
+ case "development":
7093
+ case "dev":
7094
+ return "dev";
7095
+ case "production":
7096
+ case "prod":
7097
+ return "prod";
7098
+ case "staging":
7099
+ case "stage":
7100
+ return "staging";
7101
+ case "test":
7102
+ return "test";
7103
+ case "preview":
7104
+ return "preview";
7105
+ default:
7106
+ return suffix;
7107
+ }
7108
+ }
7109
+ function hasExistingKeynvEnv(rootDir) {
7110
+ return existsSync(join(rootDir, KEYNV_ENV_BASENAME));
7111
+ }
7112
+ var PROJECT_MARKERS, GIT_MARKER, ENV_GLOB, ENV_EXAMPLE, KEYNV_ENV_BASENAME;
7113
+ var init_detect = __esm({
7114
+ "src/init/detect.ts"() {
7115
+ PROJECT_MARKERS = [
7116
+ "package.json",
7117
+ "pyproject.toml",
7118
+ "Cargo.toml",
7119
+ "go.mod",
7120
+ "pnpm-workspace.yaml",
7121
+ "deno.json",
7122
+ "deno.jsonc",
7123
+ "requirements.txt"
7124
+ ];
7125
+ GIT_MARKER = ".git";
7126
+ ENV_GLOB = /^\.env(\.[A-Za-z0-9_-]+)?$/;
7127
+ ENV_EXAMPLE = /^\.env\.(example|sample|template)$/;
7128
+ KEYNV_ENV_BASENAME = ".keynv.env";
7129
+ }
7130
+ });
7131
+ function aiContextBody() {
7132
+ return `## keynv (secrets)
7133
+
7134
+ This project uses [keynv](https://keynv.dev) for secrets. There is a \`.keynv.env\` file at the project root containing **alias references** like \`OPENAI_API_KEY=@projectname.dev.openai-key\` \u2014 these are NOT real values, they are references to secrets stored in the keynv vault.
7135
+
7136
+ ### Mental model
7137
+
7138
+ - **\`.keynv.env\`** \u2014 checked into git, contains aliases. Safe to read, edit, commit.
7139
+ - **Vault** \u2014 holds the real values. The \`keynv\` CLI reads it on demand.
7140
+ - **\`keynv exec -- <command>\`** \u2014 forks the command in a subprocess where the real values are injected into env vars. The parent process (where you, the AI agent, run) NEVER sees the real values.
7141
+ - **Redactor** \u2014 pipes subprocess stdout/stderr through a masker before they reach this terminal. Even if a script accidentally echoes a secret, you see \`<REDACTED:...>\` here.
7142
+
7143
+ ### What you should do
7144
+
7145
+ When the user asks about secrets or env vars, follow this decision tree:
7146
+
7147
+ | User intent | Run / suggest |
7148
+ |---|---|
7149
+ | "Add a new API key" / "set up a secret" | \`keynv secret create\` (interactive prompt picks project + env + key) |
7150
+ | "I have a \`.env\`, migrate it" | \`keynv init\` (you're seeing this file because that already happened) |
7151
+ | "Run the app / dev server / tests" | \`keynv exec -- <their existing command>\` (auto-loads \`.keynv.env\`) |
7152
+ | "Show me the value of X" | \`keynv secret get @alias\` \u2014 but copy to clipboard, do NOT print the value into chat / terminal |
7153
+ | "Rotate this key" | \`keynv secret rotate @alias\` |
7154
+ | "Add a new env var to the project" | Edit \`.keynv.env\` and add \`NAME=@project.env.key\` (after creating the secret with \`keynv secret create\`) |
7155
+ | "Who has access?" | \`keynv member list <project>\` |
7156
+
7157
+ ### Hard rules \u2014 do not violate
7158
+
7159
+ 1. **Never print resolved secret values** to the chat, terminal, log, or any file. The user's editor / scrollback / chat history is an attack surface.
7160
+ 2. **Never write a \`.env\` file** (or any file) containing real secret values. The whole point of keynv is that those don't exist on disk.
7161
+ 3. **Never edit \`.keynv.env\` to substitute resolved values for aliases.** The file should only ever contain \`@project.env.key\` references and plain non-secret literals.
7162
+ 4. **Use \`keynv exec --\` to run commands that need env vars.** Don't try to load \`.keynv.env\` yourself by parsing it manually; the wrapper handles resolution + redaction + subprocess isolation.
7163
+ 5. **If a tool fails with "blocked by keynv-guard" or similar**, do NOT try to work around it. Tell the user \u2014 that's a sign of a misconfiguration, not an obstacle to bypass.
7164
+ 6. **Treat the alias literal (\`@project.env.key\`) as the canonical reference**, never the resolved value. When you write code, configs, or commands that need a secret, write the alias.
7165
+
7166
+ ### Quick reference
7167
+
7168
+ \`\`\`bash
7169
+ keynv # interactive TUI menu (pick projects, secrets, members)
7170
+ keynv exec -- <cmd> # run cmd with .keynv.env loaded
7171
+ keynv secret create # walk through creating a new secret
7172
+ keynv secret list <project> # list aliases (no values)
7173
+ keynv whoami # who am I logged in as
7174
+ keynv --help # full command list
7175
+ \`\`\`
7176
+
7177
+ If \`.keynv.env\` is missing or empty, the user probably hasn't run \`keynv init\` yet \u2014 suggest they do so before they paste a secret into a \`.env\`.`;
7178
+ }
7179
+ function renderKeynvBlock() {
7180
+ return `${KEYNV_BLOCK_START}
7181
+ ${aiContextBody()}
7182
+ ${KEYNV_BLOCK_END}`;
7183
+ }
7184
+ function writeAiContext(rootPath) {
7185
+ const path = join(rootPath, AGENTS_FILE_BASENAME);
7186
+ const block = renderKeynvBlock();
7187
+ if (!existsSync(path)) {
7188
+ const initial = `# Agent guidance for this project
7189
+
7190
+ ${block}
7191
+ `;
7192
+ writeFileSync(path, initial);
7193
+ return "created";
7194
+ }
7195
+ const existing = readFileSync(path, "utf8");
7196
+ const startIdx = existing.indexOf(KEYNV_BLOCK_START);
7197
+ const endIdx = existing.indexOf(KEYNV_BLOCK_END);
7198
+ if (startIdx >= 0 && endIdx > startIdx) {
7199
+ const before = existing.slice(0, startIdx);
7200
+ const after = existing.slice(endIdx + KEYNV_BLOCK_END.length);
7201
+ const next = `${before}${block}${after}`;
7202
+ if (next === existing) return "unchanged";
7203
+ writeFileSync(path, next);
7204
+ return "updated";
7205
+ }
7206
+ const sep = existing.length === 0 ? "" : existing.endsWith("\n\n") ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
7207
+ const trailingNewline = existing.endsWith("\n") ? "" : "\n";
7208
+ writeFileSync(path, `${existing}${trailingNewline}${sep}${block}
7209
+ `);
7210
+ return "appended";
7211
+ }
7212
+ var AGENTS_FILE_BASENAME, KEYNV_BLOCK_START, KEYNV_BLOCK_END;
7213
+ var init_aiContext = __esm({
7214
+ "src/init/aiContext.ts"() {
7215
+ AGENTS_FILE_BASENAME = "AGENTS.md";
7216
+ KEYNV_BLOCK_START = "<!-- keynv:start -- generated by `keynv init`; safe to leave intact, will be refreshed on re-run -->";
7217
+ KEYNV_BLOCK_END = "<!-- keynv:end -->";
7218
+ }
7219
+ });
7220
+
7221
+ // src/init/heuristics.ts
7222
+ function shannonEntropyBits(s) {
7223
+ if (s.length === 0) return 0;
7224
+ const counts = /* @__PURE__ */ new Map();
7225
+ for (const ch of s) counts.set(ch, (counts.get(ch) ?? 0) + 1);
7226
+ let h2 = 0;
7227
+ for (const c2 of counts.values()) {
7228
+ const p2 = c2 / s.length;
7229
+ h2 -= p2 * Math.log2(p2);
7230
+ }
7231
+ return h2;
7232
+ }
7233
+ function nameMatchesLiteralPrefix(name) {
7234
+ const upper = name.toUpperCase();
7235
+ return NAME_LITERAL_PREFIX.some((p2) => upper.startsWith(p2));
7236
+ }
7237
+ function nameMatchesSecretSuffix(name) {
7238
+ const upper = name.toUpperCase();
7239
+ for (const { suffix, hint } of NAME_SECRET_SUFFIXES) {
7240
+ if (upper.endsWith(suffix) || upper.endsWith(`_${suffix}`)) {
7241
+ return { matched: true, hint };
7242
+ }
7243
+ }
7244
+ return { matched: false, hint: "" };
7245
+ }
7246
+ function classifyEntry(name, value) {
7247
+ const upper = name.toUpperCase();
7248
+ if (NAME_LITERAL_EXACT.has(upper)) {
7249
+ return { verdict: "literal", hint: "common config var" };
7250
+ }
7251
+ if (nameMatchesLiteralPrefix(name)) {
7252
+ return { verdict: "literal", hint: "public env (build-time bundled)" };
7253
+ }
7254
+ if (value.length === 0) {
7255
+ return { verdict: "literal", hint: "empty" };
7256
+ }
7257
+ for (const { re, hint } of VALUE_PATTERNS) {
7258
+ if (re.test(value)) return { verdict: "secret", hint };
7259
+ }
7260
+ const suffix = nameMatchesSecretSuffix(name);
7261
+ if (suffix.matched) {
7262
+ return { verdict: "secret", hint: suffix.hint };
7263
+ }
7264
+ if (NAME_DB_URL.test(name)) {
7265
+ return { verdict: "secret", hint: "database URL" };
7266
+ }
7267
+ if (value.length >= 32) {
7268
+ const bits = shannonEntropyBits(value);
7269
+ if (bits >= 3.5) {
7270
+ return { verdict: "secret", hint: `${value.length}-char random-looking string` };
7271
+ }
7272
+ }
7273
+ return { verdict: "ambiguous", hint: "" };
7274
+ }
7275
+ function previewValue(value, max = 40) {
7276
+ if (value.length === 0) return "(empty)";
7277
+ if (value.length <= max) return value;
7278
+ return `${value.slice(0, max - 1)}\u2026`;
7279
+ }
7280
+ var NAME_LITERAL_EXACT, NAME_LITERAL_PREFIX, NAME_SECRET_SUFFIXES, NAME_DB_URL, VALUE_PATTERNS;
7281
+ var init_heuristics = __esm({
7282
+ "src/init/heuristics.ts"() {
7283
+ NAME_LITERAL_EXACT = /* @__PURE__ */ new Set([
7284
+ "NODE_ENV",
7285
+ "PORT",
7286
+ "HOST",
7287
+ "HOSTNAME",
7288
+ "DEBUG",
7289
+ "LOG_LEVEL",
7290
+ "LOGLEVEL",
7291
+ "TZ",
7292
+ "LANG",
7293
+ "LC_ALL",
7294
+ "PATH",
7295
+ "HOME",
7296
+ "USER",
7297
+ "SHELL",
7298
+ "PWD",
7299
+ "CI",
7300
+ "NODE_OPTIONS",
7301
+ "NPM_CONFIG_LOGLEVEL",
7302
+ "TS_NODE_PROJECT"
7303
+ ]);
7304
+ NAME_LITERAL_PREFIX = ["NEXT_PUBLIC_", "VITE_", "REACT_APP_", "PUBLIC_", "EXPO_PUBLIC_"];
7305
+ NAME_SECRET_SUFFIXES = [
7306
+ { suffix: "PRIVATE_KEY", hint: "private key" },
7307
+ { suffix: "API_KEY", hint: "API key" },
7308
+ { suffix: "ACCESS_KEY", hint: "access key" },
7309
+ { suffix: "SECRET_KEY", hint: "secret key" },
7310
+ { suffix: "SECRET", hint: "secret" },
7311
+ { suffix: "PASSWORD", hint: "password" },
7312
+ { suffix: "PASSPHRASE", hint: "passphrase" },
7313
+ { suffix: "TOKEN", hint: "token" },
7314
+ { suffix: "KEY", hint: "key" },
7315
+ { suffix: "CREDENTIALS", hint: "credentials" },
7316
+ { suffix: "AUTH", hint: "auth" },
7317
+ { suffix: "DSN", hint: "connection string" }
7318
+ ];
7319
+ NAME_DB_URL = /^(DATABASE|DB|POSTGRES|MYSQL|MONGO|REDIS)_URL$/i;
7320
+ VALUE_PATTERNS = [
7321
+ { re: /^sk-proj-/, hint: "OpenAI project key" },
7322
+ { re: /^sk-[A-Za-z0-9]{20,}/, hint: "OpenAI key" },
7323
+ { re: /^sk_live_/, hint: "Stripe live key" },
7324
+ { re: /^sk_test_/, hint: "Stripe test key" },
7325
+ { re: /^pk_live_/, hint: "Stripe publishable (often public, double-check)" },
7326
+ { re: /^xoxb-/, hint: "Slack bot token" },
7327
+ { re: /^xoxp-/, hint: "Slack user token" },
7328
+ { re: /^ghp_[A-Za-z0-9]{30,}/, hint: "GitHub personal access token" },
7329
+ { re: /^github_pat_/, hint: "GitHub fine-grained PAT" },
7330
+ { re: /^gho_/, hint: "GitHub OAuth token" },
7331
+ { re: /^AKIA[0-9A-Z]{16}$/, hint: "AWS access key id" },
7332
+ { re: /^ASIA[0-9A-Z]{16}$/, hint: "AWS temporary key id" },
7333
+ { re: /^AIza[0-9A-Za-z_-]{35}$/, hint: "Google API key" },
7334
+ { re: /^ya29\./, hint: "Google OAuth access token" },
7335
+ { re: /^eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/, hint: "JWT" },
7336
+ { re: /^-----BEGIN [A-Z ]+PRIVATE KEY-----/, hint: "PEM private key" },
7337
+ { re: /^([a-z]+):\/\/[^@]+:[^@]+@/i, hint: "connection string with credentials" }
7338
+ ];
7339
+ }
7340
+ });
7341
+
7342
+ // src/init/scriptWrap.ts
7343
+ function analyzeScript(name, command) {
7344
+ const trimmed = command.trim();
7345
+ if (trimmed.startsWith("keynv ") || trimmed.startsWith("keynv ")) {
7346
+ return {
7347
+ name,
7348
+ original: command,
7349
+ wrapped: command,
7350
+ verdict: "skip-already-wrapped",
7351
+ hint: "already wrapped"
7352
+ };
7353
+ }
7354
+ const firstWord = extractFirstCommandWord(trimmed);
7355
+ if (firstWord === null) {
7356
+ return {
7357
+ name,
7358
+ original: command,
7359
+ wrapped: `${KEYNV_PREFIX} ${command}`,
7360
+ verdict: "skip-unknown",
7361
+ hint: "cannot parse"
7362
+ };
7363
+ }
7364
+ const wrapped = `${KEYNV_PREFIX} ${command}`;
7365
+ if (ENV_AWARE_TOOLS.has(firstWord)) {
7366
+ return { name, original: command, wrapped, verdict: "wrap", hint: `${firstWord} reads env` };
7367
+ }
7368
+ if (NON_ENV_TOOLS.has(firstWord)) {
7369
+ return {
7370
+ name,
7371
+ original: command,
7372
+ wrapped,
7373
+ verdict: "skip-no-env-tool",
7374
+ hint: `${firstWord} doesn't need env`
7375
+ };
7376
+ }
7377
+ return {
7378
+ name,
7379
+ original: command,
7380
+ wrapped,
7381
+ verdict: "skip-unknown",
7382
+ hint: `unrecognized: ${firstWord}`
7383
+ };
7384
+ }
7385
+ function extractFirstCommandWord(s) {
7386
+ const tokens = s.split(/\s+/).filter((t) => t.length > 0);
7387
+ let i = 0;
7388
+ while (i < tokens.length) {
7389
+ const t = tokens[i];
7390
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(t)) {
7391
+ i++;
7392
+ continue;
7393
+ }
7394
+ if (t === "cross-env") {
7395
+ i++;
7396
+ while (i < tokens.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[i])) i++;
7397
+ continue;
7398
+ }
7399
+ if (t === "dotenv") {
7400
+ const dashDash = tokens.indexOf("--", i + 1);
7401
+ if (dashDash >= 0) {
7402
+ i = dashDash + 1;
7403
+ continue;
7404
+ }
7405
+ i++;
7406
+ while (i < tokens.length && tokens[i].startsWith("-")) i++;
7407
+ continue;
7408
+ }
7409
+ if (t === "sh" || t === "bash" || t === "zsh") {
7410
+ return null;
7411
+ }
7412
+ return t.replace(/^.*\//, "");
7413
+ }
7414
+ return null;
7415
+ }
7416
+ function planScriptWrap(scripts) {
7417
+ const recommended = [];
7418
+ const skipped = [];
7419
+ const unknown = [];
7420
+ for (const [name, command] of Object.entries(scripts)) {
7421
+ const analysis = analyzeScript(name, command);
7422
+ switch (analysis.verdict) {
7423
+ case "wrap":
7424
+ recommended.push(analysis);
7425
+ break;
7426
+ case "skip-unknown":
7427
+ unknown.push(analysis);
7428
+ break;
7429
+ default:
7430
+ skipped.push(analysis);
7431
+ }
7432
+ }
7433
+ return { recommended, skipped, unknown };
7434
+ }
7435
+ function applyWraps(original, selectedScriptNames) {
7436
+ const out = { ...original };
7437
+ const selection = new Set(selectedScriptNames);
7438
+ for (const [name, command] of Object.entries(original)) {
7439
+ if (!selection.has(name)) continue;
7440
+ const trimmed = command.trim();
7441
+ if (trimmed.startsWith("keynv ") || trimmed.startsWith("keynv ")) continue;
7442
+ out[name] = `${KEYNV_PREFIX} ${command}`;
7443
+ }
7444
+ return out;
7445
+ }
7446
+ var KEYNV_PREFIX, ENV_AWARE_TOOLS, NON_ENV_TOOLS;
7447
+ var init_scriptWrap = __esm({
7448
+ "src/init/scriptWrap.ts"() {
7449
+ KEYNV_PREFIX = "keynv exec --";
7450
+ ENV_AWARE_TOOLS = /* @__PURE__ */ new Set([
7451
+ "node",
7452
+ "tsx",
7453
+ "ts-node",
7454
+ "bun",
7455
+ "deno",
7456
+ "next",
7457
+ "nuxt",
7458
+ "vite",
7459
+ "remix",
7460
+ "astro",
7461
+ "gatsby",
7462
+ "nest",
7463
+ "webpack",
7464
+ "rollup",
7465
+ "parcel",
7466
+ "vitest",
7467
+ "jest",
7468
+ "mocha",
7469
+ "cypress",
7470
+ "playwright",
7471
+ "storybook",
7472
+ "tsc-watch",
7473
+ "pm2",
7474
+ "forever",
7475
+ "nodemon",
7476
+ "concurrently",
7477
+ "pytest",
7478
+ "python",
7479
+ "python3",
7480
+ "gunicorn",
7481
+ "uvicorn",
7482
+ "celery",
7483
+ "flask",
7484
+ "django-admin",
7485
+ "manage.py",
7486
+ "rails",
7487
+ "rake",
7488
+ "go",
7489
+ "cargo",
7490
+ "air"
7491
+ ]);
7492
+ NON_ENV_TOOLS = /* @__PURE__ */ new Set([
7493
+ "eslint",
7494
+ "biome",
7495
+ "prettier",
7496
+ "tsc",
7497
+ "tslint",
7498
+ "stylelint",
7499
+ "rm",
7500
+ "cp",
7501
+ "mv",
7502
+ "mkdir",
7503
+ "echo",
7504
+ "cat",
7505
+ "find",
7506
+ "grep",
7507
+ "sort",
7508
+ "uniq",
7509
+ "sed",
7510
+ "awk"
7511
+ ]);
7512
+ }
7513
+ });
6887
7514
 
6888
7515
  // src/ui/helpers/cancel.ts
6889
7516
  function unwrap(value) {
@@ -6925,6 +7552,428 @@ var init_pickProject = __esm({
6925
7552
  }
6926
7553
  });
6927
7554
 
7555
+ // src/ui/flows/init.ts
7556
+ var init_exports = {};
7557
+ __export(init_exports, {
7558
+ UserCancelled: () => UserCancelled,
7559
+ runInitFlow: () => runInitFlow
7560
+ });
7561
+ async function runInitFlow(client, opts) {
7562
+ ge("keynv init");
7563
+ const root = findProjectRoot(opts.cwd);
7564
+ if (root === null) {
7565
+ me(
7566
+ "Couldn't find a project root (no package.json, pyproject.toml, Cargo.toml, go.mod, or .git anywhere up the tree). Run `keynv init` inside a project directory."
7567
+ );
7568
+ return { exitCode: 1 };
7569
+ }
7570
+ if (root.packageJsonInvalid) {
7571
+ R2.warn(`package.json at ${root.path} is not valid JSON \u2014 script wrapping will be skipped.`);
7572
+ }
7573
+ const envFiles = findEnvFiles(root.path);
7574
+ if (envFiles.length === 0 && !hasExistingKeynvEnv(root.path)) {
7575
+ R2.info(
7576
+ `No .env files found in ${root.path}. There's nothing to migrate yet \u2014 create a .keynv.env by hand or run \`keynv exec\` once you have one.`
7577
+ );
7578
+ ye("Nothing to do.");
7579
+ return { exitCode: 0 };
7580
+ }
7581
+ const intoExisting = hasExistingKeynvEnv(root.path);
7582
+ Se(
7583
+ [
7584
+ `Project root: ${root.path}`,
7585
+ `Marker: ${root.marker}`,
7586
+ envFiles.length > 0 ? `Found env files: ${envFiles.map((f) => f.name).join(", ")}` : "Found env files: (none)",
7587
+ intoExisting ? "Existing .keynv.env detected \u2014 will merge new entries in." : ""
7588
+ ].filter(Boolean).join("\n"),
7589
+ "Detected"
7590
+ );
7591
+ const merged = mergeEnvFiles(envFiles);
7592
+ if (merged.length === 0) {
7593
+ R2.info("All env files were empty (only comments/blanks). Nothing to upload.");
7594
+ ye("Done.");
7595
+ return { exitCode: 0 };
7596
+ }
7597
+ const projectChoice = await pickOrCreateProject(client, root.suggestedName);
7598
+ if (projectChoice === null) {
7599
+ me("No project selected.");
7600
+ return { exitCode: 130 };
7601
+ }
7602
+ const envName = await pickEnvForUpload(client, projectChoice, envFiles);
7603
+ if (envName === null) {
7604
+ me("No environment selected.");
7605
+ return { exitCode: 130 };
7606
+ }
7607
+ const choices = merged.map((e2) => {
7608
+ const verdict = classifyEntry(e2.name, e2.value);
7609
+ const hint = verdict.hint || (e2.isAlias ? "looks like an alias literal" : "no signal");
7610
+ const preview2 = e2.isAlias ? e2.value : previewValue(e2.value, 32);
7611
+ return {
7612
+ name: e2.name,
7613
+ value: e2.value,
7614
+ isAlias: e2.isAlias,
7615
+ verdict: verdict.verdict,
7616
+ label: `${e2.name} ${preview2}`,
7617
+ hint,
7618
+ sourceLine: e2.sourceLine,
7619
+ source: e2.source
7620
+ };
7621
+ });
7622
+ const initialSecretSelection = choices.filter((c2) => c2.verdict === "secret" && !c2.isAlias).map((c2) => c2.name);
7623
+ const selectedSecretNames = unwrap(
7624
+ await ve({
7625
+ message: "Mark which keys are secrets (vault-uploaded). Unchecked keys stay as literals.",
7626
+ options: choices.map((c2) => ({
7627
+ value: c2.name,
7628
+ label: c2.label,
7629
+ hint: c2.isAlias ? `${c2.hint} \u2014 already aliased; will pass through` : c2.hint
7630
+ })),
7631
+ initialValues: initialSecretSelection,
7632
+ required: false
7633
+ })
7634
+ );
7635
+ const selected = new Set(selectedSecretNames);
7636
+ let scriptWrapSelection = [];
7637
+ let scriptPlan = root.packageJsonScripts ? planScriptWrap(root.packageJsonScripts) : null;
7638
+ if (!opts.noScripts && scriptPlan && scriptPlan.recommended.length > 0) {
7639
+ const wrapAnswer = unwrap(
7640
+ await ve({
7641
+ message: "Wrap package.json scripts with `keynv exec`? (recommended)",
7642
+ options: [
7643
+ ...scriptPlan.recommended.map((a) => ({
7644
+ value: a.name,
7645
+ label: `${a.name} \u2192 ${a.wrapped}`,
7646
+ hint: a.hint
7647
+ })),
7648
+ ...scriptPlan.unknown.map((a) => ({
7649
+ value: a.name,
7650
+ label: `${a.name} \u2192 ${a.wrapped}`,
7651
+ hint: `unknown tool \u2014 opt in if you know it reads env`
7652
+ }))
7653
+ ],
7654
+ initialValues: scriptPlan.recommended.map((a) => a.name),
7655
+ required: false
7656
+ })
7657
+ );
7658
+ scriptWrapSelection = wrapAnswer;
7659
+ } else if (opts.noScripts) {
7660
+ scriptPlan = null;
7661
+ }
7662
+ const envFileFateRaw = unwrap(
7663
+ await Ee({
7664
+ message: "After upload, what about the original .env files?",
7665
+ options: [
7666
+ { value: "delete", label: "Delete (recommended \u2014 eliminates the leak vector)" },
7667
+ { value: "gitignore", label: "Keep but make sure .gitignore covers them" }
7668
+ ],
7669
+ initialValue: "delete"
7670
+ })
7671
+ );
7672
+ const planSummary = [
7673
+ `Project: ${projectChoice.name}${projectChoice.created ? " (will be created)" : ""}`,
7674
+ `Environment: ${envName}`,
7675
+ `Secrets to vault: ${selected.size}`,
7676
+ `Literals in file: ${merged.length - selected.size}`,
7677
+ `Script wraps: ${scriptWrapSelection.length}`,
7678
+ `Original .env: ${envFileFateRaw === "delete" ? "delete" : "keep + gitignore"}`,
7679
+ opts.dryRun ? "Dry-run: no changes will be made." : ""
7680
+ ].filter(Boolean).join("\n");
7681
+ Se(planSummary, "About to apply");
7682
+ const proceed = unwrap(await ue({ message: "Proceed?", initialValue: true }));
7683
+ if (!proceed) {
7684
+ me("Aborted.");
7685
+ return { exitCode: 130 };
7686
+ }
7687
+ if (opts.dryRun) {
7688
+ ye("Dry-run complete \u2014 no changes were made.");
7689
+ return { exitCode: 0 };
7690
+ }
7691
+ let projectId2;
7692
+ if (projectChoice.created) {
7693
+ const s = ft();
7694
+ s.start(`Creating project "${projectChoice.name}"`);
7695
+ try {
7696
+ const created = await client.request("/v1/projects", {
7697
+ method: "POST",
7698
+ body: {
7699
+ name: projectChoice.name,
7700
+ environments: [{ name: envName, tier: "non-production", require_approval: false }]
7701
+ }
7702
+ });
7703
+ projectId2 = created.id;
7704
+ s.stop(`Created project ${created.name}`);
7705
+ } catch (err) {
7706
+ s.error(`Failed to create project: ${err instanceof Error ? err.message : String(err)}`);
7707
+ return { exitCode: 1 };
7708
+ }
7709
+ } else {
7710
+ projectId2 = projectChoice.id;
7711
+ }
7712
+ const uploaded = [];
7713
+ const failed = [];
7714
+ if (selected.size > 0) {
7715
+ const s = ft();
7716
+ s.start(`Uploading ${selected.size} secrets`);
7717
+ let i = 0;
7718
+ for (const entry2 of merged) {
7719
+ if (!selected.has(entry2.name)) continue;
7720
+ i++;
7721
+ s.message(`Uploading (${i}/${selected.size}) ${entry2.name}`);
7722
+ const aliasKey = entry2.name.toLowerCase().replace(/_/g, "-");
7723
+ try {
7724
+ await client.request(`/v1/projects/${projectId2}/secrets`, {
7725
+ method: "POST",
7726
+ body: { env: envName, key: aliasKey, value: entry2.value }
7727
+ });
7728
+ const alias2 = buildAlias({ project: projectChoice.name, environment: envName, key: aliasKey });
7729
+ if (alias2 === null) {
7730
+ failed.push({
7731
+ name: entry2.name,
7732
+ reason: `produced an invalid alias for project=${projectChoice.name} env=${envName} key=${aliasKey}`
7733
+ });
7734
+ } else {
7735
+ uploaded.push({ name: entry2.name, aliasLiteral: alias2.literal });
7736
+ }
7737
+ } catch (err) {
7738
+ failed.push({ name: entry2.name, reason: err instanceof Error ? err.message : String(err) });
7739
+ }
7740
+ }
7741
+ if (failed.length === 0) {
7742
+ s.stop(`Uploaded ${uploaded.length} secrets`);
7743
+ } else {
7744
+ s.error(`${uploaded.length}/${selected.size} uploaded; ${failed.length} failed`);
7745
+ for (const f of failed) R2.warn(` ${f.name}: ${f.reason}`);
7746
+ }
7747
+ }
7748
+ const literals = merged.filter((e2) => !selected.has(e2.name));
7749
+ const successUploads = new Map(uploaded.map((u) => [u.name, u.aliasLiteral]));
7750
+ const keynvEnvPath = join(root.path, ".keynv.env");
7751
+ let writtenLines;
7752
+ try {
7753
+ writtenLines = composeKeynvEnv({
7754
+ uploadedAliases: successUploads,
7755
+ literals,
7756
+ mergeWithExisting: intoExisting ? readFileSync(keynvEnvPath, "utf8") : null
7757
+ });
7758
+ writeFileSync(keynvEnvPath, `${writtenLines.join("\n")}
7759
+ `);
7760
+ R2.success(
7761
+ `${intoExisting ? "Updated" : "Wrote"} ${keynvEnvPath} (${successUploads.size + literals.length} entries)`
7762
+ );
7763
+ } catch (err) {
7764
+ R2.error(`Failed to write .keynv.env: ${err instanceof Error ? err.message : String(err)}`);
7765
+ return { exitCode: 1 };
7766
+ }
7767
+ try {
7768
+ const outcome = writeAiContext(root.path);
7769
+ if (outcome === "created") R2.success("Wrote AGENTS.md (so AI agents understand keynv)");
7770
+ else if (outcome === "updated") R2.success("Refreshed keynv section in AGENTS.md");
7771
+ else if (outcome === "appended") R2.success("Appended keynv section to AGENTS.md");
7772
+ } catch (err) {
7773
+ R2.warn(`Could not write AGENTS.md: ${err instanceof Error ? err.message : String(err)}`);
7774
+ }
7775
+ if (scriptWrapSelection.length > 0 && root.packageJsonScripts) {
7776
+ try {
7777
+ updatePackageJsonScripts(
7778
+ join(root.path, "package.json"),
7779
+ root.packageJsonScripts,
7780
+ scriptWrapSelection
7781
+ );
7782
+ R2.success(`Wrapped ${scriptWrapSelection.length} script(s) in package.json`);
7783
+ } catch (err) {
7784
+ R2.warn(
7785
+ `Could not update package.json scripts: ${err instanceof Error ? err.message : String(err)}`
7786
+ );
7787
+ }
7788
+ }
7789
+ if (envFileFateRaw === "delete") {
7790
+ for (const f of envFiles) {
7791
+ try {
7792
+ unlinkSync(f.path);
7793
+ R2.success(`Removed ${f.name}`);
7794
+ } catch (err) {
7795
+ R2.warn(`Could not remove ${f.name}: ${err instanceof Error ? err.message : String(err)}`);
7796
+ }
7797
+ }
7798
+ } else {
7799
+ const gitignorePath = join(root.path, ".gitignore");
7800
+ try {
7801
+ ensureGitignoreEntries(gitignorePath, envFiles.map((f) => f.name));
7802
+ R2.success(`Updated .gitignore (${envFiles.length} entries ensured)`);
7803
+ } catch (err) {
7804
+ R2.warn(`Could not update .gitignore: ${err instanceof Error ? err.message : String(err)}`);
7805
+ }
7806
+ }
7807
+ ye(
7808
+ failed.length > 0 ? `Done with ${failed.length} failure(s) \u2014 see warnings above.` : `Done. Try: ${scriptWrapSelection.includes("dev") ? "npm run dev" : "keynv exec -- <your command>"}`
7809
+ );
7810
+ return { exitCode: failed.length > 0 ? 1 : 0 };
7811
+ }
7812
+ function mergeEnvFiles(files) {
7813
+ const map = /* @__PURE__ */ new Map();
7814
+ for (const f of files) {
7815
+ let entries;
7816
+ try {
7817
+ entries = parseEnvFile(readFileSync(f.path, "utf8"), f.path);
7818
+ } catch (err) {
7819
+ R2.warn(`${f.name}: ${err instanceof Error ? err.message : String(err)} \u2014 skipping file`);
7820
+ continue;
7821
+ }
7822
+ for (const e2 of entries) {
7823
+ const existing = map.get(e2.name);
7824
+ if (existing) {
7825
+ existing.shadowedBy.push(f.name);
7826
+ existing.value = e2.value;
7827
+ existing.isAlias = e2.isAlias;
7828
+ } else {
7829
+ map.set(e2.name, {
7830
+ name: e2.name,
7831
+ value: e2.value,
7832
+ isAlias: e2.isAlias,
7833
+ source: f.name,
7834
+ sourceLine: e2.line,
7835
+ shadowedBy: []
7836
+ });
7837
+ }
7838
+ }
7839
+ }
7840
+ return [...map.values()];
7841
+ }
7842
+ async function pickOrCreateProject(client, suggestedName) {
7843
+ const projects = await listProjects(client);
7844
+ const value = unwrap(
7845
+ await Ee({
7846
+ message: "Use which keynv project?",
7847
+ options: [
7848
+ { value: "__new", label: `+ Create new: "${suggestedName}"` },
7849
+ ...projects.map((p2) => ({ value: p2.id, label: p2.name, hint: p2.id }))
7850
+ ]
7851
+ })
7852
+ );
7853
+ if (value === "__new") {
7854
+ const name = unwrap(
7855
+ await Re({
7856
+ message: "Project name",
7857
+ initialValue: suggestedName,
7858
+ validate: (v2) => v2 && /^[a-z0-9][a-z0-9-]{0,47}$/.test(v2) ? void 0 : "lowercase letters, digits, dashes; up to 48 chars"
7859
+ })
7860
+ );
7861
+ return { id: "", name, created: true };
7862
+ }
7863
+ const match = projects.find((p2) => p2.id === value);
7864
+ if (!match) return null;
7865
+ return { id: match.id, name: match.name, created: false };
7866
+ }
7867
+ async function pickEnvForUpload(client, project, envFiles) {
7868
+ const firstSuffix = envFiles[0]?.suffix ?? null;
7869
+ const suggested = suggestedEnvForSuffix(firstSuffix);
7870
+ if (project.created) {
7871
+ const value2 = unwrap(
7872
+ await Re({
7873
+ message: "Environment to create",
7874
+ initialValue: suggested,
7875
+ validate: (v2) => v2 && /^[a-z0-9][a-z0-9-]{0,23}$/.test(v2) ? void 0 : "lowercase letters, digits, dashes; up to 24 chars"
7876
+ })
7877
+ );
7878
+ return value2;
7879
+ }
7880
+ const detail = await client.request(`/v1/projects/${project.id}`);
7881
+ if (detail.environments.length === 0) {
7882
+ me(
7883
+ `Project "${project.name}" has no environments yet, and we can't add one from init in this version. Create one with \`keynv project create\` (or pick a different project).`
7884
+ );
7885
+ return null;
7886
+ }
7887
+ if (detail.environments.length === 1) {
7888
+ return detail.environments[0]?.name ?? null;
7889
+ }
7890
+ const value = unwrap(
7891
+ await Ee({
7892
+ message: "Upload to which environment?",
7893
+ options: detail.environments.map((e2) => ({
7894
+ value: e2.name,
7895
+ label: e2.name,
7896
+ hint: e2.tier
7897
+ })),
7898
+ initialValue: detail.environments.find((e2) => e2.name === suggested)?.name
7899
+ })
7900
+ );
7901
+ return value;
7902
+ }
7903
+ function composeKeynvEnv(opts) {
7904
+ const { uploadedAliases, literals, mergeWithExisting } = opts;
7905
+ const lines = [];
7906
+ if (mergeWithExisting !== null) {
7907
+ const trimmed = mergeWithExisting.replace(/\n+$/, "");
7908
+ if (trimmed.length > 0) {
7909
+ lines.push(...trimmed.split("\n"));
7910
+ lines.push("");
7911
+ }
7912
+ lines.push(`# >>> keynv init ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)} >>>`);
7913
+ } else {
7914
+ lines.push("# .keynv.env \u2014 alias references to vault secrets.");
7915
+ lines.push("# Safe to commit: this file contains references, not values.");
7916
+ lines.push("# Auto-loaded by `keynv exec`. See https://keynv.dev/docs/keynv-env");
7917
+ lines.push("");
7918
+ }
7919
+ if (uploadedAliases.size > 0) {
7920
+ lines.push("# Vault-resolved (real values live on the keynv server)");
7921
+ for (const [name, alias2] of uploadedAliases) {
7922
+ lines.push(`${name}=${alias2}`);
7923
+ }
7924
+ }
7925
+ if (literals.length > 0) {
7926
+ if (uploadedAliases.size > 0) lines.push("");
7927
+ lines.push("# Plain literals (passed through unchanged)");
7928
+ for (const e2 of literals) {
7929
+ const value = needsQuoting(e2.value) ? `"${e2.value.replace(/"/g, '\\"')}"` : e2.value;
7930
+ lines.push(`${e2.name}=${value}`);
7931
+ }
7932
+ }
7933
+ if (mergeWithExisting !== null) {
7934
+ lines.push(`# <<< keynv init <<<`);
7935
+ }
7936
+ return lines;
7937
+ }
7938
+ function needsQuoting(value) {
7939
+ return /\s/.test(value) || value.includes("#") || value.length === 0;
7940
+ }
7941
+ function updatePackageJsonScripts(path, originalScripts, selectedNames) {
7942
+ const raw = readFileSync(path, "utf8");
7943
+ const indentMatch = raw.match(/^([ \t]+)"/m);
7944
+ const indent = indentMatch ? indentMatch[1] : " ";
7945
+ const trailingNewline = raw.endsWith("\n");
7946
+ const pkg = JSON.parse(raw);
7947
+ const updated = applyWraps(originalScripts, selectedNames);
7948
+ pkg.scripts = updated;
7949
+ const out = JSON.stringify(pkg, null, indent);
7950
+ writeFileSync(path, trailingNewline ? `${out}
7951
+ ` : out);
7952
+ }
7953
+ function ensureGitignoreEntries(path, basenames) {
7954
+ let existing = "";
7955
+ if (existsSync(path)) existing = readFileSync(path, "utf8");
7956
+ const existingLines = new Set(existing.split("\n").map((l) => l.trim()));
7957
+ const toAdd = basenames.filter((n) => !existingLines.has(n));
7958
+ if (toAdd.length === 0) return;
7959
+ const sep = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
7960
+ const block = ["", "# added by keynv init", ...toAdd, ""].join("\n");
7961
+ writeFileSync(path, `${existing}${sep}${block}`);
7962
+ }
7963
+ var init_init = __esm({
7964
+ "src/ui/flows/init.ts"() {
7965
+ init_dist();
7966
+ init_dist5();
7967
+ init_envFile();
7968
+ init_detect();
7969
+ init_aiContext();
7970
+ init_heuristics();
7971
+ init_scriptWrap();
7972
+ init_cancel();
7973
+ init_pickProject();
7974
+ }
7975
+ });
7976
+
6928
7977
  // src/ui/helpers/pickSecret.ts
6929
7978
  async function listSecrets(client, projectId2) {
6930
7979
  const data = await client.request(
@@ -7060,14 +8109,14 @@ async function runSecretMenu(client, project, alias2) {
7060
8109
  async function copyToClipboard(value) {
7061
8110
  const platform = process.platform;
7062
8111
  const cmd = platform === "darwin" ? ["pbcopy", []] : platform === "win32" ? ["clip", []] : ["xclip", ["-selection", "clipboard"]];
7063
- return new Promise((resolve2) => {
8112
+ return new Promise((resolve3) => {
7064
8113
  try {
7065
8114
  const child = spawn(cmd[0], cmd[1], { stdio: ["pipe", "ignore", "ignore"] });
7066
- child.on("error", () => resolve2(false));
7067
- child.on("exit", (code) => resolve2(code === 0));
8115
+ child.on("error", () => resolve3(false));
8116
+ child.on("exit", (code) => resolve3(code === 0));
7068
8117
  child.stdin.end(value);
7069
8118
  } catch {
7070
- resolve2(false);
8119
+ resolve3(false);
7071
8120
  }
7072
8121
  });
7073
8122
  }
@@ -7187,24 +8236,24 @@ var require_lib2 = __commonJS({
7187
8236
  const currentChar = sql.charCodeAt(position);
7188
8237
  const nextChar = sql.charCodeAt(position + 1);
7189
8238
  if (currentChar === charCode.singleQuote) {
7190
- for (let cursor2 = position + 1; cursor2 < sql.length; cursor2++) {
7191
- if (sql.charCodeAt(cursor2) === charCode.backslash)
7192
- cursor2++;
7193
- else if (sql.charCodeAt(cursor2) === charCode.singleQuote)
7194
- return cursor2 + 1;
8239
+ for (let cursor = position + 1; cursor < sql.length; cursor++) {
8240
+ if (sql.charCodeAt(cursor) === charCode.backslash)
8241
+ cursor++;
8242
+ else if (sql.charCodeAt(cursor) === charCode.singleQuote)
8243
+ return cursor + 1;
7195
8244
  }
7196
8245
  return sql.length;
7197
8246
  }
7198
8247
  if (currentChar === charCode.backtick) {
7199
8248
  const length = sql.length;
7200
- for (let cursor2 = position + 1; cursor2 < length; cursor2++) {
7201
- if (sql.charCodeAt(cursor2) !== charCode.backtick)
8249
+ for (let cursor = position + 1; cursor < length; cursor++) {
8250
+ if (sql.charCodeAt(cursor) !== charCode.backtick)
7202
8251
  continue;
7203
- if (sql.charCodeAt(cursor2 + 1) === charCode.backtick) {
7204
- cursor2++;
8252
+ if (sql.charCodeAt(cursor + 1) === charCode.backtick) {
8253
+ cursor++;
7205
8254
  continue;
7206
8255
  }
7207
- return cursor2 + 1;
8256
+ return cursor + 1;
7208
8257
  }
7209
8258
  return length;
7210
8259
  }
@@ -7247,11 +8296,11 @@ var require_lib2 = __commonJS({
7247
8296
  if (lower === 115 && matchesWord(sql, position, "set", length))
7248
8297
  return position + 3;
7249
8298
  if (lower === 107 && matchesWord(sql, position, "key", length)) {
7250
- let cursor2 = position + 3;
7251
- while (cursor2 < length && isWhitespace(sql.charCodeAt(cursor2)))
7252
- cursor2++;
7253
- if (matchesWord(sql, cursor2, "update", length))
7254
- return cursor2 + 6;
8299
+ let cursor = position + 3;
8300
+ while (cursor < length && isWhitespace(sql.charCodeAt(cursor)))
8301
+ cursor++;
8302
+ if (matchesWord(sql, cursor, "update", length))
8303
+ return cursor + 6;
7255
8304
  }
7256
8305
  }
7257
8306
  return -1;
@@ -23813,7 +24862,7 @@ var require_named_placeholders = __commonJS({
23813
24862
  }
23814
24863
  return s;
23815
24864
  }
23816
- function join8(tree) {
24865
+ function join6(tree) {
23817
24866
  if (tree.length === 1) {
23818
24867
  return tree;
23819
24868
  }
@@ -23839,7 +24888,7 @@ var require_named_placeholders = __commonJS({
23839
24888
  if (cache2 && (tree = cache2.get(query))) {
23840
24889
  return toArrayParams(tree, paramsObj);
23841
24890
  }
23842
- tree = join8(parse(query));
24891
+ tree = join6(parse(query));
23843
24892
  if (cache2) {
23844
24893
  cache2.set(query, tree);
23845
24894
  }
@@ -23995,11 +25044,11 @@ var require_connection = __commonJS({
23995
25044
  const config = this.config;
23996
25045
  tracePromise(
23997
25046
  connectChannel,
23998
- () => new Promise((resolve2, reject) => {
25047
+ () => new Promise((resolve3, reject) => {
23999
25048
  let onConnect, onError;
24000
25049
  onConnect = (param) => {
24001
25050
  this.removeListener("error", onError);
24002
- resolve2(param);
25051
+ resolve3(param);
24003
25052
  };
24004
25053
  onError = (err) => {
24005
25054
  this.removeListener("connect", onConnect);
@@ -24424,9 +25473,9 @@ var require_connection = __commonJS({
24424
25473
  } else if (shouldTrace(queryChannel)) {
24425
25474
  tracePromise(
24426
25475
  queryChannel,
24427
- () => new Promise((resolve2, reject) => {
25476
+ () => new Promise((resolve3, reject) => {
24428
25477
  cmdQuery.once("error", reject);
24429
- cmdQuery.once("end", () => resolve2());
25478
+ cmdQuery.once("end", () => resolve3());
24430
25479
  this.addCommand(cmdQuery);
24431
25480
  }),
24432
25481
  () => {
@@ -24573,12 +25622,12 @@ var require_connection = __commonJS({
24573
25622
  } else if (shouldTrace(executeChannel)) {
24574
25623
  tracePromise(
24575
25624
  executeChannel,
24576
- () => new Promise((resolve2, reject) => {
25625
+ () => new Promise((resolve3, reject) => {
24577
25626
  prepareAndExecute((err) => {
24578
25627
  executeCommand.emit("error", err);
24579
25628
  });
24580
25629
  executeCommand.once("error", reject);
24581
- executeCommand.once("end", () => resolve2());
25630
+ executeCommand.once("end", () => resolve3());
24582
25631
  }),
24583
25632
  () => {
24584
25633
  const server = getServerContext(this.config);
@@ -24843,13 +25892,13 @@ var require_capture_local_err = __commonJS({
24843
25892
  var require_make_done_cb = __commonJS({
24844
25893
  "../../node_modules/.pnpm/mysql2@3.22.3_@types+node@24.12.3/node_modules/mysql2/lib/promise/make_done_cb.js"(exports, module) {
24845
25894
  var { applyCapturedStack } = require_capture_local_err();
24846
- function makeDoneCb(resolve2, reject, stackHolder) {
25895
+ function makeDoneCb(resolve3, reject, stackHolder) {
24847
25896
  return function(err, rows, fields) {
24848
25897
  if (err) {
24849
25898
  applyCapturedStack(err, stackHolder);
24850
25899
  reject(err);
24851
25900
  } else {
24852
- resolve2([rows, fields]);
25901
+ resolve3([rows, fields]);
24853
25902
  }
24854
25903
  };
24855
25904
  }
@@ -24872,8 +25921,8 @@ var require_prepared_statement_info = __commonJS({
24872
25921
  const stackHolder = captureStackHolder(
24873
25922
  _PromisePreparedStatementInfo.prototype.execute
24874
25923
  );
24875
- return new this.Promise((resolve2, reject) => {
24876
- const done = makeDoneCb(resolve2, reject, stackHolder);
25924
+ return new this.Promise((resolve3, reject) => {
25925
+ const done = makeDoneCb(resolve3, reject, stackHolder);
24877
25926
  if (parameters) {
24878
25927
  s.execute(parameters, done);
24879
25928
  } else {
@@ -24882,9 +25931,9 @@ var require_prepared_statement_info = __commonJS({
24882
25931
  });
24883
25932
  }
24884
25933
  close() {
24885
- return new this.Promise((resolve2) => {
25934
+ return new this.Promise((resolve3) => {
24886
25935
  this.statement.close();
24887
- resolve2();
25936
+ resolve3();
24888
25937
  });
24889
25938
  }
24890
25939
  };
@@ -24955,8 +26004,8 @@ var require_connection2 = __commonJS({
24955
26004
  "Callback function is not available with promise clients."
24956
26005
  );
24957
26006
  }
24958
- return new this.Promise((resolve2, reject) => {
24959
- const done = makeDoneCb(resolve2, reject, stackHolder);
26007
+ return new this.Promise((resolve3, reject) => {
26008
+ const done = makeDoneCb(resolve3, reject, stackHolder);
24960
26009
  if (params !== void 0) {
24961
26010
  c2.query(query, params, done);
24962
26011
  } else {
@@ -24972,8 +26021,8 @@ var require_connection2 = __commonJS({
24972
26021
  "Callback function is not available with promise clients."
24973
26022
  );
24974
26023
  }
24975
- return new this.Promise((resolve2, reject) => {
24976
- const done = makeDoneCb(resolve2, reject, stackHolder);
26024
+ return new this.Promise((resolve3, reject) => {
26025
+ const done = makeDoneCb(resolve3, reject, stackHolder);
24977
26026
  if (params !== void 0) {
24978
26027
  c2.execute(query, params, done);
24979
26028
  } else {
@@ -24982,8 +26031,8 @@ var require_connection2 = __commonJS({
24982
26031
  });
24983
26032
  }
24984
26033
  end() {
24985
- return new this.Promise((resolve2) => {
24986
- this.connection.end(resolve2);
26034
+ return new this.Promise((resolve3) => {
26035
+ this.connection.end(resolve3);
24987
26036
  });
24988
26037
  }
24989
26038
  async [Symbol.asyncDispose]() {
@@ -24996,16 +26045,16 @@ var require_connection2 = __commonJS({
24996
26045
  const stackHolder = captureStackHolder(
24997
26046
  _PromiseConnection.prototype.beginTransaction
24998
26047
  );
24999
- return new this.Promise((resolve2, reject) => {
25000
- const done = makeDoneCb(resolve2, reject, stackHolder);
26048
+ return new this.Promise((resolve3, reject) => {
26049
+ const done = makeDoneCb(resolve3, reject, stackHolder);
25001
26050
  c2.beginTransaction(done);
25002
26051
  });
25003
26052
  }
25004
26053
  commit() {
25005
26054
  const c2 = this.connection;
25006
26055
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.commit);
25007
- return new this.Promise((resolve2, reject) => {
25008
- const done = makeDoneCb(resolve2, reject, stackHolder);
26056
+ return new this.Promise((resolve3, reject) => {
26057
+ const done = makeDoneCb(resolve3, reject, stackHolder);
25009
26058
  c2.commit(done);
25010
26059
  });
25011
26060
  }
@@ -25014,21 +26063,21 @@ var require_connection2 = __commonJS({
25014
26063
  const stackHolder = captureStackHolder(
25015
26064
  _PromiseConnection.prototype.rollback
25016
26065
  );
25017
- return new this.Promise((resolve2, reject) => {
25018
- const done = makeDoneCb(resolve2, reject, stackHolder);
26066
+ return new this.Promise((resolve3, reject) => {
26067
+ const done = makeDoneCb(resolve3, reject, stackHolder);
25019
26068
  c2.rollback(done);
25020
26069
  });
25021
26070
  }
25022
26071
  ping() {
25023
26072
  const c2 = this.connection;
25024
26073
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.ping);
25025
- return new this.Promise((resolve2, reject) => {
26074
+ return new this.Promise((resolve3, reject) => {
25026
26075
  c2.ping((err) => {
25027
26076
  if (err) {
25028
26077
  applyCapturedStack(err, stackHolder);
25029
26078
  reject(err);
25030
26079
  } else {
25031
- resolve2(true);
26080
+ resolve3(true);
25032
26081
  }
25033
26082
  });
25034
26083
  });
@@ -25036,13 +26085,13 @@ var require_connection2 = __commonJS({
25036
26085
  reset() {
25037
26086
  const c2 = this.connection;
25038
26087
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.reset);
25039
- return new this.Promise((resolve2, reject) => {
26088
+ return new this.Promise((resolve3, reject) => {
25040
26089
  c2.reset((err) => {
25041
26090
  if (err) {
25042
26091
  applyCapturedStack(err, stackHolder);
25043
26092
  reject(err);
25044
26093
  } else {
25045
- resolve2();
26094
+ resolve3();
25046
26095
  }
25047
26096
  });
25048
26097
  });
@@ -25050,13 +26099,13 @@ var require_connection2 = __commonJS({
25050
26099
  connect() {
25051
26100
  const c2 = this.connection;
25052
26101
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.connect);
25053
- return new this.Promise((resolve2, reject) => {
26102
+ return new this.Promise((resolve3, reject) => {
25054
26103
  c2.connect((err, param) => {
25055
26104
  if (err) {
25056
26105
  applyCapturedStack(err, stackHolder);
25057
26106
  reject(err);
25058
26107
  } else {
25059
- resolve2(param);
26108
+ resolve3(param);
25060
26109
  }
25061
26110
  });
25062
26111
  });
@@ -25065,7 +26114,7 @@ var require_connection2 = __commonJS({
25065
26114
  const c2 = this.connection;
25066
26115
  const promiseImpl = this.Promise;
25067
26116
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.prepare);
25068
- return new this.Promise((resolve2, reject) => {
26117
+ return new this.Promise((resolve3, reject) => {
25069
26118
  c2.prepare(options, (err, statement) => {
25070
26119
  if (err) {
25071
26120
  applyCapturedStack(err, stackHolder);
@@ -25075,7 +26124,7 @@ var require_connection2 = __commonJS({
25075
26124
  statement,
25076
26125
  promiseImpl
25077
26126
  );
25078
- resolve2(wrappedStatement);
26127
+ resolve3(wrappedStatement);
25079
26128
  }
25080
26129
  });
25081
26130
  });
@@ -25085,13 +26134,13 @@ var require_connection2 = __commonJS({
25085
26134
  const stackHolder = captureStackHolder(
25086
26135
  _PromiseConnection.prototype.changeUser
25087
26136
  );
25088
- return new this.Promise((resolve2, reject) => {
26137
+ return new this.Promise((resolve3, reject) => {
25089
26138
  c2.changeUser(options, (err) => {
25090
26139
  if (err) {
25091
26140
  applyCapturedStack(err, stackHolder);
25092
26141
  reject(err);
25093
26142
  } else {
25094
- resolve2();
26143
+ resolve3();
25095
26144
  }
25096
26145
  });
25097
26146
  });
@@ -25553,12 +26602,12 @@ var require_pool2 = __commonJS({
25553
26602
  }
25554
26603
  getConnection() {
25555
26604
  const corePool = this.pool;
25556
- return new this.Promise((resolve2, reject) => {
26605
+ return new this.Promise((resolve3, reject) => {
25557
26606
  corePool.getConnection((err, coreConnection) => {
25558
26607
  if (err) {
25559
26608
  reject(err);
25560
26609
  } else {
25561
- resolve2(new PromisePoolConnection(coreConnection, this.Promise));
26610
+ resolve3(new PromisePoolConnection(coreConnection, this.Promise));
25562
26611
  }
25563
26612
  });
25564
26613
  });
@@ -25574,8 +26623,8 @@ var require_pool2 = __commonJS({
25574
26623
  "Callback function is not available with promise clients."
25575
26624
  );
25576
26625
  }
25577
- return new this.Promise((resolve2, reject) => {
25578
- const done = makeDoneCb(resolve2, reject, stackHolder);
26626
+ return new this.Promise((resolve3, reject) => {
26627
+ const done = makeDoneCb(resolve3, reject, stackHolder);
25579
26628
  if (args !== void 0) {
25580
26629
  corePool.query(sql, args, done);
25581
26630
  } else {
@@ -25591,8 +26640,8 @@ var require_pool2 = __commonJS({
25591
26640
  "Callback function is not available with promise clients."
25592
26641
  );
25593
26642
  }
25594
- return new this.Promise((resolve2, reject) => {
25595
- const done = makeDoneCb(resolve2, reject, stackHolder);
26643
+ return new this.Promise((resolve3, reject) => {
26644
+ const done = makeDoneCb(resolve3, reject, stackHolder);
25596
26645
  if (args) {
25597
26646
  corePool.execute(sql, args, done);
25598
26647
  } else {
@@ -25603,13 +26652,13 @@ var require_pool2 = __commonJS({
25603
26652
  end() {
25604
26653
  const corePool = this.pool;
25605
26654
  const stackHolder = captureStackHolder(_PromisePool.prototype.end);
25606
- return new this.Promise((resolve2, reject) => {
26655
+ return new this.Promise((resolve3, reject) => {
25607
26656
  corePool.end((err) => {
25608
26657
  if (err) {
25609
26658
  applyCapturedStack(err, stackHolder);
25610
26659
  reject(err);
25611
26660
  } else {
25612
- resolve2();
26661
+ resolve3();
25613
26662
  }
25614
26663
  });
25615
26664
  });
@@ -26034,12 +27083,12 @@ var require_pool_cluster2 = __commonJS({
26034
27083
  }
26035
27084
  getConnection() {
26036
27085
  const corePoolNamespace = this.poolNamespace;
26037
- return new this.Promise((resolve2, reject) => {
27086
+ return new this.Promise((resolve3, reject) => {
26038
27087
  corePoolNamespace.getConnection((err, coreConnection) => {
26039
27088
  if (err) {
26040
27089
  reject(err);
26041
27090
  } else {
26042
- resolve2(new PromisePoolConnection(coreConnection, this.Promise));
27091
+ resolve3(new PromisePoolConnection(coreConnection, this.Promise));
26043
27092
  }
26044
27093
  });
26045
27094
  });
@@ -26054,8 +27103,8 @@ var require_pool_cluster2 = __commonJS({
26054
27103
  "Callback function is not available with promise clients."
26055
27104
  );
26056
27105
  }
26057
- return new this.Promise((resolve2, reject) => {
26058
- const done = makeDoneCb(resolve2, reject, stackHolder);
27106
+ return new this.Promise((resolve3, reject) => {
27107
+ const done = makeDoneCb(resolve3, reject, stackHolder);
26059
27108
  corePoolNamespace.query(sql, values, done);
26060
27109
  });
26061
27110
  }
@@ -26069,8 +27118,8 @@ var require_pool_cluster2 = __commonJS({
26069
27118
  "Callback function is not available with promise clients."
26070
27119
  );
26071
27120
  }
26072
- return new this.Promise((resolve2, reject) => {
26073
- const done = makeDoneCb(resolve2, reject, stackHolder);
27121
+ return new this.Promise((resolve3, reject) => {
27122
+ const done = makeDoneCb(resolve3, reject, stackHolder);
26074
27123
  corePoolNamespace.execute(sql, values, done);
26075
27124
  });
26076
27125
  }
@@ -26108,9 +27157,9 @@ var require_promise = __commonJS({
26108
27157
  "no Promise implementation available.Use promise-enabled node version or pass userland Promise implementation as parameter, for example: { Promise: require('bluebird') }"
26109
27158
  );
26110
27159
  }
26111
- return new thePromise((resolve2, reject) => {
27160
+ return new thePromise((resolve3, reject) => {
26112
27161
  coreConnection.once("connect", () => {
26113
- resolve2(new PromiseConnection(coreConnection, thePromise));
27162
+ resolve3(new PromiseConnection(coreConnection, thePromise));
26114
27163
  });
26115
27164
  coreConnection.once("error", (err) => {
26116
27165
  applyCapturedStack(err, stackHolder);
@@ -26137,7 +27186,7 @@ var require_promise = __commonJS({
26137
27186
  }
26138
27187
  getConnection(pattern, selector) {
26139
27188
  const corePoolCluster = this.poolCluster;
26140
- return new this.Promise((resolve2, reject) => {
27189
+ return new this.Promise((resolve3, reject) => {
26141
27190
  corePoolCluster.getConnection(
26142
27191
  pattern,
26143
27192
  selector,
@@ -26145,7 +27194,7 @@ var require_promise = __commonJS({
26145
27194
  if (err) {
26146
27195
  reject(err);
26147
27196
  } else {
26148
- resolve2(new PromisePoolConnection(coreConnection, this.Promise));
27197
+ resolve3(new PromisePoolConnection(coreConnection, this.Promise));
26149
27198
  }
26150
27199
  }
26151
27200
  );
@@ -26159,8 +27208,8 @@ var require_promise = __commonJS({
26159
27208
  "Callback function is not available with promise clients."
26160
27209
  );
26161
27210
  }
26162
- return new this.Promise((resolve2, reject) => {
26163
- const done = makeDoneCb(resolve2, reject, stackHolder);
27211
+ return new this.Promise((resolve3, reject) => {
27212
+ const done = makeDoneCb(resolve3, reject, stackHolder);
26164
27213
  corePoolCluster.query(sql, args, done);
26165
27214
  });
26166
27215
  }
@@ -26174,8 +27223,8 @@ var require_promise = __commonJS({
26174
27223
  "Callback function is not available with promise clients."
26175
27224
  );
26176
27225
  }
26177
- return new this.Promise((resolve2, reject) => {
26178
- const done = makeDoneCb(resolve2, reject, stackHolder);
27226
+ return new this.Promise((resolve3, reject) => {
27227
+ const done = makeDoneCb(resolve3, reject, stackHolder);
26179
27228
  corePoolCluster.execute(sql, args, done);
26180
27229
  });
26181
27230
  }
@@ -26188,13 +27237,13 @@ var require_promise = __commonJS({
26188
27237
  end() {
26189
27238
  const corePoolCluster = this.poolCluster;
26190
27239
  const stackHolder = captureStackHolder(_PromisePoolCluster.prototype.end);
26191
- return new this.Promise((resolve2, reject) => {
27240
+ return new this.Promise((resolve3, reject) => {
26192
27241
  corePoolCluster.end((err) => {
26193
27242
  if (err) {
26194
27243
  applyCapturedStack(err, stackHolder);
26195
27244
  reject(err);
26196
27245
  } else {
26197
- resolve2();
27246
+ resolve3();
26198
27247
  }
26199
27248
  });
26200
27249
  });
@@ -29269,7 +30318,7 @@ var require_dist = __commonJS({
29269
30318
  function parse(stream, callback) {
29270
30319
  const parser = new parser_1.Parser();
29271
30320
  stream.on("data", (buffer) => parser.parse(buffer, callback));
29272
- return new Promise((resolve2) => stream.on("end", () => resolve2()));
30321
+ return new Promise((resolve3) => stream.on("end", () => resolve3()));
29273
30322
  }
29274
30323
  exports.parse = parse;
29275
30324
  }
@@ -29994,12 +31043,12 @@ var require_client2 = __commonJS({
29994
31043
  this._connect(callback);
29995
31044
  return;
29996
31045
  }
29997
- return new this._Promise((resolve2, reject) => {
31046
+ return new this._Promise((resolve3, reject) => {
29998
31047
  this._connect((error) => {
29999
31048
  if (error) {
30000
31049
  reject(error);
30001
31050
  } else {
30002
- resolve2(this);
31051
+ resolve3(this);
30003
31052
  }
30004
31053
  });
30005
31054
  });
@@ -30345,8 +31394,8 @@ var require_client2 = __commonJS({
30345
31394
  readTimeout = config.query_timeout || this.connectionParameters.query_timeout;
30346
31395
  query = new Query2(config, values, callback);
30347
31396
  if (!query.callback) {
30348
- result = new this._Promise((resolve2, reject) => {
30349
- query.callback = (err, res) => err ? reject(err) : resolve2(res);
31397
+ result = new this._Promise((resolve3, reject) => {
31398
+ query.callback = (err, res) => err ? reject(err) : resolve3(res);
30350
31399
  }).catch((err) => {
30351
31400
  Error.captureStackTrace(err);
30352
31401
  throw err;
@@ -30423,8 +31472,8 @@ var require_client2 = __commonJS({
30423
31472
  if (cb) {
30424
31473
  this.connection.once("end", cb);
30425
31474
  } else {
30426
- return new this._Promise((resolve2) => {
30427
- this.connection.once("end", resolve2);
31475
+ return new this._Promise((resolve3) => {
31476
+ this.connection.once("end", resolve3);
30428
31477
  });
30429
31478
  }
30430
31479
  }
@@ -30472,8 +31521,8 @@ var require_pg_pool = __commonJS({
30472
31521
  const cb = function(err, client) {
30473
31522
  err ? rej(err) : res(client);
30474
31523
  };
30475
- const result = new Promise2(function(resolve2, reject) {
30476
- res = resolve2;
31524
+ const result = new Promise2(function(resolve3, reject) {
31525
+ res = resolve3;
30477
31526
  rej = reject;
30478
31527
  }).catch((err) => {
30479
31528
  Error.captureStackTrace(err);
@@ -30534,7 +31583,7 @@ var require_pg_pool = __commonJS({
30534
31583
  if (typeof Promise2.try === "function") {
30535
31584
  return Promise2.try(f);
30536
31585
  }
30537
- return new Promise2((resolve2) => resolve2(f()));
31586
+ return new Promise2((resolve3) => resolve3(f()));
30538
31587
  }
30539
31588
  _isFull() {
30540
31589
  return this._clients.length >= this.options.max;
@@ -30926,8 +31975,8 @@ var require_query4 = __commonJS({
30926
31975
  NativeQuery.prototype._getPromise = function() {
30927
31976
  if (this._promise) return this._promise;
30928
31977
  this._promise = new Promise(
30929
- function(resolve2, reject) {
30930
- this._once("end", resolve2);
31978
+ function(resolve3, reject) {
31979
+ this._once("end", resolve3);
30931
31980
  this._once("error", reject);
30932
31981
  }.bind(this)
30933
31982
  );
@@ -31104,12 +32153,12 @@ var require_client3 = __commonJS({
31104
32153
  this._connect(callback);
31105
32154
  return;
31106
32155
  }
31107
- return new this._Promise((resolve2, reject) => {
32156
+ return new this._Promise((resolve3, reject) => {
31108
32157
  this._connect((error) => {
31109
32158
  if (error) {
31110
32159
  reject(error);
31111
32160
  } else {
31112
- resolve2(this);
32161
+ resolve3(this);
31113
32162
  }
31114
32163
  });
31115
32164
  });
@@ -31133,8 +32182,8 @@ var require_client3 = __commonJS({
31133
32182
  query = new NativeQuery(config, values, callback);
31134
32183
  if (!query.callback) {
31135
32184
  let resolveOut, rejectOut;
31136
- result = new this._Promise((resolve2, reject) => {
31137
- resolveOut = resolve2;
32185
+ result = new this._Promise((resolve3, reject) => {
32186
+ resolveOut = resolve3;
31138
32187
  rejectOut = reject;
31139
32188
  }).catch((err) => {
31140
32189
  Error.captureStackTrace(err);
@@ -31194,8 +32243,8 @@ var require_client3 = __commonJS({
31194
32243
  }
31195
32244
  let result;
31196
32245
  if (!cb) {
31197
- result = new this._Promise(function(resolve2, reject) {
31198
- cb = (err) => err ? reject(err) : resolve2();
32246
+ result = new this._Promise(function(resolve3, reject) {
32247
+ cb = (err) => err ? reject(err) : resolve3();
31199
32248
  });
31200
32249
  }
31201
32250
  this.native.end(function() {
@@ -36302,7 +37351,7 @@ var require_Command = __commonJS({
36302
37351
  }
36303
37352
  }
36304
37353
  initPromise() {
36305
- const promise = new Promise((resolve2, reject) => {
37354
+ const promise = new Promise((resolve3, reject) => {
36306
37355
  if (!this.transformed) {
36307
37356
  this.transformed = true;
36308
37357
  const transformer = _Command._transformer.argument[this.name];
@@ -36311,7 +37360,7 @@ var require_Command = __commonJS({
36311
37360
  }
36312
37361
  this.stringifyArguments();
36313
37362
  }
36314
- this.resolve = this._convertValue(resolve2);
37363
+ this.resolve = this._convertValue(resolve3);
36315
37364
  this.reject = (err) => {
36316
37365
  this._clearTimers();
36317
37366
  if (this.errorStack) {
@@ -36344,11 +37393,11 @@ var require_Command = __commonJS({
36344
37393
  /**
36345
37394
  * Convert the value from buffer to the target encoding.
36346
37395
  */
36347
- _convertValue(resolve2) {
37396
+ _convertValue(resolve3) {
36348
37397
  return (value) => {
36349
37398
  try {
36350
37399
  this._clearTimers();
36351
- resolve2(this.transformReply(value));
37400
+ resolve3(this.transformReply(value));
36352
37401
  this.isResolved = true;
36353
37402
  } catch (err) {
36354
37403
  this.reject(err);
@@ -36626,13 +37675,13 @@ var require_autoPipelining = __commonJS({
36626
37675
  if (client.isCluster && !client.slots.length) {
36627
37676
  if (client.status === "wait")
36628
37677
  client.connect().catch(lodash_1.noop);
36629
- return (0, standard_as_callback_1.default)(new Promise(function(resolve2, reject) {
37678
+ return (0, standard_as_callback_1.default)(new Promise(function(resolve3, reject) {
36630
37679
  client.delayUntilReady((err) => {
36631
37680
  if (err) {
36632
37681
  reject(err);
36633
37682
  return;
36634
37683
  }
36635
- executeWithAutoPipelining(client, functionName, commandName, args, null).then(resolve2, reject);
37684
+ executeWithAutoPipelining(client, functionName, commandName, args, null).then(resolve3, reject);
36636
37685
  });
36637
37686
  }), callback);
36638
37687
  }
@@ -36653,13 +37702,13 @@ var require_autoPipelining = __commonJS({
36653
37702
  pipeline[exports.kExec] = true;
36654
37703
  setImmediate(executeAutoPipeline, client, slotKey);
36655
37704
  }
36656
- const autoPipelinePromise = new Promise(function(resolve2, reject) {
37705
+ const autoPipelinePromise = new Promise(function(resolve3, reject) {
36657
37706
  pipeline[exports.kCallbacks].push(function(err, value) {
36658
37707
  if (err) {
36659
37708
  reject(err);
36660
37709
  return;
36661
37710
  }
36662
- resolve2(value);
37711
+ resolve3(value);
36663
37712
  });
36664
37713
  if (functionName === "call") {
36665
37714
  args.unshift(commandName);
@@ -36894,8 +37943,8 @@ var require_Pipeline = __commonJS({
36894
37943
  this[name] = redis[name];
36895
37944
  this[name + "Buffer"] = redis[name + "Buffer"];
36896
37945
  });
36897
- this.promise = new Promise((resolve2, reject) => {
36898
- this.resolve = resolve2;
37946
+ this.promise = new Promise((resolve3, reject) => {
37947
+ this.resolve = resolve3;
36899
37948
  this.reject = reject;
36900
37949
  });
36901
37950
  const _this = this;
@@ -37195,13 +38244,13 @@ var require_transaction = __commonJS({
37195
38244
  if (this.isCluster && !this.redis.slots.length) {
37196
38245
  if (this.redis.status === "wait")
37197
38246
  this.redis.connect().catch(utils_1.noop);
37198
- return (0, standard_as_callback_1.default)(new Promise((resolve2, reject) => {
38247
+ return (0, standard_as_callback_1.default)(new Promise((resolve3, reject) => {
37199
38248
  this.redis.delayUntilReady((err) => {
37200
38249
  if (err) {
37201
38250
  reject(err);
37202
38251
  return;
37203
38252
  }
37204
- this.exec(pipeline).then(resolve2, reject);
38253
+ this.exec(pipeline).then(resolve3, reject);
37205
38254
  });
37206
38255
  }), callback);
37207
38256
  }
@@ -38330,7 +39379,7 @@ var require_cluster = __commonJS({
38330
39379
  * Connect to a cluster
38331
39380
  */
38332
39381
  connect() {
38333
- return new Promise((resolve2, reject) => {
39382
+ return new Promise((resolve3, reject) => {
38334
39383
  if (this.status === "connecting" || this.status === "connect" || this.status === "ready") {
38335
39384
  reject(new Error("Redis is already connecting/connected"));
38336
39385
  return;
@@ -38359,7 +39408,7 @@ var require_cluster = __commonJS({
38359
39408
  this.retryAttempts = 0;
38360
39409
  this.executeOfflineCommands();
38361
39410
  this.resetNodesRefreshInterval();
38362
- resolve2();
39411
+ resolve3();
38363
39412
  };
38364
39413
  let closeListener = void 0;
38365
39414
  const refreshListener = () => {
@@ -38969,7 +40018,7 @@ var require_cluster = __commonJS({
38969
40018
  });
38970
40019
  }
38971
40020
  resolveSrv(hostname) {
38972
- return new Promise((resolve2, reject) => {
40021
+ return new Promise((resolve3, reject) => {
38973
40022
  this.options.resolveSrv(hostname, (err, records) => {
38974
40023
  if (err) {
38975
40024
  return reject(err);
@@ -38983,7 +40032,7 @@ var require_cluster = __commonJS({
38983
40032
  if (!group.records.length) {
38984
40033
  sortedKeys.shift();
38985
40034
  }
38986
- self2.dnsLookup(record.name).then((host) => resolve2({
40035
+ self2.dnsLookup(record.name).then((host) => resolve3({
38987
40036
  host,
38988
40037
  port: record.port
38989
40038
  }), tryFirstOne);
@@ -38993,14 +40042,14 @@ var require_cluster = __commonJS({
38993
40042
  });
38994
40043
  }
38995
40044
  dnsLookup(hostname) {
38996
- return new Promise((resolve2, reject) => {
40045
+ return new Promise((resolve3, reject) => {
38997
40046
  this.options.dnsLookup(hostname, (err, address) => {
38998
40047
  if (err) {
38999
40048
  debug2("failed to resolve hostname %s to IP: %s", hostname, err.message);
39000
40049
  reject(err);
39001
40050
  } else {
39002
40051
  debug2("resolved hostname %s to IP %s", hostname, address);
39003
- resolve2(address);
40052
+ resolve3(address);
39004
40053
  }
39005
40054
  });
39006
40055
  });
@@ -39155,7 +40204,7 @@ var require_StandaloneConnector = __commonJS({
39155
40204
  if (options.tls) {
39156
40205
  Object.assign(connectionOptions, options.tls);
39157
40206
  }
39158
- return new Promise((resolve2, reject) => {
40207
+ return new Promise((resolve3, reject) => {
39159
40208
  process.nextTick(() => {
39160
40209
  if (!this.connecting) {
39161
40210
  reject(new Error(utils_1.CONNECTION_CLOSED_ERROR_MSG));
@@ -39174,7 +40223,7 @@ var require_StandaloneConnector = __commonJS({
39174
40223
  this.stream.once("error", (err) => {
39175
40224
  this.firstError = err;
39176
40225
  });
39177
- resolve2(this.stream);
40226
+ resolve3(this.stream);
39178
40227
  });
39179
40228
  });
39180
40229
  }
@@ -39330,7 +40379,7 @@ var require_SentinelConnector = __commonJS({
39330
40379
  const error = new Error(errorMsg);
39331
40380
  if (typeof retryDelay === "number") {
39332
40381
  eventEmitter("error", error);
39333
- await new Promise((resolve2) => setTimeout(resolve2, retryDelay));
40382
+ await new Promise((resolve3) => setTimeout(resolve3, retryDelay));
39334
40383
  return connectToNext();
39335
40384
  } else {
39336
40385
  throw error;
@@ -40647,7 +41696,7 @@ var require_Redis = __commonJS({
40647
41696
  * if the connection fails, times out, or if Redis is already connecting/connected.
40648
41697
  */
40649
41698
  connect(callback) {
40650
- const promise = new Promise((resolve2, reject) => {
41699
+ const promise = new Promise((resolve3, reject) => {
40651
41700
  if (this.status === "connecting" || this.status === "connect" || this.status === "ready") {
40652
41701
  reject(new Error("Redis is already connecting/connected"));
40653
41702
  return;
@@ -40726,7 +41775,7 @@ var require_Redis = __commonJS({
40726
41775
  }
40727
41776
  const connectionReadyHandler = function() {
40728
41777
  _this.removeListener("close", connectionCloseHandler);
40729
- resolve2();
41778
+ resolve3();
40730
41779
  };
40731
41780
  var connectionCloseHandler = function() {
40732
41781
  _this.removeListener("ready", connectionReadyHandler);
@@ -40820,10 +41869,10 @@ var require_Redis = __commonJS({
40820
41869
  monitor: true,
40821
41870
  lazyConnect: false
40822
41871
  });
40823
- return (0, standard_as_callback_1.default)(new Promise(function(resolve2, reject) {
41872
+ return (0, standard_as_callback_1.default)(new Promise(function(resolve3, reject) {
40824
41873
  monitorInstance.once("error", reject);
40825
41874
  monitorInstance.once("monitoring", function() {
40826
- resolve2(monitorInstance);
41875
+ resolve3(monitorInstance);
40827
41876
  });
40828
41877
  }), callback);
40829
41878
  }
@@ -41645,6 +42694,7 @@ async function runMenu() {
41645
42694
  const value = await Ee({
41646
42695
  message: "What now?",
41647
42696
  options: [
42697
+ { value: "init", label: "Initialize this project (migrate .env)", hint: "keynv init" },
41648
42698
  { value: "projects", label: "Projects" },
41649
42699
  { value: "secrets", label: "Secrets" },
41650
42700
  { value: "members", label: "Members" },
@@ -41683,7 +42733,10 @@ async function runMenu() {
41683
42733
  ye("Logged out.");
41684
42734
  return 0;
41685
42735
  }
41686
- if (choice === "projects") await runProjectsFlow(client);
42736
+ if (choice === "init") {
42737
+ const { runInitFlow: runInitFlow2 } = await Promise.resolve().then(() => (init_init(), init_exports));
42738
+ await runInitFlow2(client, { cwd: process.cwd(), dryRun: false, noScripts: false });
42739
+ } else if (choice === "projects") await runProjectsFlow(client);
41687
42740
  else if (choice === "secrets") await runSecretsFlow(client);
41688
42741
  else if (choice === "members") await runMembersFlow(client);
41689
42742
  else if (choice === "audit") await runAuditFlow(client);
@@ -43496,134 +44549,7 @@ var AuditVerifyCommand = class extends Command {
43496
44549
 
43497
44550
  // src/commands/exec.ts
43498
44551
  init_http();
43499
-
43500
- // src/exec/envFile.ts
43501
- init_dist();
43502
- var MAX_FILE_BYTES = 1e6;
43503
- var KEY_RE2 = /^[A-Za-z_][A-Za-z0-9_]*$/;
43504
- var ENV_FILE_BASENAME = ".keynv.env";
43505
- var EnvFileParseError = class extends Error {
43506
- constructor(file, line, reason) {
43507
- super(`${file}:${line}: ${reason}`);
43508
- this.file = file;
43509
- this.line = line;
43510
- this.reason = reason;
43511
- this.name = "EnvFileParseError";
43512
- }
43513
- file;
43514
- line;
43515
- reason;
43516
- };
43517
- var EnvFileNotFoundError = class extends Error {
43518
- constructor(path) {
43519
- super(`env file not found: ${path}`);
43520
- this.path = path;
43521
- this.name = "EnvFileNotFoundError";
43522
- }
43523
- path;
43524
- };
43525
- var EnvFileTooLargeError = class extends Error {
43526
- constructor(path, bytes) {
43527
- super(`env file ${path} is ${bytes} bytes (max ${MAX_FILE_BYTES})`);
43528
- this.path = path;
43529
- this.bytes = bytes;
43530
- this.name = "EnvFileTooLargeError";
43531
- }
43532
- path;
43533
- bytes;
43534
- };
43535
- function parseEnvFile(content, filename) {
43536
- const normalized = content.charCodeAt(0) === 65279 ? content.slice(1) : content;
43537
- const lines = normalized.split(/\r?\n/);
43538
- const entries = [];
43539
- for (let i = 0; i < lines.length; i++) {
43540
- const raw = lines[i] ?? "";
43541
- const lineNo = i + 1;
43542
- const trimmed = raw.trim();
43543
- if (trimmed.length === 0) continue;
43544
- if (trimmed.startsWith("#")) continue;
43545
- let body = trimmed;
43546
- if (body.startsWith("export ")) {
43547
- body = body.slice("export ".length).trimStart();
43548
- }
43549
- const eq = body.indexOf("=");
43550
- if (eq <= 0) {
43551
- throw new EnvFileParseError(filename, lineNo, "expected 'KEY=value'");
43552
- }
43553
- const name = body.slice(0, eq).trim();
43554
- if (!KEY_RE2.test(name)) {
43555
- throw new EnvFileParseError(
43556
- filename,
43557
- lineNo,
43558
- `invalid key '${name}' (must match /^[A-Za-z_][A-Za-z0-9_]*$/)`
43559
- );
43560
- }
43561
- let valueRaw = body.slice(eq + 1);
43562
- let value;
43563
- const valueLeading = valueRaw.replace(/^\s+/, "");
43564
- const firstCh = valueLeading.charAt(0);
43565
- if (firstCh === '"' || firstCh === "'") {
43566
- const close = valueLeading.lastIndexOf(firstCh);
43567
- if (close === 0) {
43568
- throw new EnvFileParseError(filename, lineNo, `unclosed ${firstCh} quote`);
43569
- }
43570
- const after = valueLeading.slice(close + 1).trim();
43571
- if (after.length > 0) {
43572
- throw new EnvFileParseError(
43573
- filename,
43574
- lineNo,
43575
- `unexpected content after closing ${firstCh}`
43576
- );
43577
- }
43578
- value = valueLeading.slice(1, close);
43579
- } else {
43580
- value = valueRaw.replace(/\s+$/, "");
43581
- value = value.replace(/^\s+/, "");
43582
- }
43583
- entries.push({
43584
- name,
43585
- value,
43586
- isAlias: parseAlias(value) !== null,
43587
- line: lineNo
43588
- });
43589
- }
43590
- return entries;
43591
- }
43592
- function findEnvFile(startDir) {
43593
- let dir = resolve(startDir);
43594
- for (let i = 0; i < 64; i++) {
43595
- const candidate = join(dir, ENV_FILE_BASENAME);
43596
- if (existsSync(candidate)) {
43597
- try {
43598
- if (statSync(candidate).isFile()) return candidate;
43599
- } catch {
43600
- }
43601
- }
43602
- const parent = dirname(dir);
43603
- if (parent === dir) return null;
43604
- dir = parent;
43605
- }
43606
- return null;
43607
- }
43608
- function loadEnvFile(opts) {
43609
- if (opts.disabled) return null;
43610
- const pickExplicit = opts.explicitPath ?? opts.envVarOverride;
43611
- let path = null;
43612
- if (pickExplicit !== void 0) {
43613
- path = isAbsolute(pickExplicit) ? pickExplicit : resolve(opts.cwd, pickExplicit);
43614
- if (!existsSync(path)) throw new EnvFileNotFoundError(path);
43615
- } else {
43616
- path = findEnvFile(opts.cwd);
43617
- }
43618
- if (path === null) return null;
43619
- const stat = statSync(path);
43620
- if (stat.size > MAX_FILE_BYTES) {
43621
- throw new EnvFileTooLargeError(path, stat.size);
43622
- }
43623
- const content = readFileSync(path, "utf8");
43624
- const entries = parseEnvFile(content, path);
43625
- return { path, entries };
43626
- }
44552
+ init_envFile();
43627
44553
 
43628
44554
  // src/exec/resolve.ts
43629
44555
  init_dist();
@@ -43984,14 +44910,14 @@ function spawnPrivileged(opts) {
43984
44910
  }, opts.timeoutS * 1e3);
43985
44911
  timer.unref();
43986
44912
  }
43987
- return new Promise((resolve2, reject) => {
44913
+ return new Promise((resolve3, reject) => {
43988
44914
  child.on("error", (err) => {
43989
44915
  if (timer) clearTimeout(timer);
43990
44916
  reject(err);
43991
44917
  });
43992
44918
  child.on("close", (code, signal) => {
43993
44919
  if (timer) clearTimeout(timer);
43994
- resolve2({
44920
+ resolve3({
43995
44921
  exitCode: code ?? 0,
43996
44922
  signal,
43997
44923
  durationMs: Date.now() - startedAt
@@ -44209,552 +45135,67 @@ function signalNumber(sig) {
44209
45135
  return map[sig] ?? null;
44210
45136
  }
44211
45137
 
44212
- // ../../packages/integrations/dist/file-deny-list.js
44213
- var KEYNV_FILE_DENY_PATTERNS = [
44214
- // dotenv variants
44215
- ".env",
44216
- ".env.*",
44217
- "*.env",
44218
- "**/.env",
44219
- "**/.env.*",
44220
- "**/*.env",
44221
- // raw key material
44222
- "*.pem",
44223
- "*.key",
44224
- "*.p12",
44225
- "*.pfx",
44226
- "**/*.pem",
44227
- "**/*.key",
44228
- "**/*.p12",
44229
- "**/*.pfx",
44230
- // SSH private keys
44231
- "id_rsa",
44232
- "id_rsa.*",
44233
- "id_ed25519",
44234
- "id_ed25519.*",
44235
- "id_ecdsa",
44236
- "id_ecdsa.*",
44237
- "**/id_rsa",
44238
- "**/id_rsa.*",
44239
- "**/id_ed25519",
44240
- "**/id_ed25519.*",
44241
- "**/id_ecdsa",
44242
- "**/id_ecdsa.*",
44243
- // Generic credential containers
44244
- "*credentials*",
44245
- "*.kdbx",
44246
- "**/*credentials*",
44247
- "**/*.kdbx",
44248
- // Cloud provider credential paths (typically under ~/, but also
44249
- // appear at project roots in dev setups)
44250
- ".aws/credentials",
44251
- "**/.aws/credentials",
44252
- ".aws/config",
44253
- "**/.aws/config",
44254
- ".gcp/**/key.json",
44255
- "**/.gcp/**/key.json",
44256
- "**/google-services.json",
44257
- "**/service-account*.json",
44258
- ".azure/**",
44259
- "**/.azure/**",
44260
- ".kube/config",
44261
- "**/.kube/config",
44262
- ".docker/config.json",
44263
- "**/.docker/config.json"
44264
- ];
44265
- var KEYNV_FILE_ALLOW_PATTERNS = [
44266
- ".keynv.env",
44267
- "**/.keynv.env"
44268
- ];
44269
- function gitignoreBlock() {
44270
- return [...KEYNV_FILE_DENY_PATTERNS, ...KEYNV_FILE_ALLOW_PATTERNS.map((p2) => `!${p2}`)];
44271
- }
44272
- var KEYNV_BEGIN = "# >>> keynv >>>";
44273
- var KEYNV_END = "# <<< keynv <<<";
44274
- function readJsonOrEmpty(path) {
44275
- if (!existsSync(path))
44276
- return {};
44277
- try {
44278
- return JSON.parse(readFileSync(path, "utf8"));
44279
- } catch {
44280
- return {};
44281
- }
44282
- }
44283
- function ensureDir(path) {
44284
- const dir = dirname(path);
44285
- if (!existsSync(dir))
44286
- mkdirSync(dir, { recursive: true });
44287
- }
44288
- function writeJson(path, value) {
44289
- ensureDir(path);
44290
- writeFileSync(path, `${JSON.stringify(value, null, 2)}
44291
- `, { mode: 420 });
44292
- }
44293
- function ensureKeynvBlock(path, lines) {
44294
- const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
44295
- const marked = existing.split("\n");
44296
- const beginIdx = marked.findIndex((l) => l.trim() === KEYNV_BEGIN);
44297
- const endIdx = marked.findIndex((l) => l.trim() === KEYNV_END);
44298
- const block = [KEYNV_BEGIN, ...lines, KEYNV_END];
44299
- let next;
44300
- if (beginIdx >= 0 && endIdx > beginIdx) {
44301
- next = [...marked.slice(0, beginIdx), ...block, ...marked.slice(endIdx + 1)];
44302
- } else {
44303
- next = existing.length > 0 && !existing.endsWith("\n") ? [...marked, "", ...block] : [...marked[marked.length - 1] === "" ? marked.slice(0, -1) : marked, ...block, ""];
44304
- }
44305
- const out = next.join("\n");
44306
- if (out === existing)
44307
- return false;
44308
- ensureDir(path);
44309
- writeFileSync(path, out, { mode: 420 });
44310
- return true;
44311
- }
44312
- function removeKeynvBlock(path) {
44313
- if (!existsSync(path))
44314
- return false;
44315
- const lines = readFileSync(path, "utf8").split("\n");
44316
- const beginIdx = lines.findIndex((l) => l.trim() === KEYNV_BEGIN);
44317
- const endIdx = lines.findIndex((l) => l.trim() === KEYNV_END);
44318
- if (beginIdx < 0 || endIdx <= beginIdx)
44319
- return false;
44320
- const next = [...lines.slice(0, beginIdx), ...lines.slice(endIdx + 1)];
44321
- while (next.length > 0 && next[next.length - 1] === "")
44322
- next.pop();
44323
- writeFileSync(path, `${next.join("\n")}${next.length ? "\n" : ""}`, { mode: 420 });
44324
- return true;
44325
- }
44326
-
44327
- // ../../packages/integrations/dist/aider.js
44328
- var AIDER_IGNORE_REL = ".aiderignore";
44329
- var aider = {
44330
- name: "aider",
44331
- displayName: "Aider",
44332
- async detect(opts = {}) {
44333
- const cwd = opts.cwd ?? process.cwd();
44334
- return existsSync(join(cwd, AIDER_IGNORE_REL)) || existsSync(join(cwd, ".aider.conf.yml")) || existsSync(join(homedir(), ".aider.conf.yml"));
44335
- },
44336
- async install(opts = {}) {
44337
- const cwd = opts.cwd ?? process.cwd();
44338
- const path = join(cwd, AIDER_IGNORE_REL);
44339
- if (opts.dryRun) {
44340
- return {
44341
- agent: "aider",
44342
- applied: false,
44343
- changes: [{ path, action: "update" }],
44344
- summary: `[dry-run] would write ${path}`
44345
- };
44346
- }
44347
- const changed = ensureKeynvBlock(path, gitignoreBlock());
44348
- return {
44349
- agent: "aider",
44350
- applied: true,
44351
- changes: [{ path, action: changed ? "update" : "skip" }],
44352
- summary: changed ? `wrote ${KEYNV_FILE_DENY_PATTERNS.length} patterns to ${AIDER_IGNORE_REL}` : "unchanged"
44353
- };
44354
- },
44355
- async uninstall(opts = {}) {
44356
- const cwd = opts.cwd ?? process.cwd();
44357
- const path = join(cwd, AIDER_IGNORE_REL);
44358
- if (opts.dryRun) {
44359
- return {
44360
- agent: "aider",
44361
- applied: false,
44362
- changes: [{ path, action: "update" }],
44363
- summary: `[dry-run] would remove keynv block from ${AIDER_IGNORE_REL}`
44364
- };
44365
- }
44366
- const changed = removeKeynvBlock(path);
44367
- return {
44368
- agent: "aider",
44369
- applied: true,
44370
- changes: [{ path, action: changed ? "update" : "skip" }],
44371
- summary: changed ? "removed keynv block" : "no keynv block found"
44372
- };
44373
- }
44374
- };
44375
- var SETTINGS_PATH_REL = ".claude/settings.local.json";
44376
- var KEYNV_DENY_TAG = "__keynv_managed__";
44377
- function denyEntriesForReadTool() {
44378
- return KEYNV_FILE_DENY_PATTERNS.map((p2) => `Read(${p2})`);
44379
- }
44380
- function allowEntriesForReadTool() {
44381
- return KEYNV_FILE_ALLOW_PATTERNS.map((p2) => `Read(${p2})`);
44382
- }
44383
- var claudeCode = {
44384
- name: "claude-code",
44385
- displayName: "Claude Code",
44386
- async detect(opts = {}) {
44387
- const cwd = opts.cwd ?? process.cwd();
44388
- return existsSync(join(cwd, ".claude"));
44389
- },
44390
- async install(opts = {}) {
44391
- const cwd = opts.cwd ?? process.cwd();
44392
- const path = join(cwd, SETTINGS_PATH_REL);
44393
- const settings = readJsonOrEmpty(path);
44394
- const denyToAdd = denyEntriesForReadTool();
44395
- const allowToAdd = allowEntriesForReadTool();
44396
- const existingDeny = new Set(settings.permissions?.deny ?? []);
44397
- const existingAllow = new Set(settings.permissions?.allow ?? []);
44398
- const newlyAdded = [];
44399
- for (const entry2 of denyToAdd) {
44400
- if (!existingDeny.has(entry2)) {
44401
- existingDeny.add(entry2);
44402
- newlyAdded.push(entry2);
44403
- }
44404
- }
44405
- for (const entry2 of allowToAdd) {
44406
- if (!existingAllow.has(entry2)) {
44407
- existingAllow.add(entry2);
44408
- }
44409
- }
44410
- settings.permissions = {
44411
- ...settings.permissions,
44412
- allow: [...existingAllow].sort((a, b2) => a.localeCompare(b2)),
44413
- deny: [...existingDeny].sort((a, b2) => a.localeCompare(b2))
44414
- };
44415
- settings.hooks = settings.hooks ?? {};
44416
- const post = settings.hooks["PostToolUse"] ?? [];
44417
- const alreadyHooked = post.some((entry2) => (entry2.hooks ?? []).some((h2) => h2.command?.includes("keynv redact-stream")));
44418
- if (!alreadyHooked) {
44419
- post.push({
44420
- matcher: "Bash",
44421
- hooks: [{ type: "command", command: "keynv redact-stream" }]
44422
- });
44423
- settings.hooks["PostToolUse"] = post;
44424
- }
44425
- settings[KEYNV_DENY_TAG] = {
44426
- deny_added: denyToAdd,
44427
- allow_added: allowToAdd,
44428
- hook_added: true
44429
- };
44430
- const changes = [];
44431
- if (opts.dryRun) {
44432
- changes.push({
44433
- path,
44434
- action: existsSync(path) ? "update" : "create",
44435
- note: `would add ${newlyAdded.length} deny entries${alreadyHooked ? "" : " + PostToolUse(Bash) \u2192 keynv redact-stream"}`
44436
- });
44437
- } else {
44438
- writeJson(path, settings);
44439
- changes.push({
44440
- path,
44441
- action: existsSync(path) ? "update" : "create",
44442
- note: `${newlyAdded.length} new deny entries${alreadyHooked ? "" : " + redact hook"}`
44443
- });
44444
- }
44445
- return {
44446
- agent: "claude-code",
44447
- applied: !opts.dryRun,
44448
- changes,
44449
- summary: opts.dryRun ? `[dry-run] ${path}: would add ${newlyAdded.length} permission denies + redact hook` : `installed: ${newlyAdded.length} new denies; redact hook ${alreadyHooked ? "kept" : "added"}.`
44450
- };
44451
- },
44452
- async uninstall(opts = {}) {
44453
- const cwd = opts.cwd ?? process.cwd();
44454
- const path = join(cwd, SETTINGS_PATH_REL);
44455
- if (!existsSync(path)) {
44456
- return {
44457
- agent: "claude-code",
44458
- applied: false,
44459
- changes: [{ path, action: "skip", note: "no settings file" }],
44460
- summary: "nothing to uninstall"
44461
- };
44462
- }
44463
- const settings = readJsonOrEmpty(path);
44464
- const tracker = settings[KEYNV_DENY_TAG];
44465
- const removedDeny = [];
44466
- const permissions = settings.permissions;
44467
- if (tracker?.deny_added && permissions && Array.isArray(permissions.deny)) {
44468
- const remove = new Set(tracker.deny_added);
44469
- const before = permissions.deny;
44470
- permissions.deny = before.filter((entry2) => {
44471
- if (remove.has(entry2)) {
44472
- removedDeny.push(entry2);
44473
- return false;
44474
- }
44475
- return true;
44476
- });
44477
- if (permissions.deny.length === 0)
44478
- delete permissions.deny;
44479
- }
44480
- if (tracker?.allow_added && permissions && Array.isArray(permissions.allow)) {
44481
- const remove = new Set(tracker.allow_added);
44482
- permissions.allow = permissions.allow.filter((entry2) => !remove.has(entry2));
44483
- if (permissions.allow.length === 0)
44484
- delete permissions.allow;
44485
- }
44486
- const hooks = settings.hooks;
44487
- if (tracker?.hook_added && hooks && Array.isArray(hooks.PostToolUse)) {
44488
- const filtered = hooks.PostToolUse.filter((entry2) => !(entry2.hooks ?? []).some((h2) => h2.command?.includes("keynv redact-stream")));
44489
- hooks.PostToolUse = filtered;
44490
- if (filtered.length === 0)
44491
- delete hooks.PostToolUse;
44492
- }
44493
- delete settings[KEYNV_DENY_TAG];
44494
- if (opts.dryRun) {
44495
- return {
44496
- agent: "claude-code",
44497
- applied: false,
44498
- changes: [
44499
- { path, action: "update", note: `would remove ${removedDeny.length} denies + hook` }
44500
- ],
44501
- summary: `[dry-run] would remove ${removedDeny.length} denies`
44502
- };
44503
- }
44504
- writeJson(path, settings);
44505
- return {
44506
- agent: "claude-code",
44507
- applied: true,
44508
- changes: [{ path, action: "update" }],
44509
- summary: `removed ${removedDeny.length} denies + hook`
44510
- };
44511
- }
44512
- };
44513
- var CODEX_IGNORE_REL = ".codex/.deny";
44514
- var codexCli = {
44515
- name: "codex",
44516
- displayName: "Codex CLI",
44517
- async detect(opts = {}) {
44518
- const cwd = opts.cwd ?? process.cwd();
44519
- return existsSync(join(cwd, ".codex")) || existsSync(join(homedir(), ".codex"));
44520
- },
44521
- async install(opts = {}) {
44522
- const cwd = opts.cwd ?? process.cwd();
44523
- const path = join(cwd, CODEX_IGNORE_REL);
44524
- if (opts.dryRun) {
44525
- return {
44526
- agent: "codex",
44527
- applied: false,
44528
- changes: [{ path, action: "update" }],
44529
- summary: `[dry-run] would write ${CODEX_IGNORE_REL}`
44530
- };
44531
- }
44532
- const changed = ensureKeynvBlock(path, gitignoreBlock());
44533
- return {
44534
- agent: "codex",
44535
- applied: true,
44536
- changes: [{ path, action: changed ? "update" : "skip" }],
44537
- summary: changed ? `wrote ${CODEX_IGNORE_REL}; consider adding 'alias codex="keynv exec -- codex"' to your shell rc` : "unchanged"
44538
- };
44539
- },
44540
- async uninstall(opts = {}) {
44541
- const cwd = opts.cwd ?? process.cwd();
44542
- const path = join(cwd, CODEX_IGNORE_REL);
44543
- if (opts.dryRun) {
44544
- return {
44545
- agent: "codex",
44546
- applied: false,
44547
- changes: [{ path, action: "update" }],
44548
- summary: `[dry-run] would remove keynv block from ${CODEX_IGNORE_REL}`
44549
- };
44550
- }
44551
- const changed = removeKeynvBlock(path);
44552
- return {
44553
- agent: "codex",
44554
- applied: true,
44555
- changes: [{ path, action: changed ? "update" : "skip" }],
44556
- summary: changed ? "removed keynv block" : "no keynv block found"
44557
- };
44558
- }
44559
- };
44560
- var CURSOR_IGNORE_REL = ".cursorignore";
44561
- var cursor = {
44562
- name: "cursor",
44563
- displayName: "Cursor",
44564
- async detect(opts = {}) {
44565
- const cwd = opts.cwd ?? process.cwd();
44566
- return existsSync(join(cwd, ".cursor")) || existsSync(join(cwd, ".cursorrules"));
44567
- },
44568
- async install(opts = {}) {
44569
- const cwd = opts.cwd ?? process.cwd();
44570
- const path = join(cwd, CURSOR_IGNORE_REL);
44571
- if (opts.dryRun) {
44572
- return {
44573
- agent: "cursor",
44574
- applied: false,
44575
- changes: [
44576
- {
44577
- path,
44578
- action: "update",
44579
- note: `would add ${KEYNV_FILE_DENY_PATTERNS.length} ignore patterns`
44580
- }
44581
- ],
44582
- summary: `[dry-run] would write ${path}`
44583
- };
44584
- }
44585
- const changed = ensureKeynvBlock(path, gitignoreBlock());
44586
- return {
44587
- agent: "cursor",
44588
- applied: true,
44589
- changes: [{ path, action: changed ? "update" : "skip" }],
44590
- summary: changed ? `wrote ${KEYNV_FILE_DENY_PATTERNS.length} patterns to ${CURSOR_IGNORE_REL}` : "unchanged"
44591
- };
44592
- },
44593
- async uninstall(opts = {}) {
44594
- const cwd = opts.cwd ?? process.cwd();
44595
- const path = join(cwd, CURSOR_IGNORE_REL);
44596
- if (opts.dryRun) {
44597
- return {
44598
- agent: "cursor",
44599
- applied: false,
44600
- changes: [{ path, action: "update" }],
44601
- summary: `[dry-run] would remove keynv block from ${CURSOR_IGNORE_REL}`
44602
- };
44603
- }
44604
- const changed = removeKeynvBlock(path);
44605
- return {
44606
- agent: "cursor",
44607
- applied: true,
44608
- changes: [{ path, action: changed ? "update" : "skip" }],
44609
- summary: changed ? "removed keynv block" : "no keynv block found"
44610
- };
44611
- }
44612
- };
44613
- var OPENCODE_IGNORE_REL = ".opencode/.keynv-deny";
44614
- var opencode = {
44615
- name: "opencode",
44616
- displayName: "OpenCode",
44617
- async detect(opts = {}) {
44618
- const cwd = opts.cwd ?? process.cwd();
44619
- return existsSync(join(cwd, ".opencode")) || existsSync(join(homedir(), ".opencode"));
44620
- },
44621
- async install(opts = {}) {
44622
- const cwd = opts.cwd ?? process.cwd();
44623
- const path = join(cwd, OPENCODE_IGNORE_REL);
44624
- if (opts.dryRun) {
44625
- return {
44626
- agent: "opencode",
44627
- applied: false,
44628
- changes: [{ path, action: "update" }],
44629
- summary: `[dry-run] would write ${OPENCODE_IGNORE_REL}`
44630
- };
44631
- }
44632
- const changed = ensureKeynvBlock(path, gitignoreBlock());
44633
- return {
44634
- agent: "opencode",
44635
- applied: true,
44636
- changes: [{ path, action: changed ? "update" : "skip" }],
44637
- summary: changed ? `wrote ${OPENCODE_IGNORE_REL}; full hook/MCP integration TBD` : "unchanged"
44638
- };
44639
- },
44640
- async uninstall(opts = {}) {
44641
- const cwd = opts.cwd ?? process.cwd();
44642
- const path = join(cwd, OPENCODE_IGNORE_REL);
44643
- if (opts.dryRun) {
44644
- return {
44645
- agent: "opencode",
44646
- applied: false,
44647
- changes: [{ path, action: "update" }],
44648
- summary: `[dry-run] would remove keynv block from ${OPENCODE_IGNORE_REL}`
44649
- };
44650
- }
44651
- const changed = removeKeynvBlock(path);
44652
- return {
44653
- agent: "opencode",
44654
- applied: true,
44655
- changes: [{ path, action: changed ? "update" : "skip" }],
44656
- summary: changed ? "removed keynv block" : "no keynv block found"
44657
- };
44658
- }
44659
- };
44660
-
44661
- // ../../packages/integrations/dist/index.js
44662
- var REGISTRY = [claudeCode, cursor, opencode, codexCli, aider];
44663
- function findIntegration(name) {
44664
- return REGISTRY.find((i) => i.name === name) ?? null;
44665
- }
44666
-
44667
- // src/commands/install.ts
44668
- function printReport(stdout, report) {
44669
- stdout.write(`[${report.agent}] ${report.summary}
44670
- `);
44671
- for (const change of report.changes) {
44672
- const note = change.note ? `: ${change.note}` : "";
44673
- stdout.write(` ${change.action.padEnd(7)} ${change.path}${note}
44674
- `);
44675
- }
44676
- }
44677
- var InstallCommand = class extends Command {
44678
- static paths = [["install"]];
45138
+ // src/commands/init.ts
45139
+ init_http();
45140
+ init_tty();
45141
+ init_init();
45142
+ init_cancel();
45143
+ var InitCommand = class extends Command {
45144
+ static paths = [["init"]];
44679
45145
  static usage = Command.Usage({
44680
- description: "Install per-agent file deny lists, hooks, and config templates.",
45146
+ description: "Migrate an existing project from .env to keynv.",
44681
45147
  details: `
44682
- Each integration writes a small, idempotent set of files. Re-running
44683
- yields the same state. Use --dry-run to preview changes before they
44684
- land.
45148
+ Walks the current directory's .env files, prompts you to mark which
45149
+ keys are real secrets, uploads those to the keynv vault, writes a
45150
+ .keynv.env file with alias references, and (optionally) wraps your
45151
+ package.json scripts with \`keynv exec\`.
45152
+
45153
+ Safe to re-run: existing .keynv.env entries are preserved; new
45154
+ entries are appended below a marker.
45155
+
45156
+ Requires an interactive terminal (clack TUI). For scripted
45157
+ migration, use the lower-level \`keynv project\` and \`keynv secret\`
45158
+ commands directly.
44685
45159
  `,
44686
45160
  examples: [
44687
- ["Install Claude Code", "$0 install claude-code"],
44688
- ["Preview the change", "$0 install claude-code --dry-run"],
44689
- ["Install all detected", "$0 install --all"],
44690
- ["List supported integrations", "$0 install list"]
45161
+ ["Walk the current project", "$0 init"],
45162
+ ["Preview without writing or uploading", "$0 init --dry-run"],
45163
+ ["Skip the package.json script-wrapping step", "$0 init --no-scripts"]
44691
45164
  ]
44692
45165
  });
44693
- agent = options_exports.String({ required: false });
44694
- dryRun = options_exports.Boolean("--dry-run", false);
44695
- all = options_exports.Boolean("--all", false);
45166
+ dryRun = options_exports.Boolean("--dry-run", false, {
45167
+ description: "Show what would be done without writing files or uploading secrets."
45168
+ });
45169
+ noScripts = options_exports.Boolean("--no-scripts", false, {
45170
+ description: "Skip the package.json script-wrapping step."
45171
+ });
44696
45172
  async execute() {
44697
- if (this.agent === "list") {
44698
- this.context.stdout.write("Supported integrations:\n");
44699
- for (const i of REGISTRY) {
44700
- this.context.stdout.write(` ${i.name.padEnd(14)} ${i.displayName}
44701
- `);
44702
- }
44703
- return 0;
44704
- }
44705
- if (this.all) {
44706
- const cwd = process.cwd();
44707
- let any = false;
44708
- for (const integration2 of REGISTRY) {
44709
- const detected = await integration2.detect({ cwd });
44710
- if (!detected) continue;
44711
- any = true;
44712
- const report2 = await integration2.install({ cwd, dryRun: this.dryRun });
44713
- printReport(this.context.stdout, report2);
44714
- }
44715
- if (!any) {
44716
- this.context.stdout.write("no integrations detected in this directory\n");
44717
- }
44718
- return 0;
44719
- }
44720
- if (!this.agent) {
45173
+ if (!isInteractive()) {
44721
45174
  this.context.stderr.write(
44722
- "keynv: usage: keynv install <agent> | keynv install --all | keynv install list\n"
45175
+ "keynv init requires an interactive terminal. Use the lower-level commands (`keynv project`, `keynv secret`) for scripted setup.\n"
44723
45176
  );
44724
- return 2;
45177
+ return 1;
44725
45178
  }
44726
- const integration = findIntegration(this.agent);
44727
- if (!integration) {
44728
- this.context.stderr.write(
44729
- `keynv: unknown integration '${this.agent}'. Try \`keynv install list\`.
44730
- `
44731
- );
45179
+ const client = new ApiClient();
45180
+ await client.ensureHydrated();
45181
+ if (!client.isLoggedIn) {
45182
+ this.context.stderr.write("keynv: not logged in. Run `keynv login` first.\n");
44732
45183
  return 1;
44733
45184
  }
44734
- const report = await integration.install({ cwd: process.cwd(), dryRun: this.dryRun });
44735
- printReport(this.context.stdout, report);
44736
- return 0;
44737
- }
44738
- };
44739
- var UninstallCommand = class extends Command {
44740
- static paths = [["uninstall"]];
44741
- static usage = Command.Usage({
44742
- description: "Remove keynv-managed entries written by an earlier `keynv install`."
44743
- });
44744
- agent = options_exports.String();
44745
- dryRun = options_exports.Boolean("--dry-run", false);
44746
- async execute() {
44747
- const integration = findIntegration(this.agent);
44748
- if (!integration) {
44749
- this.context.stderr.write(
44750
- `keynv: unknown integration '${this.agent}'. Try \`keynv install list\`.
44751
- `
44752
- );
45185
+ try {
45186
+ const outcome = await runInitFlow(client, {
45187
+ cwd: process.cwd(),
45188
+ dryRun: this.dryRun,
45189
+ noScripts: this.noScripts
45190
+ });
45191
+ return outcome.exitCode;
45192
+ } catch (err) {
45193
+ if (err instanceof UserCancelled) return 130;
45194
+ const e2 = err;
45195
+ this.context.stderr.write(`keynv: ${e2.message}
45196
+ `);
44753
45197
  return 1;
44754
45198
  }
44755
- const report = await integration.uninstall({ cwd: process.cwd(), dryRun: this.dryRun });
44756
- printReport(this.context.stdout, report);
44757
- return 0;
44758
45199
  }
44759
45200
  };
44760
45201
 
@@ -44770,7 +45211,7 @@ async function promptHidden(prompt) {
44770
45211
  process.stdin.setRawMode(true);
44771
45212
  process.stdin.resume();
44772
45213
  process.stdin.setEncoding("utf8");
44773
- return new Promise((resolve2) => {
45214
+ return new Promise((resolve3) => {
44774
45215
  let buf = "";
44775
45216
  const onData = (chunk) => {
44776
45217
  for (const ch of chunk) {
@@ -44779,7 +45220,7 @@ async function promptHidden(prompt) {
44779
45220
  process.stdin.pause();
44780
45221
  process.stdin.removeListener("data", onData);
44781
45222
  process.stdout.write("\n");
44782
- resolve2(buf);
45223
+ resolve3(buf);
44783
45224
  return;
44784
45225
  }
44785
45226
  if (ch === "") {
@@ -44797,10 +45238,10 @@ async function promptHidden(prompt) {
44797
45238
  }
44798
45239
  async function promptLine(prompt) {
44799
45240
  const rl = createInterface({ input: process.stdin, output: process.stdout });
44800
- return new Promise((resolve2) => {
45241
+ return new Promise((resolve3) => {
44801
45242
  rl.question(prompt, (answer) => {
44802
45243
  rl.close();
44803
- resolve2(answer.trim());
45244
+ resolve3(answer.trim());
44804
45245
  });
44805
45246
  });
44806
45247
  }
@@ -45191,9 +45632,9 @@ streaming-mode limitation in @keynv/redactor).
45191
45632
  `
45192
45633
  });
45193
45634
  async execute() {
45194
- return new Promise((resolve2, reject) => {
45635
+ return new Promise((resolve3, reject) => {
45195
45636
  const transform = createRedactStream();
45196
- this.context.stdin.pipe(transform).pipe(this.context.stdout).on("error", reject).on("finish", () => resolve2(0));
45637
+ this.context.stdin.pipe(transform).pipe(this.context.stdout).on("error", reject).on("finish", () => resolve3(0));
45197
45638
  this.context.stdin.on("error", reject);
45198
45639
  });
45199
45640
  }
@@ -45683,7 +46124,7 @@ var sshTester = {
45683
46124
  async test(secret, target) {
45684
46125
  const start = Date.now();
45685
46126
  const { Client: Client2 } = await import('ssh2');
45686
- return new Promise((resolve2) => {
46127
+ return new Promise((resolve3) => {
45687
46128
  const client = new Client2();
45688
46129
  let settled = false;
45689
46130
  const settle = (result) => {
@@ -45694,7 +46135,7 @@ var sshTester = {
45694
46135
  client.end();
45695
46136
  } catch {
45696
46137
  }
45697
- resolve2(result);
46138
+ resolve3(result);
45698
46139
  };
45699
46140
  client.once("ready", () => {
45700
46141
  client.exec("true", (err, stream) => {
@@ -45760,12 +46201,12 @@ function sanitizeResult(result, secret) {
45760
46201
 
45761
46202
  // ../../packages/testers/dist/run.js
45762
46203
  function withTimeout(promise, ms) {
45763
- return new Promise((resolve2, reject) => {
46204
+ return new Promise((resolve3, reject) => {
45764
46205
  const t = setTimeout(() => reject(new Error(`tester timed out after ${ms}ms`)), ms);
45765
46206
  t.unref();
45766
46207
  promise.then((v2) => {
45767
46208
  clearTimeout(t);
45768
- resolve2(v2);
46209
+ resolve3(v2);
45769
46210
  }, (err) => {
45770
46211
  clearTimeout(t);
45771
46212
  reject(err);
@@ -45999,10 +46440,9 @@ cli.register(MemberListCommand);
45999
46440
  cli.register(AuditListCommand);
46000
46441
  cli.register(AuditVerifyCommand);
46001
46442
  cli.register(ExecCommand);
46443
+ cli.register(InitCommand);
46002
46444
  cli.register(RedactCommand);
46003
46445
  cli.register(RedactStreamCommand);
46004
- cli.register(InstallCommand);
46005
- cli.register(UninstallCommand);
46006
46446
  cli.register(TestCommand);
46007
46447
  cli.register(UICommand);
46008
46448
  var argv = process.argv.slice(2);