@keynv/cli 0.1.0-rc.12 → 0.1.0-rc.14

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,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module';
3
3
  import { randomBytes } from 'crypto';
4
- import { readFileSync, existsSync, statSync, writeFileSync, unlinkSync, mkdirSync, rmSync, readdirSync } from 'fs';
4
+ import { readFileSync, writeFileSync, unlinkSync, existsSync, statSync, readdirSync, mkdirSync, rmSync } from 'fs';
5
5
  import { hostname, platform, homedir } from 'os';
6
- import { relative, isAbsolute, resolve, join, dirname, basename } from 'path';
6
+ import * as nodePath from 'path';
7
+ import { relative, join, isAbsolute, resolve, dirname, basename } from 'path';
7
8
  import { Entry } from '@napi-rs/keyring';
8
9
  import { styleText } from 'util';
9
10
  import j2, { stdin, stdout } from 'process';
@@ -301,16 +302,16 @@ var require_lib = __commonJS({
301
302
  }
302
303
  });
303
304
  }
304
- function isArray(spec, { delimiter } = {}) {
305
+ function isArray(spec, { delimiter: delimiter2 } = {}) {
305
306
  return makeValidator({
306
307
  test: (value, state) => {
307
308
  var _a;
308
309
  const originalValue = value;
309
- if (typeof value === `string` && typeof delimiter !== `undefined`) {
310
+ if (typeof value === `string` && typeof delimiter2 !== `undefined`) {
310
311
  if (typeof (state === null || state === void 0 ? void 0 : state.coercions) !== `undefined`) {
311
312
  if (typeof (state === null || state === void 0 ? void 0 : state.coercion) === `undefined`)
312
313
  return pushError(state, `Unbound coercion result`);
313
- value = value.split(delimiter);
314
+ value = value.split(delimiter2);
314
315
  }
315
316
  }
316
317
  if (!Array.isArray(value))
@@ -328,8 +329,8 @@ var require_lib = __commonJS({
328
329
  }
329
330
  });
330
331
  }
331
- function isSet(spec, { delimiter } = {}) {
332
- const isArrayValidator = isArray(spec, { delimiter });
332
+ function isSet(spec, { delimiter: delimiter2 } = {}) {
333
+ const isArrayValidator = isArray(spec, { delimiter: delimiter2 });
333
334
  return makeValidator({
334
335
  test: (value, state) => {
335
336
  var _a, _b;
@@ -420,16 +421,16 @@ var require_lib = __commonJS({
420
421
  }
421
422
  });
422
423
  }
423
- function isTuple(spec, { delimiter } = {}) {
424
+ function isTuple(spec, { delimiter: delimiter2 } = {}) {
424
425
  const lengthValidator = hasExactLength(spec.length);
425
426
  return makeValidator({
426
427
  test: (value, state) => {
427
428
  var _a;
428
- if (typeof value === `string` && typeof delimiter !== `undefined`) {
429
+ if (typeof value === `string` && typeof delimiter2 !== `undefined`) {
429
430
  if (typeof (state === null || state === void 0 ? void 0 : state.coercions) !== `undefined`) {
430
431
  if (typeof (state === null || state === void 0 ? void 0 : state.coercion) === `undefined`)
431
432
  return pushError(state, `Unbound coercion result`);
432
- value = value.split(delimiter);
433
+ value = value.split(delimiter2);
433
434
  state.coercions.push([(_a = state.p) !== null && _a !== void 0 ? _a : `.`, state.coercion.bind(null, value)]);
434
435
  }
435
436
  }
@@ -1056,7 +1057,7 @@ var require_lib = __commonJS({
1056
1057
  var VERSION, AGENT;
1057
1058
  var init_version = __esm({
1058
1059
  "src/version.ts"() {
1059
- VERSION = "0.1.0-rc.12" ;
1060
+ VERSION = "0.1.0-rc.14" ;
1060
1061
  AGENT = `keynv-cli/${VERSION}`;
1061
1062
  }
1062
1063
  });
@@ -5599,6 +5600,9 @@ var init_store = __esm({
5599
5600
  });
5600
5601
 
5601
5602
  // src/client/http.ts
5603
+ function isClientError(err) {
5604
+ return err instanceof Error && typeof err.status === "number";
5605
+ }
5602
5606
  function clientError(status, code, message, details) {
5603
5607
  const err = Object.assign(new Error(message), { status, code, details });
5604
5608
  return err;
@@ -5653,7 +5657,16 @@ var init_http = __esm({
5653
5657
  return this.creds;
5654
5658
  }
5655
5659
  async ensureHydrated() {
5656
- if (this.hydrated) await this.hydrated;
5660
+ if (this.hydrated) {
5661
+ try {
5662
+ await this.hydrated;
5663
+ } catch (err) {
5664
+ process.stderr.write(
5665
+ `${err instanceof Error ? err.message : `keynv: credential load failed \u2014 ${String(err)}`}
5666
+ `
5667
+ );
5668
+ }
5669
+ }
5657
5670
  }
5658
5671
  async setCredentials(creds) {
5659
5672
  this.creds = creds;
@@ -5675,21 +5688,40 @@ var init_http = __esm({
5675
5688
  headers.authorization = `Bearer ${this.creds.access_token}`;
5676
5689
  }
5677
5690
  const url = this.creds ? buildUrl(this.creds.server_url, path, opts.query) : path;
5678
- let res = await fetch(url, {
5679
- method: opts.method ?? "GET",
5680
- headers,
5681
- ...opts.body !== void 0 ? { body: JSON.stringify(opts.body) } : {}
5682
- });
5691
+ let res;
5692
+ try {
5693
+ res = await fetch(url, {
5694
+ method: opts.method ?? "GET",
5695
+ headers,
5696
+ ...opts.body !== void 0 ? { body: JSON.stringify(opts.body) } : {}
5697
+ });
5698
+ } catch (err) {
5699
+ const cause = err instanceof Error ? err.message : String(err);
5700
+ const serverUrl = this.creds?.server_url ?? url;
5701
+ throw new Error(
5702
+ `keynv: cannot reach server '${serverUrl}' \u2014 ${cause}
5703
+ Check the server is running: curl ${serverUrl}/v1/health`
5704
+ );
5705
+ }
5683
5706
  if (res.status === 401 && this.creds && opts.authed !== false) {
5684
5707
  const refreshed = await tryRefresh(this.creds);
5685
5708
  if (refreshed) {
5686
5709
  this.creds = refreshed;
5687
5710
  headers.authorization = `Bearer ${refreshed.access_token}`;
5688
- res = await fetch(url, {
5689
- method: opts.method ?? "GET",
5690
- headers,
5691
- ...opts.body !== void 0 ? { body: JSON.stringify(opts.body) } : {}
5692
- });
5711
+ try {
5712
+ res = await fetch(url, {
5713
+ method: opts.method ?? "GET",
5714
+ headers,
5715
+ ...opts.body !== void 0 ? { body: JSON.stringify(opts.body) } : {}
5716
+ });
5717
+ } catch (err) {
5718
+ const cause = err instanceof Error ? err.message : String(err);
5719
+ const serverUrl = this.creds?.server_url ?? url;
5720
+ throw new Error(
5721
+ `keynv: cannot reach server '${serverUrl}' \u2014 ${cause}
5722
+ Check the server is running: curl ${serverUrl}/v1/health`
5723
+ );
5724
+ }
5693
5725
  }
5694
5726
  }
5695
5727
  if (res.status === 204) return void 0;
@@ -5728,8 +5760,23 @@ function fmtError(err) {
5728
5760
  const status = err.status ? ` (${err.status})` : "";
5729
5761
  return `keynv:${code}${status} ${err.message}`;
5730
5762
  }
5763
+ function handleExecError(stderr, err) {
5764
+ if (isClientError(err)) {
5765
+ const code = err.code ? `[${err.code}] ` : "";
5766
+ stderr.write(`keynv: ${code}${err.message}
5767
+ `);
5768
+ } else if (err instanceof Error) {
5769
+ stderr.write(`keynv: ${err.message}
5770
+ `);
5771
+ } else {
5772
+ stderr.write(`keynv: unexpected error
5773
+ `);
5774
+ }
5775
+ return 1;
5776
+ }
5731
5777
  var init_format = __esm({
5732
5778
  "src/ui/format.ts"() {
5779
+ init_http();
5733
5780
  }
5734
5781
  });
5735
5782
  function walkUp(startDir, predicate) {
@@ -5873,6 +5920,121 @@ var init_envFile = __esm({
5873
5920
  };
5874
5921
  }
5875
5922
  });
5923
+ function findProjectRoot(startDir) {
5924
+ const result = walkUp(startDir, (dir) => {
5925
+ for (const marker of PROJECT_MARKERS) {
5926
+ if (existsSync(join(dir, marker))) {
5927
+ return { dir, marker };
5928
+ }
5929
+ }
5930
+ if (existsSync(join(dir, GIT_MARKER))) {
5931
+ return { dir, marker: GIT_MARKER };
5932
+ }
5933
+ return null;
5934
+ });
5935
+ if (!result) return null;
5936
+ return buildRoot(result.dir, result.marker);
5937
+ }
5938
+ function buildRoot(dir, marker) {
5939
+ let suggestedName = basename(dir);
5940
+ let scripts = null;
5941
+ let invalid = false;
5942
+ if (marker === "package.json" || existsSync(join(dir, "package.json"))) {
5943
+ try {
5944
+ const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
5945
+ if (typeof pkg.name === "string" && pkg.name.length > 0) {
5946
+ suggestedName = pkg.name.replace(/^@[^/]+\//, "");
5947
+ }
5948
+ if (pkg.scripts && typeof pkg.scripts === "object") {
5949
+ scripts = Object.fromEntries(
5950
+ Object.entries(pkg.scripts).filter(([, v2]) => typeof v2 === "string")
5951
+ );
5952
+ }
5953
+ } catch {
5954
+ invalid = true;
5955
+ }
5956
+ }
5957
+ return {
5958
+ path: dir,
5959
+ suggestedName,
5960
+ marker,
5961
+ packageJsonScripts: scripts,
5962
+ packageJsonInvalid: invalid
5963
+ };
5964
+ }
5965
+ function findEnvFiles(rootDir) {
5966
+ let entries;
5967
+ try {
5968
+ entries = readdirSync(rootDir);
5969
+ } catch {
5970
+ return [];
5971
+ }
5972
+ const hits = [];
5973
+ for (const name of entries) {
5974
+ if (!ENV_GLOB.test(name)) continue;
5975
+ if (ENV_EXAMPLE.test(name)) continue;
5976
+ if (name === KEYNV_ENV_BASENAME) continue;
5977
+ const full = join(rootDir, name);
5978
+ try {
5979
+ if (!statSync(full).isFile()) continue;
5980
+ } catch {
5981
+ continue;
5982
+ }
5983
+ const suffixMatch = name.match(/^\.env\.(.+)$/);
5984
+ const suffix = suffixMatch ? suffixMatch[1] : null;
5985
+ hits.push({ path: full, name, suffix, suggestedEnv: suggestedEnvForSuffix(suffix) });
5986
+ }
5987
+ hits.sort((a, b2) => {
5988
+ if (a.suffix === null) return -1;
5989
+ if (b2.suffix === null) return 1;
5990
+ return a.name.localeCompare(b2.name);
5991
+ });
5992
+ return hits;
5993
+ }
5994
+ function suggestedEnvForSuffix(suffix) {
5995
+ if (suffix === null) return "dev";
5996
+ switch (suffix) {
5997
+ case "local":
5998
+ case "development":
5999
+ case "dev":
6000
+ return "dev";
6001
+ case "production":
6002
+ case "prod":
6003
+ return "prod";
6004
+ case "staging":
6005
+ case "stage":
6006
+ return "staging";
6007
+ case "test":
6008
+ return "test";
6009
+ case "preview":
6010
+ return "preview";
6011
+ default:
6012
+ return suffix;
6013
+ }
6014
+ }
6015
+ function hasExistingKeynvEnv(rootDir) {
6016
+ return existsSync(join(rootDir, KEYNV_ENV_BASENAME));
6017
+ }
6018
+ var PROJECT_MARKERS, GIT_MARKER, ENV_GLOB, ENV_EXAMPLE, KEYNV_ENV_BASENAME;
6019
+ var init_detect = __esm({
6020
+ "src/init/detect.ts"() {
6021
+ init_fs();
6022
+ PROJECT_MARKERS = [
6023
+ "package.json",
6024
+ "pyproject.toml",
6025
+ "Cargo.toml",
6026
+ "go.mod",
6027
+ "pnpm-workspace.yaml",
6028
+ "deno.json",
6029
+ "deno.jsonc",
6030
+ "requirements.txt"
6031
+ ];
6032
+ GIT_MARKER = ".git";
6033
+ ENV_GLOB = /^\.env(\.[A-Za-z0-9_-]+)?$/;
6034
+ ENV_EXAMPLE = /^\.env\.(example|sample|template|dist|defaults)$/;
6035
+ KEYNV_ENV_BASENAME = ".keynv.env";
6036
+ }
6037
+ });
5876
6038
 
5877
6039
  // src/init/heuristics.ts
5878
6040
  function shannonEntropyBits(s) {
@@ -5999,6 +6161,95 @@ var init_heuristics = __esm({
5999
6161
  ];
6000
6162
  }
6001
6163
  });
6164
+ function aiContextBody() {
6165
+ return `## keynv (secrets)
6166
+
6167
+ 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.
6168
+
6169
+ ### Mental model
6170
+
6171
+ - **\`.keynv.env\`** \u2014 checked into git, contains aliases. Safe to read, edit, commit.
6172
+ - **Vault** \u2014 holds the real values. The \`keynv\` CLI reads it on demand.
6173
+ - **\`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.
6174
+ - **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.
6175
+
6176
+ ### What you should do
6177
+
6178
+ When the user asks about secrets or env vars, follow this decision tree:
6179
+
6180
+ | User intent | Run / suggest |
6181
+ |---|---|
6182
+ | "Add a new API key" / "set up a secret" | \`keynv secret create\` (interactive prompt picks project + env + key) |
6183
+ | "I have a \`.env\`, migrate it" | \`keynv init\` (you're seeing this file because that already happened) |
6184
+ | "Run the app / dev server / tests" | \`keynv exec -- <their existing command>\` (auto-loads \`.keynv.env\`) |
6185
+ | "Show me the value of X" | \`keynv secret get @alias\` \u2014 but copy to clipboard, do NOT print the value into chat / terminal |
6186
+ | "Rotate this key" | \`keynv secret rotate @alias\` |
6187
+ | "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\`) |
6188
+ | "Who has access?" | \`keynv member list <project>\` |
6189
+
6190
+ ### Hard rules \u2014 do not violate
6191
+
6192
+ 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.
6193
+ 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.
6194
+ 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.
6195
+ 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.
6196
+ 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.
6197
+ 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.
6198
+
6199
+ ### Quick reference
6200
+
6201
+ \`\`\`bash
6202
+ keynv # interactive TUI menu (pick projects, secrets, members)
6203
+ keynv exec -- <cmd> # run cmd with .keynv.env loaded
6204
+ keynv secret create # walk through creating a new secret
6205
+ keynv secret list <project> # list aliases (no values)
6206
+ keynv whoami # who am I logged in as
6207
+ keynv --help # full command list
6208
+ \`\`\`
6209
+
6210
+ 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\`.`;
6211
+ }
6212
+ function renderKeynvBlock() {
6213
+ return `${KEYNV_BLOCK_START}
6214
+ ${aiContextBody()}
6215
+ ${KEYNV_BLOCK_END}`;
6216
+ }
6217
+ function writeAiContext(rootPath) {
6218
+ const path = join(rootPath, AGENTS_FILE_BASENAME);
6219
+ const block = renderKeynvBlock();
6220
+ if (!existsSync(path)) {
6221
+ const initial = `# Agent guidance for this project
6222
+
6223
+ ${block}
6224
+ `;
6225
+ writeFileSync(path, initial);
6226
+ return "created";
6227
+ }
6228
+ const existing = readFileSync(path, "utf8");
6229
+ const startIdx = existing.indexOf(KEYNV_BLOCK_START);
6230
+ const endIdx = existing.indexOf(KEYNV_BLOCK_END);
6231
+ if (startIdx >= 0 && endIdx > startIdx) {
6232
+ const before = existing.slice(0, startIdx);
6233
+ const after = existing.slice(endIdx + KEYNV_BLOCK_END.length);
6234
+ const next = `${before}${block}${after}`;
6235
+ if (next === existing) return "unchanged";
6236
+ writeFileSync(path, next);
6237
+ return "updated";
6238
+ }
6239
+ const sep = existing.length === 0 ? "" : existing.endsWith("\n\n") ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
6240
+ const trailingNewline = existing.endsWith("\n") ? "" : "\n";
6241
+ writeFileSync(path, `${existing}${trailingNewline}${sep}${block}
6242
+ `);
6243
+ return "appended";
6244
+ }
6245
+ var AGENTS_FILE_BASENAME, KEYNV_BLOCK_START, KEYNV_BLOCK_END;
6246
+ var init_aiContext = __esm({
6247
+ "src/init/aiContext.ts"() {
6248
+ AGENTS_FILE_BASENAME = "AGENTS.md";
6249
+ KEYNV_BLOCK_START = "<!-- keynv:start -- generated by `keynv init`; safe to leave intact, will be refreshed on re-run -->";
6250
+ KEYNV_BLOCK_END = "<!-- keynv:end -->";
6251
+ }
6252
+ });
6002
6253
 
6003
6254
  // ../../node_modules/.pnpm/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
6004
6255
  var getCodePointsLength, isFullWidth, isWideNotCJKTNotEmoji;
@@ -7154,210 +7405,6 @@ ${c2}
7154
7405
  } }).prompt();
7155
7406
  }
7156
7407
  });
7157
- function aiContextBody() {
7158
- return `## keynv (secrets)
7159
-
7160
- 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.
7161
-
7162
- ### Mental model
7163
-
7164
- - **\`.keynv.env\`** \u2014 checked into git, contains aliases. Safe to read, edit, commit.
7165
- - **Vault** \u2014 holds the real values. The \`keynv\` CLI reads it on demand.
7166
- - **\`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.
7167
- - **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.
7168
-
7169
- ### What you should do
7170
-
7171
- When the user asks about secrets or env vars, follow this decision tree:
7172
-
7173
- | User intent | Run / suggest |
7174
- |---|---|
7175
- | "Add a new API key" / "set up a secret" | \`keynv secret create\` (interactive prompt picks project + env + key) |
7176
- | "I have a \`.env\`, migrate it" | \`keynv init\` (you're seeing this file because that already happened) |
7177
- | "Run the app / dev server / tests" | \`keynv exec -- <their existing command>\` (auto-loads \`.keynv.env\`) |
7178
- | "Show me the value of X" | \`keynv secret get @alias\` \u2014 but copy to clipboard, do NOT print the value into chat / terminal |
7179
- | "Rotate this key" | \`keynv secret rotate @alias\` |
7180
- | "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\`) |
7181
- | "Who has access?" | \`keynv member list <project>\` |
7182
-
7183
- ### Hard rules \u2014 do not violate
7184
-
7185
- 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.
7186
- 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.
7187
- 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.
7188
- 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.
7189
- 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.
7190
- 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.
7191
-
7192
- ### Quick reference
7193
-
7194
- \`\`\`bash
7195
- keynv # interactive TUI menu (pick projects, secrets, members)
7196
- keynv exec -- <cmd> # run cmd with .keynv.env loaded
7197
- keynv secret create # walk through creating a new secret
7198
- keynv secret list <project> # list aliases (no values)
7199
- keynv whoami # who am I logged in as
7200
- keynv --help # full command list
7201
- \`\`\`
7202
-
7203
- 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\`.`;
7204
- }
7205
- function renderKeynvBlock() {
7206
- return `${KEYNV_BLOCK_START}
7207
- ${aiContextBody()}
7208
- ${KEYNV_BLOCK_END}`;
7209
- }
7210
- function writeAiContext(rootPath) {
7211
- const path = join(rootPath, AGENTS_FILE_BASENAME);
7212
- const block = renderKeynvBlock();
7213
- if (!existsSync(path)) {
7214
- const initial = `# Agent guidance for this project
7215
-
7216
- ${block}
7217
- `;
7218
- writeFileSync(path, initial);
7219
- return "created";
7220
- }
7221
- const existing = readFileSync(path, "utf8");
7222
- const startIdx = existing.indexOf(KEYNV_BLOCK_START);
7223
- const endIdx = existing.indexOf(KEYNV_BLOCK_END);
7224
- if (startIdx >= 0 && endIdx > startIdx) {
7225
- const before = existing.slice(0, startIdx);
7226
- const after = existing.slice(endIdx + KEYNV_BLOCK_END.length);
7227
- const next = `${before}${block}${after}`;
7228
- if (next === existing) return "unchanged";
7229
- writeFileSync(path, next);
7230
- return "updated";
7231
- }
7232
- const sep = existing.length === 0 ? "" : existing.endsWith("\n\n") ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
7233
- const trailingNewline = existing.endsWith("\n") ? "" : "\n";
7234
- writeFileSync(path, `${existing}${trailingNewline}${sep}${block}
7235
- `);
7236
- return "appended";
7237
- }
7238
- var AGENTS_FILE_BASENAME, KEYNV_BLOCK_START, KEYNV_BLOCK_END;
7239
- var init_aiContext = __esm({
7240
- "src/init/aiContext.ts"() {
7241
- AGENTS_FILE_BASENAME = "AGENTS.md";
7242
- KEYNV_BLOCK_START = "<!-- keynv:start -- generated by `keynv init`; safe to leave intact, will be refreshed on re-run -->";
7243
- KEYNV_BLOCK_END = "<!-- keynv:end -->";
7244
- }
7245
- });
7246
- function findProjectRoot(startDir) {
7247
- const result = walkUp(startDir, (dir) => {
7248
- for (const marker of PROJECT_MARKERS) {
7249
- if (existsSync(join(dir, marker))) {
7250
- return { dir, marker };
7251
- }
7252
- }
7253
- if (existsSync(join(dir, GIT_MARKER))) {
7254
- return { dir, marker: GIT_MARKER };
7255
- }
7256
- return null;
7257
- });
7258
- if (!result) return null;
7259
- return buildRoot(result.dir, result.marker);
7260
- }
7261
- function buildRoot(dir, marker) {
7262
- let suggestedName = basename(dir);
7263
- let scripts = null;
7264
- let invalid = false;
7265
- if (marker === "package.json" || existsSync(join(dir, "package.json"))) {
7266
- try {
7267
- const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
7268
- if (typeof pkg.name === "string" && pkg.name.length > 0) {
7269
- suggestedName = pkg.name.replace(/^@[^/]+\//, "");
7270
- }
7271
- if (pkg.scripts && typeof pkg.scripts === "object") {
7272
- scripts = Object.fromEntries(
7273
- Object.entries(pkg.scripts).filter(([, v2]) => typeof v2 === "string")
7274
- );
7275
- }
7276
- } catch {
7277
- invalid = true;
7278
- }
7279
- }
7280
- return {
7281
- path: dir,
7282
- suggestedName,
7283
- marker,
7284
- packageJsonScripts: scripts,
7285
- packageJsonInvalid: invalid
7286
- };
7287
- }
7288
- function findEnvFiles(rootDir) {
7289
- let entries;
7290
- try {
7291
- entries = readdirSync(rootDir);
7292
- } catch {
7293
- return [];
7294
- }
7295
- const hits = [];
7296
- for (const name of entries) {
7297
- if (!ENV_GLOB.test(name)) continue;
7298
- if (ENV_EXAMPLE.test(name)) continue;
7299
- if (name === KEYNV_ENV_BASENAME) continue;
7300
- const full = join(rootDir, name);
7301
- try {
7302
- if (!statSync(full).isFile()) continue;
7303
- } catch {
7304
- continue;
7305
- }
7306
- const suffixMatch = name.match(/^\.env\.(.+)$/);
7307
- const suffix = suffixMatch ? suffixMatch[1] : null;
7308
- hits.push({ path: full, name, suffix, suggestedEnv: suggestedEnvForSuffix(suffix) });
7309
- }
7310
- hits.sort((a, b2) => {
7311
- if (a.suffix === null) return -1;
7312
- if (b2.suffix === null) return 1;
7313
- return a.name.localeCompare(b2.name);
7314
- });
7315
- return hits;
7316
- }
7317
- function suggestedEnvForSuffix(suffix) {
7318
- if (suffix === null) return "dev";
7319
- switch (suffix) {
7320
- case "local":
7321
- case "development":
7322
- case "dev":
7323
- return "dev";
7324
- case "production":
7325
- case "prod":
7326
- return "prod";
7327
- case "staging":
7328
- case "stage":
7329
- return "staging";
7330
- case "test":
7331
- return "test";
7332
- case "preview":
7333
- return "preview";
7334
- default:
7335
- return suffix;
7336
- }
7337
- }
7338
- function hasExistingKeynvEnv(rootDir) {
7339
- return existsSync(join(rootDir, KEYNV_ENV_BASENAME));
7340
- }
7341
- var PROJECT_MARKERS, GIT_MARKER, ENV_GLOB, ENV_EXAMPLE, KEYNV_ENV_BASENAME;
7342
- var init_detect = __esm({
7343
- "src/init/detect.ts"() {
7344
- init_fs();
7345
- PROJECT_MARKERS = [
7346
- "package.json",
7347
- "pyproject.toml",
7348
- "Cargo.toml",
7349
- "go.mod",
7350
- "pnpm-workspace.yaml",
7351
- "deno.json",
7352
- "deno.jsonc",
7353
- "requirements.txt"
7354
- ];
7355
- GIT_MARKER = ".git";
7356
- ENV_GLOB = /^\.env(\.[A-Za-z0-9_-]+)?$/;
7357
- ENV_EXAMPLE = /^\.env\.(example|sample|template|dist|defaults)$/;
7358
- KEYNV_ENV_BASENAME = ".keynv.env";
7359
- }
7360
- });
7361
7408
 
7362
7409
  // src/init/scriptWrap.ts
7363
7410
  function analyzeScript(name, command) {
@@ -7578,6 +7625,14 @@ __export(init_exports, {
7578
7625
  UserCancelled: () => UserCancelled,
7579
7626
  runInitFlow: () => runInitFlow
7580
7627
  });
7628
+ function toAliasKey(name) {
7629
+ if (!name) return name;
7630
+ const KEY_RE3 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
7631
+ if (KEY_RE3.test(name)) return name;
7632
+ const normalised = name.toLowerCase().replace(/_/g, "-");
7633
+ if (KEY_RE3.test(normalised)) return normalised;
7634
+ return normalised.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 64) || "key";
7635
+ }
7581
7636
  async function runInitFlow(client, opts) {
7582
7637
  ge("keynv init");
7583
7638
  const root = findProjectRoot(opts.cwd);
@@ -7736,7 +7791,7 @@ ${detail}`
7736
7791
  if (!selected.has(`${env2}|${e2.name}`)) continue;
7737
7792
  i++;
7738
7793
  s.message(`Uploading (${i}/${totalToUpload}) [${env2}] ${e2.name}`);
7739
- const aliasKey = e2.name.toLowerCase().replace(/_/g, "-");
7794
+ const aliasKey = toAliasKey(e2.name);
7740
7795
  try {
7741
7796
  await client.request(`/v1/projects/${projectId2}/secrets`, {
7742
7797
  method: "POST",
@@ -7794,6 +7849,30 @@ ${detail}`
7794
7849
  R2.error(`Failed to write .keynv.env: ${err instanceof Error ? err.message : String(err)}`);
7795
7850
  return { exitCode: 1 };
7796
7851
  }
7852
+ const otherEnvsWithAliases = distinctEnvs.filter(
7853
+ (env2) => env2 !== defaultEnv && (uploadedByEnv.get(env2)?.size ?? 0) > 0
7854
+ );
7855
+ for (const env2 of otherEnvsWithAliases) {
7856
+ const envUploaded = uploadedByEnv.get(env2) ?? /* @__PURE__ */ new Map();
7857
+ const envLiterals = (perEnv.get(env2) ?? []).filter((e2) => !selected.has(`${env2}|${e2.name}`));
7858
+ const envFilePath = join(root.path, `.keynv.${env2}.env`);
7859
+ try {
7860
+ const lines = composeKeynvEnv({
7861
+ uploadedAliases: envUploaded,
7862
+ literals: envLiterals,
7863
+ mergeWithExisting: null
7864
+ });
7865
+ writeFileSync(envFilePath, `${lines.join("\n")}
7866
+ `);
7867
+ R2.success(
7868
+ `Wrote .keynv.${env2}.env (${envUploaded.size} secret alias${envUploaded.size === 1 ? "" : "es"} from "${env2}")`
7869
+ );
7870
+ } catch (err) {
7871
+ R2.warn(
7872
+ `Could not write .keynv.${env2}.env: ${err instanceof Error ? err.message : String(err)}`
7873
+ );
7874
+ }
7875
+ }
7797
7876
  try {
7798
7877
  const outcome = writeAiContext(root.path);
7799
7878
  if (outcome === "created") R2.success("Wrote AGENTS.md (so AI agents understand keynv)");
@@ -7830,7 +7909,8 @@ ${detail}`
7830
7909
  if (otherEnvs.length > 0) {
7831
7910
  const lines = otherEnvs.map((env2) => {
7832
7911
  const count = uploadedByEnv.get(env2)?.size ?? 0;
7833
- return ` ${env2}: ${count} secret${count === 1 ? "" : "s"} in vault (use \`keynv exec --from .keynv.${env2}.env -- <cmd>\` after creating that file)`;
7912
+ const hasFile = count > 0;
7913
+ return hasFile ? ` ${env2}: ${count} secret${count === 1 ? "" : "s"} \u2192 .keynv.${env2}.env (use \`keynv exec --from .keynv.${env2}.env -- <cmd>\`)` : ` ${env2}: 0 secrets in vault (no alias file written)`;
7834
7914
  });
7835
7915
  Se(lines.join("\n"), "Secrets in other envs");
7836
7916
  }
@@ -8080,7 +8160,7 @@ var init_tty = __esm({
8080
8160
  }
8081
8161
  });
8082
8162
  function sleep(ms) {
8083
- return new Promise((resolve3) => setTimeout(resolve3, ms));
8163
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
8084
8164
  }
8085
8165
  async function errorMessage(res, fallback) {
8086
8166
  const text = await res.text();
@@ -8322,16 +8402,16 @@ async function runSecretMenu(client, project, alias2) {
8322
8402
  async function copyToClipboard(value) {
8323
8403
  const platform2 = process.platform;
8324
8404
  const cmd = platform2 === "darwin" ? ["pbcopy", []] : platform2 === "win32" ? ["clip", []] : ["xclip", ["-selection", "clipboard"]];
8325
- return new Promise((resolve3) => {
8405
+ return new Promise((resolve4) => {
8326
8406
  try {
8327
8407
  const child = spawn(cmd[0], cmd[1], {
8328
8408
  stdio: ["pipe", "ignore", "ignore"]
8329
8409
  });
8330
- child.on("error", () => resolve3(false));
8331
- child.on("exit", (code) => resolve3(code === 0));
8410
+ child.on("error", () => resolve4(false));
8411
+ child.on("exit", (code) => resolve4(code === 0));
8332
8412
  child.stdin.end(value);
8333
8413
  } catch {
8334
- resolve3(false);
8414
+ resolve4(false);
8335
8415
  }
8336
8416
  });
8337
8417
  }
@@ -25077,7 +25157,7 @@ var require_named_placeholders = __commonJS({
25077
25157
  }
25078
25158
  return s;
25079
25159
  }
25080
- function join6(tree) {
25160
+ function join8(tree) {
25081
25161
  if (tree.length === 1) {
25082
25162
  return tree;
25083
25163
  }
@@ -25103,7 +25183,7 @@ var require_named_placeholders = __commonJS({
25103
25183
  if (cache2 && (tree = cache2.get(query))) {
25104
25184
  return toArrayParams(tree, paramsObj);
25105
25185
  }
25106
- tree = join6(parse(query));
25186
+ tree = join8(parse(query));
25107
25187
  if (cache2) {
25108
25188
  cache2.set(query, tree);
25109
25189
  }
@@ -25259,11 +25339,11 @@ var require_connection = __commonJS({
25259
25339
  const config = this.config;
25260
25340
  tracePromise(
25261
25341
  connectChannel,
25262
- () => new Promise((resolve3, reject) => {
25342
+ () => new Promise((resolve4, reject) => {
25263
25343
  let onConnect, onError;
25264
25344
  onConnect = (param) => {
25265
25345
  this.removeListener("error", onError);
25266
- resolve3(param);
25346
+ resolve4(param);
25267
25347
  };
25268
25348
  onError = (err) => {
25269
25349
  this.removeListener("connect", onConnect);
@@ -25688,9 +25768,9 @@ var require_connection = __commonJS({
25688
25768
  } else if (shouldTrace(queryChannel)) {
25689
25769
  tracePromise(
25690
25770
  queryChannel,
25691
- () => new Promise((resolve3, reject) => {
25771
+ () => new Promise((resolve4, reject) => {
25692
25772
  cmdQuery.once("error", reject);
25693
- cmdQuery.once("end", () => resolve3());
25773
+ cmdQuery.once("end", () => resolve4());
25694
25774
  this.addCommand(cmdQuery);
25695
25775
  }),
25696
25776
  () => {
@@ -25837,12 +25917,12 @@ var require_connection = __commonJS({
25837
25917
  } else if (shouldTrace(executeChannel)) {
25838
25918
  tracePromise(
25839
25919
  executeChannel,
25840
- () => new Promise((resolve3, reject) => {
25920
+ () => new Promise((resolve4, reject) => {
25841
25921
  prepareAndExecute((err) => {
25842
25922
  executeCommand.emit("error", err);
25843
25923
  });
25844
25924
  executeCommand.once("error", reject);
25845
- executeCommand.once("end", () => resolve3());
25925
+ executeCommand.once("end", () => resolve4());
25846
25926
  }),
25847
25927
  () => {
25848
25928
  const server = getServerContext(this.config);
@@ -26107,13 +26187,13 @@ var require_capture_local_err = __commonJS({
26107
26187
  var require_make_done_cb = __commonJS({
26108
26188
  "../../node_modules/.pnpm/mysql2@3.22.3_@types+node@24.12.3/node_modules/mysql2/lib/promise/make_done_cb.js"(exports, module) {
26109
26189
  var { applyCapturedStack } = require_capture_local_err();
26110
- function makeDoneCb(resolve3, reject, stackHolder) {
26190
+ function makeDoneCb(resolve4, reject, stackHolder) {
26111
26191
  return function(err, rows, fields) {
26112
26192
  if (err) {
26113
26193
  applyCapturedStack(err, stackHolder);
26114
26194
  reject(err);
26115
26195
  } else {
26116
- resolve3([rows, fields]);
26196
+ resolve4([rows, fields]);
26117
26197
  }
26118
26198
  };
26119
26199
  }
@@ -26136,8 +26216,8 @@ var require_prepared_statement_info = __commonJS({
26136
26216
  const stackHolder = captureStackHolder(
26137
26217
  _PromisePreparedStatementInfo.prototype.execute
26138
26218
  );
26139
- return new this.Promise((resolve3, reject) => {
26140
- const done = makeDoneCb(resolve3, reject, stackHolder);
26219
+ return new this.Promise((resolve4, reject) => {
26220
+ const done = makeDoneCb(resolve4, reject, stackHolder);
26141
26221
  if (parameters) {
26142
26222
  s.execute(parameters, done);
26143
26223
  } else {
@@ -26146,9 +26226,9 @@ var require_prepared_statement_info = __commonJS({
26146
26226
  });
26147
26227
  }
26148
26228
  close() {
26149
- return new this.Promise((resolve3) => {
26229
+ return new this.Promise((resolve4) => {
26150
26230
  this.statement.close();
26151
- resolve3();
26231
+ resolve4();
26152
26232
  });
26153
26233
  }
26154
26234
  };
@@ -26219,8 +26299,8 @@ var require_connection2 = __commonJS({
26219
26299
  "Callback function is not available with promise clients."
26220
26300
  );
26221
26301
  }
26222
- return new this.Promise((resolve3, reject) => {
26223
- const done = makeDoneCb(resolve3, reject, stackHolder);
26302
+ return new this.Promise((resolve4, reject) => {
26303
+ const done = makeDoneCb(resolve4, reject, stackHolder);
26224
26304
  if (params !== void 0) {
26225
26305
  c2.query(query, params, done);
26226
26306
  } else {
@@ -26236,8 +26316,8 @@ var require_connection2 = __commonJS({
26236
26316
  "Callback function is not available with promise clients."
26237
26317
  );
26238
26318
  }
26239
- return new this.Promise((resolve3, reject) => {
26240
- const done = makeDoneCb(resolve3, reject, stackHolder);
26319
+ return new this.Promise((resolve4, reject) => {
26320
+ const done = makeDoneCb(resolve4, reject, stackHolder);
26241
26321
  if (params !== void 0) {
26242
26322
  c2.execute(query, params, done);
26243
26323
  } else {
@@ -26246,8 +26326,8 @@ var require_connection2 = __commonJS({
26246
26326
  });
26247
26327
  }
26248
26328
  end() {
26249
- return new this.Promise((resolve3) => {
26250
- this.connection.end(resolve3);
26329
+ return new this.Promise((resolve4) => {
26330
+ this.connection.end(resolve4);
26251
26331
  });
26252
26332
  }
26253
26333
  async [Symbol.asyncDispose]() {
@@ -26260,16 +26340,16 @@ var require_connection2 = __commonJS({
26260
26340
  const stackHolder = captureStackHolder(
26261
26341
  _PromiseConnection.prototype.beginTransaction
26262
26342
  );
26263
- return new this.Promise((resolve3, reject) => {
26264
- const done = makeDoneCb(resolve3, reject, stackHolder);
26343
+ return new this.Promise((resolve4, reject) => {
26344
+ const done = makeDoneCb(resolve4, reject, stackHolder);
26265
26345
  c2.beginTransaction(done);
26266
26346
  });
26267
26347
  }
26268
26348
  commit() {
26269
26349
  const c2 = this.connection;
26270
26350
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.commit);
26271
- return new this.Promise((resolve3, reject) => {
26272
- const done = makeDoneCb(resolve3, reject, stackHolder);
26351
+ return new this.Promise((resolve4, reject) => {
26352
+ const done = makeDoneCb(resolve4, reject, stackHolder);
26273
26353
  c2.commit(done);
26274
26354
  });
26275
26355
  }
@@ -26278,21 +26358,21 @@ var require_connection2 = __commonJS({
26278
26358
  const stackHolder = captureStackHolder(
26279
26359
  _PromiseConnection.prototype.rollback
26280
26360
  );
26281
- return new this.Promise((resolve3, reject) => {
26282
- const done = makeDoneCb(resolve3, reject, stackHolder);
26361
+ return new this.Promise((resolve4, reject) => {
26362
+ const done = makeDoneCb(resolve4, reject, stackHolder);
26283
26363
  c2.rollback(done);
26284
26364
  });
26285
26365
  }
26286
26366
  ping() {
26287
26367
  const c2 = this.connection;
26288
26368
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.ping);
26289
- return new this.Promise((resolve3, reject) => {
26369
+ return new this.Promise((resolve4, reject) => {
26290
26370
  c2.ping((err) => {
26291
26371
  if (err) {
26292
26372
  applyCapturedStack(err, stackHolder);
26293
26373
  reject(err);
26294
26374
  } else {
26295
- resolve3(true);
26375
+ resolve4(true);
26296
26376
  }
26297
26377
  });
26298
26378
  });
@@ -26300,13 +26380,13 @@ var require_connection2 = __commonJS({
26300
26380
  reset() {
26301
26381
  const c2 = this.connection;
26302
26382
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.reset);
26303
- return new this.Promise((resolve3, reject) => {
26383
+ return new this.Promise((resolve4, reject) => {
26304
26384
  c2.reset((err) => {
26305
26385
  if (err) {
26306
26386
  applyCapturedStack(err, stackHolder);
26307
26387
  reject(err);
26308
26388
  } else {
26309
- resolve3();
26389
+ resolve4();
26310
26390
  }
26311
26391
  });
26312
26392
  });
@@ -26314,13 +26394,13 @@ var require_connection2 = __commonJS({
26314
26394
  connect() {
26315
26395
  const c2 = this.connection;
26316
26396
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.connect);
26317
- return new this.Promise((resolve3, reject) => {
26397
+ return new this.Promise((resolve4, reject) => {
26318
26398
  c2.connect((err, param) => {
26319
26399
  if (err) {
26320
26400
  applyCapturedStack(err, stackHolder);
26321
26401
  reject(err);
26322
26402
  } else {
26323
- resolve3(param);
26403
+ resolve4(param);
26324
26404
  }
26325
26405
  });
26326
26406
  });
@@ -26329,7 +26409,7 @@ var require_connection2 = __commonJS({
26329
26409
  const c2 = this.connection;
26330
26410
  const promiseImpl = this.Promise;
26331
26411
  const stackHolder = captureStackHolder(_PromiseConnection.prototype.prepare);
26332
- return new this.Promise((resolve3, reject) => {
26412
+ return new this.Promise((resolve4, reject) => {
26333
26413
  c2.prepare(options, (err, statement) => {
26334
26414
  if (err) {
26335
26415
  applyCapturedStack(err, stackHolder);
@@ -26339,7 +26419,7 @@ var require_connection2 = __commonJS({
26339
26419
  statement,
26340
26420
  promiseImpl
26341
26421
  );
26342
- resolve3(wrappedStatement);
26422
+ resolve4(wrappedStatement);
26343
26423
  }
26344
26424
  });
26345
26425
  });
@@ -26349,13 +26429,13 @@ var require_connection2 = __commonJS({
26349
26429
  const stackHolder = captureStackHolder(
26350
26430
  _PromiseConnection.prototype.changeUser
26351
26431
  );
26352
- return new this.Promise((resolve3, reject) => {
26432
+ return new this.Promise((resolve4, reject) => {
26353
26433
  c2.changeUser(options, (err) => {
26354
26434
  if (err) {
26355
26435
  applyCapturedStack(err, stackHolder);
26356
26436
  reject(err);
26357
26437
  } else {
26358
- resolve3();
26438
+ resolve4();
26359
26439
  }
26360
26440
  });
26361
26441
  });
@@ -26817,12 +26897,12 @@ var require_pool2 = __commonJS({
26817
26897
  }
26818
26898
  getConnection() {
26819
26899
  const corePool = this.pool;
26820
- return new this.Promise((resolve3, reject) => {
26900
+ return new this.Promise((resolve4, reject) => {
26821
26901
  corePool.getConnection((err, coreConnection) => {
26822
26902
  if (err) {
26823
26903
  reject(err);
26824
26904
  } else {
26825
- resolve3(new PromisePoolConnection(coreConnection, this.Promise));
26905
+ resolve4(new PromisePoolConnection(coreConnection, this.Promise));
26826
26906
  }
26827
26907
  });
26828
26908
  });
@@ -26838,8 +26918,8 @@ var require_pool2 = __commonJS({
26838
26918
  "Callback function is not available with promise clients."
26839
26919
  );
26840
26920
  }
26841
- return new this.Promise((resolve3, reject) => {
26842
- const done = makeDoneCb(resolve3, reject, stackHolder);
26921
+ return new this.Promise((resolve4, reject) => {
26922
+ const done = makeDoneCb(resolve4, reject, stackHolder);
26843
26923
  if (args !== void 0) {
26844
26924
  corePool.query(sql, args, done);
26845
26925
  } else {
@@ -26855,8 +26935,8 @@ var require_pool2 = __commonJS({
26855
26935
  "Callback function is not available with promise clients."
26856
26936
  );
26857
26937
  }
26858
- return new this.Promise((resolve3, reject) => {
26859
- const done = makeDoneCb(resolve3, reject, stackHolder);
26938
+ return new this.Promise((resolve4, reject) => {
26939
+ const done = makeDoneCb(resolve4, reject, stackHolder);
26860
26940
  if (args) {
26861
26941
  corePool.execute(sql, args, done);
26862
26942
  } else {
@@ -26867,13 +26947,13 @@ var require_pool2 = __commonJS({
26867
26947
  end() {
26868
26948
  const corePool = this.pool;
26869
26949
  const stackHolder = captureStackHolder(_PromisePool.prototype.end);
26870
- return new this.Promise((resolve3, reject) => {
26950
+ return new this.Promise((resolve4, reject) => {
26871
26951
  corePool.end((err) => {
26872
26952
  if (err) {
26873
26953
  applyCapturedStack(err, stackHolder);
26874
26954
  reject(err);
26875
26955
  } else {
26876
- resolve3();
26956
+ resolve4();
26877
26957
  }
26878
26958
  });
26879
26959
  });
@@ -27298,12 +27378,12 @@ var require_pool_cluster2 = __commonJS({
27298
27378
  }
27299
27379
  getConnection() {
27300
27380
  const corePoolNamespace = this.poolNamespace;
27301
- return new this.Promise((resolve3, reject) => {
27381
+ return new this.Promise((resolve4, reject) => {
27302
27382
  corePoolNamespace.getConnection((err, coreConnection) => {
27303
27383
  if (err) {
27304
27384
  reject(err);
27305
27385
  } else {
27306
- resolve3(new PromisePoolConnection(coreConnection, this.Promise));
27386
+ resolve4(new PromisePoolConnection(coreConnection, this.Promise));
27307
27387
  }
27308
27388
  });
27309
27389
  });
@@ -27318,8 +27398,8 @@ var require_pool_cluster2 = __commonJS({
27318
27398
  "Callback function is not available with promise clients."
27319
27399
  );
27320
27400
  }
27321
- return new this.Promise((resolve3, reject) => {
27322
- const done = makeDoneCb(resolve3, reject, stackHolder);
27401
+ return new this.Promise((resolve4, reject) => {
27402
+ const done = makeDoneCb(resolve4, reject, stackHolder);
27323
27403
  corePoolNamespace.query(sql, values, done);
27324
27404
  });
27325
27405
  }
@@ -27333,8 +27413,8 @@ var require_pool_cluster2 = __commonJS({
27333
27413
  "Callback function is not available with promise clients."
27334
27414
  );
27335
27415
  }
27336
- return new this.Promise((resolve3, reject) => {
27337
- const done = makeDoneCb(resolve3, reject, stackHolder);
27416
+ return new this.Promise((resolve4, reject) => {
27417
+ const done = makeDoneCb(resolve4, reject, stackHolder);
27338
27418
  corePoolNamespace.execute(sql, values, done);
27339
27419
  });
27340
27420
  }
@@ -27372,9 +27452,9 @@ var require_promise = __commonJS({
27372
27452
  "no Promise implementation available.Use promise-enabled node version or pass userland Promise implementation as parameter, for example: { Promise: require('bluebird') }"
27373
27453
  );
27374
27454
  }
27375
- return new thePromise((resolve3, reject) => {
27455
+ return new thePromise((resolve4, reject) => {
27376
27456
  coreConnection.once("connect", () => {
27377
- resolve3(new PromiseConnection(coreConnection, thePromise));
27457
+ resolve4(new PromiseConnection(coreConnection, thePromise));
27378
27458
  });
27379
27459
  coreConnection.once("error", (err) => {
27380
27460
  applyCapturedStack(err, stackHolder);
@@ -27401,7 +27481,7 @@ var require_promise = __commonJS({
27401
27481
  }
27402
27482
  getConnection(pattern, selector) {
27403
27483
  const corePoolCluster = this.poolCluster;
27404
- return new this.Promise((resolve3, reject) => {
27484
+ return new this.Promise((resolve4, reject) => {
27405
27485
  corePoolCluster.getConnection(
27406
27486
  pattern,
27407
27487
  selector,
@@ -27409,7 +27489,7 @@ var require_promise = __commonJS({
27409
27489
  if (err) {
27410
27490
  reject(err);
27411
27491
  } else {
27412
- resolve3(new PromisePoolConnection(coreConnection, this.Promise));
27492
+ resolve4(new PromisePoolConnection(coreConnection, this.Promise));
27413
27493
  }
27414
27494
  }
27415
27495
  );
@@ -27423,8 +27503,8 @@ var require_promise = __commonJS({
27423
27503
  "Callback function is not available with promise clients."
27424
27504
  );
27425
27505
  }
27426
- return new this.Promise((resolve3, reject) => {
27427
- const done = makeDoneCb(resolve3, reject, stackHolder);
27506
+ return new this.Promise((resolve4, reject) => {
27507
+ const done = makeDoneCb(resolve4, reject, stackHolder);
27428
27508
  corePoolCluster.query(sql, args, done);
27429
27509
  });
27430
27510
  }
@@ -27438,8 +27518,8 @@ var require_promise = __commonJS({
27438
27518
  "Callback function is not available with promise clients."
27439
27519
  );
27440
27520
  }
27441
- return new this.Promise((resolve3, reject) => {
27442
- const done = makeDoneCb(resolve3, reject, stackHolder);
27521
+ return new this.Promise((resolve4, reject) => {
27522
+ const done = makeDoneCb(resolve4, reject, stackHolder);
27443
27523
  corePoolCluster.execute(sql, args, done);
27444
27524
  });
27445
27525
  }
@@ -27452,13 +27532,13 @@ var require_promise = __commonJS({
27452
27532
  end() {
27453
27533
  const corePoolCluster = this.poolCluster;
27454
27534
  const stackHolder = captureStackHolder(_PromisePoolCluster.prototype.end);
27455
- return new this.Promise((resolve3, reject) => {
27535
+ return new this.Promise((resolve4, reject) => {
27456
27536
  corePoolCluster.end((err) => {
27457
27537
  if (err) {
27458
27538
  applyCapturedStack(err, stackHolder);
27459
27539
  reject(err);
27460
27540
  } else {
27461
- resolve3();
27541
+ resolve4();
27462
27542
  }
27463
27543
  });
27464
27544
  });
@@ -30533,7 +30613,7 @@ var require_dist = __commonJS({
30533
30613
  function parse(stream, callback) {
30534
30614
  const parser = new parser_1.Parser();
30535
30615
  stream.on("data", (buffer) => parser.parse(buffer, callback));
30536
- return new Promise((resolve3) => stream.on("end", () => resolve3()));
30616
+ return new Promise((resolve4) => stream.on("end", () => resolve4()));
30537
30617
  }
30538
30618
  exports.parse = parse;
30539
30619
  }
@@ -31258,12 +31338,12 @@ var require_client2 = __commonJS({
31258
31338
  this._connect(callback);
31259
31339
  return;
31260
31340
  }
31261
- return new this._Promise((resolve3, reject) => {
31341
+ return new this._Promise((resolve4, reject) => {
31262
31342
  this._connect((error) => {
31263
31343
  if (error) {
31264
31344
  reject(error);
31265
31345
  } else {
31266
- resolve3(this);
31346
+ resolve4(this);
31267
31347
  }
31268
31348
  });
31269
31349
  });
@@ -31609,8 +31689,8 @@ var require_client2 = __commonJS({
31609
31689
  readTimeout = config.query_timeout || this.connectionParameters.query_timeout;
31610
31690
  query = new Query2(config, values, callback);
31611
31691
  if (!query.callback) {
31612
- result = new this._Promise((resolve3, reject) => {
31613
- query.callback = (err, res) => err ? reject(err) : resolve3(res);
31692
+ result = new this._Promise((resolve4, reject) => {
31693
+ query.callback = (err, res) => err ? reject(err) : resolve4(res);
31614
31694
  }).catch((err) => {
31615
31695
  Error.captureStackTrace(err);
31616
31696
  throw err;
@@ -31687,8 +31767,8 @@ var require_client2 = __commonJS({
31687
31767
  if (cb) {
31688
31768
  this.connection.once("end", cb);
31689
31769
  } else {
31690
- return new this._Promise((resolve3) => {
31691
- this.connection.once("end", resolve3);
31770
+ return new this._Promise((resolve4) => {
31771
+ this.connection.once("end", resolve4);
31692
31772
  });
31693
31773
  }
31694
31774
  }
@@ -31736,8 +31816,8 @@ var require_pg_pool = __commonJS({
31736
31816
  const cb = function(err, client) {
31737
31817
  err ? rej(err) : res(client);
31738
31818
  };
31739
- const result = new Promise2(function(resolve3, reject) {
31740
- res = resolve3;
31819
+ const result = new Promise2(function(resolve4, reject) {
31820
+ res = resolve4;
31741
31821
  rej = reject;
31742
31822
  }).catch((err) => {
31743
31823
  Error.captureStackTrace(err);
@@ -31798,7 +31878,7 @@ var require_pg_pool = __commonJS({
31798
31878
  if (typeof Promise2.try === "function") {
31799
31879
  return Promise2.try(f);
31800
31880
  }
31801
- return new Promise2((resolve3) => resolve3(f()));
31881
+ return new Promise2((resolve4) => resolve4(f()));
31802
31882
  }
31803
31883
  _isFull() {
31804
31884
  return this._clients.length >= this.options.max;
@@ -32190,8 +32270,8 @@ var require_query4 = __commonJS({
32190
32270
  NativeQuery.prototype._getPromise = function() {
32191
32271
  if (this._promise) return this._promise;
32192
32272
  this._promise = new Promise(
32193
- function(resolve3, reject) {
32194
- this._once("end", resolve3);
32273
+ function(resolve4, reject) {
32274
+ this._once("end", resolve4);
32195
32275
  this._once("error", reject);
32196
32276
  }.bind(this)
32197
32277
  );
@@ -32368,12 +32448,12 @@ var require_client3 = __commonJS({
32368
32448
  this._connect(callback);
32369
32449
  return;
32370
32450
  }
32371
- return new this._Promise((resolve3, reject) => {
32451
+ return new this._Promise((resolve4, reject) => {
32372
32452
  this._connect((error) => {
32373
32453
  if (error) {
32374
32454
  reject(error);
32375
32455
  } else {
32376
- resolve3(this);
32456
+ resolve4(this);
32377
32457
  }
32378
32458
  });
32379
32459
  });
@@ -32397,8 +32477,8 @@ var require_client3 = __commonJS({
32397
32477
  query = new NativeQuery(config, values, callback);
32398
32478
  if (!query.callback) {
32399
32479
  let resolveOut, rejectOut;
32400
- result = new this._Promise((resolve3, reject) => {
32401
- resolveOut = resolve3;
32480
+ result = new this._Promise((resolve4, reject) => {
32481
+ resolveOut = resolve4;
32402
32482
  rejectOut = reject;
32403
32483
  }).catch((err) => {
32404
32484
  Error.captureStackTrace(err);
@@ -32458,8 +32538,8 @@ var require_client3 = __commonJS({
32458
32538
  }
32459
32539
  let result;
32460
32540
  if (!cb) {
32461
- result = new this._Promise(function(resolve3, reject) {
32462
- cb = (err) => err ? reject(err) : resolve3();
32541
+ result = new this._Promise(function(resolve4, reject) {
32542
+ cb = (err) => err ? reject(err) : resolve4();
32463
32543
  });
32464
32544
  }
32465
32545
  this.native.end(function() {
@@ -36382,8 +36462,8 @@ var require_common = __commonJS({
36382
36462
  }
36383
36463
  return debug2;
36384
36464
  }
36385
- function extend(namespace, delimiter) {
36386
- const newDebug = createDebug(this.namespace + (typeof delimiter === "undefined" ? ":" : delimiter) + namespace);
36465
+ function extend(namespace, delimiter2) {
36466
+ const newDebug = createDebug(this.namespace + (typeof delimiter2 === "undefined" ? ":" : delimiter2) + namespace);
36387
36467
  newDebug.log = this.log;
36388
36468
  return newDebug;
36389
36469
  }
@@ -37566,7 +37646,7 @@ var require_Command = __commonJS({
37566
37646
  }
37567
37647
  }
37568
37648
  initPromise() {
37569
- const promise = new Promise((resolve3, reject) => {
37649
+ const promise = new Promise((resolve4, reject) => {
37570
37650
  if (!this.transformed) {
37571
37651
  this.transformed = true;
37572
37652
  const transformer = _Command._transformer.argument[this.name];
@@ -37575,7 +37655,7 @@ var require_Command = __commonJS({
37575
37655
  }
37576
37656
  this.stringifyArguments();
37577
37657
  }
37578
- this.resolve = this._convertValue(resolve3);
37658
+ this.resolve = this._convertValue(resolve4);
37579
37659
  this.reject = (err) => {
37580
37660
  this._clearTimers();
37581
37661
  if (this.errorStack) {
@@ -37608,11 +37688,11 @@ var require_Command = __commonJS({
37608
37688
  /**
37609
37689
  * Convert the value from buffer to the target encoding.
37610
37690
  */
37611
- _convertValue(resolve3) {
37691
+ _convertValue(resolve4) {
37612
37692
  return (value) => {
37613
37693
  try {
37614
37694
  this._clearTimers();
37615
- resolve3(this.transformReply(value));
37695
+ resolve4(this.transformReply(value));
37616
37696
  this.isResolved = true;
37617
37697
  } catch (err) {
37618
37698
  this.reject(err);
@@ -37890,13 +37970,13 @@ var require_autoPipelining = __commonJS({
37890
37970
  if (client.isCluster && !client.slots.length) {
37891
37971
  if (client.status === "wait")
37892
37972
  client.connect().catch(lodash_1.noop);
37893
- return (0, standard_as_callback_1.default)(new Promise(function(resolve3, reject) {
37973
+ return (0, standard_as_callback_1.default)(new Promise(function(resolve4, reject) {
37894
37974
  client.delayUntilReady((err) => {
37895
37975
  if (err) {
37896
37976
  reject(err);
37897
37977
  return;
37898
37978
  }
37899
- executeWithAutoPipelining(client, functionName, commandName, args, null).then(resolve3, reject);
37979
+ executeWithAutoPipelining(client, functionName, commandName, args, null).then(resolve4, reject);
37900
37980
  });
37901
37981
  }), callback);
37902
37982
  }
@@ -37917,13 +37997,13 @@ var require_autoPipelining = __commonJS({
37917
37997
  pipeline[exports.kExec] = true;
37918
37998
  setImmediate(executeAutoPipeline, client, slotKey);
37919
37999
  }
37920
- const autoPipelinePromise = new Promise(function(resolve3, reject) {
38000
+ const autoPipelinePromise = new Promise(function(resolve4, reject) {
37921
38001
  pipeline[exports.kCallbacks].push(function(err, value) {
37922
38002
  if (err) {
37923
38003
  reject(err);
37924
38004
  return;
37925
38005
  }
37926
- resolve3(value);
38006
+ resolve4(value);
37927
38007
  });
37928
38008
  if (functionName === "call") {
37929
38009
  args.unshift(commandName);
@@ -38158,8 +38238,8 @@ var require_Pipeline = __commonJS({
38158
38238
  this[name] = redis[name];
38159
38239
  this[name + "Buffer"] = redis[name + "Buffer"];
38160
38240
  });
38161
- this.promise = new Promise((resolve3, reject) => {
38162
- this.resolve = resolve3;
38241
+ this.promise = new Promise((resolve4, reject) => {
38242
+ this.resolve = resolve4;
38163
38243
  this.reject = reject;
38164
38244
  });
38165
38245
  const _this = this;
@@ -38459,13 +38539,13 @@ var require_transaction = __commonJS({
38459
38539
  if (this.isCluster && !this.redis.slots.length) {
38460
38540
  if (this.redis.status === "wait")
38461
38541
  this.redis.connect().catch(utils_1.noop);
38462
- return (0, standard_as_callback_1.default)(new Promise((resolve3, reject) => {
38542
+ return (0, standard_as_callback_1.default)(new Promise((resolve4, reject) => {
38463
38543
  this.redis.delayUntilReady((err) => {
38464
38544
  if (err) {
38465
38545
  reject(err);
38466
38546
  return;
38467
38547
  }
38468
- this.exec(pipeline).then(resolve3, reject);
38548
+ this.exec(pipeline).then(resolve4, reject);
38469
38549
  });
38470
38550
  }), callback);
38471
38551
  }
@@ -39594,7 +39674,7 @@ var require_cluster = __commonJS({
39594
39674
  * Connect to a cluster
39595
39675
  */
39596
39676
  connect() {
39597
- return new Promise((resolve3, reject) => {
39677
+ return new Promise((resolve4, reject) => {
39598
39678
  if (this.status === "connecting" || this.status === "connect" || this.status === "ready") {
39599
39679
  reject(new Error("Redis is already connecting/connected"));
39600
39680
  return;
@@ -39623,7 +39703,7 @@ var require_cluster = __commonJS({
39623
39703
  this.retryAttempts = 0;
39624
39704
  this.executeOfflineCommands();
39625
39705
  this.resetNodesRefreshInterval();
39626
- resolve3();
39706
+ resolve4();
39627
39707
  };
39628
39708
  let closeListener = void 0;
39629
39709
  const refreshListener = () => {
@@ -40233,7 +40313,7 @@ var require_cluster = __commonJS({
40233
40313
  });
40234
40314
  }
40235
40315
  resolveSrv(hostname2) {
40236
- return new Promise((resolve3, reject) => {
40316
+ return new Promise((resolve4, reject) => {
40237
40317
  this.options.resolveSrv(hostname2, (err, records) => {
40238
40318
  if (err) {
40239
40319
  return reject(err);
@@ -40247,7 +40327,7 @@ var require_cluster = __commonJS({
40247
40327
  if (!group.records.length) {
40248
40328
  sortedKeys.shift();
40249
40329
  }
40250
- self2.dnsLookup(record.name).then((host) => resolve3({
40330
+ self2.dnsLookup(record.name).then((host) => resolve4({
40251
40331
  host,
40252
40332
  port: record.port
40253
40333
  }), tryFirstOne);
@@ -40257,14 +40337,14 @@ var require_cluster = __commonJS({
40257
40337
  });
40258
40338
  }
40259
40339
  dnsLookup(hostname2) {
40260
- return new Promise((resolve3, reject) => {
40340
+ return new Promise((resolve4, reject) => {
40261
40341
  this.options.dnsLookup(hostname2, (err, address) => {
40262
40342
  if (err) {
40263
40343
  debug2("failed to resolve hostname %s to IP: %s", hostname2, err.message);
40264
40344
  reject(err);
40265
40345
  } else {
40266
40346
  debug2("resolved hostname %s to IP %s", hostname2, address);
40267
- resolve3(address);
40347
+ resolve4(address);
40268
40348
  }
40269
40349
  });
40270
40350
  });
@@ -40419,7 +40499,7 @@ var require_StandaloneConnector = __commonJS({
40419
40499
  if (options.tls) {
40420
40500
  Object.assign(connectionOptions, options.tls);
40421
40501
  }
40422
- return new Promise((resolve3, reject) => {
40502
+ return new Promise((resolve4, reject) => {
40423
40503
  process.nextTick(() => {
40424
40504
  if (!this.connecting) {
40425
40505
  reject(new Error(utils_1.CONNECTION_CLOSED_ERROR_MSG));
@@ -40438,7 +40518,7 @@ var require_StandaloneConnector = __commonJS({
40438
40518
  this.stream.once("error", (err) => {
40439
40519
  this.firstError = err;
40440
40520
  });
40441
- resolve3(this.stream);
40521
+ resolve4(this.stream);
40442
40522
  });
40443
40523
  });
40444
40524
  }
@@ -40594,7 +40674,7 @@ var require_SentinelConnector = __commonJS({
40594
40674
  const error = new Error(errorMsg);
40595
40675
  if (typeof retryDelay === "number") {
40596
40676
  eventEmitter("error", error);
40597
- await new Promise((resolve3) => setTimeout(resolve3, retryDelay));
40677
+ await new Promise((resolve4) => setTimeout(resolve4, retryDelay));
40598
40678
  return connectToNext();
40599
40679
  } else {
40600
40680
  throw error;
@@ -41911,7 +41991,7 @@ var require_Redis = __commonJS({
41911
41991
  * if the connection fails, times out, or if Redis is already connecting/connected.
41912
41992
  */
41913
41993
  connect(callback) {
41914
- const promise = new Promise((resolve3, reject) => {
41994
+ const promise = new Promise((resolve4, reject) => {
41915
41995
  if (this.status === "connecting" || this.status === "connect" || this.status === "ready") {
41916
41996
  reject(new Error("Redis is already connecting/connected"));
41917
41997
  return;
@@ -41990,7 +42070,7 @@ var require_Redis = __commonJS({
41990
42070
  }
41991
42071
  const connectionReadyHandler = function() {
41992
42072
  _this.removeListener("close", connectionCloseHandler);
41993
- resolve3();
42073
+ resolve4();
41994
42074
  };
41995
42075
  var connectionCloseHandler = function() {
41996
42076
  _this.removeListener("ready", connectionReadyHandler);
@@ -42084,10 +42164,10 @@ var require_Redis = __commonJS({
42084
42164
  monitor: true,
42085
42165
  lazyConnect: false
42086
42166
  });
42087
- return (0, standard_as_callback_1.default)(new Promise(function(resolve3, reject) {
42167
+ return (0, standard_as_callback_1.default)(new Promise(function(resolve4, reject) {
42088
42168
  monitorInstance.once("error", reject);
42089
42169
  monitorInstance.once("monitoring", function() {
42090
- resolve3(monitorInstance);
42170
+ resolve4(monitorInstance);
42091
42171
  });
42092
42172
  }), callback);
42093
42173
  }
@@ -42860,7 +42940,15 @@ async function runMenu() {
42860
42940
  });
42861
42941
  if (!q(setup) && setup) {
42862
42942
  const { runInitFlow: runInitFlow2 } = await Promise.resolve().then(() => (init_init(), init_exports));
42863
- await runInitFlow2(client, { cwd: process.cwd(), dryRun: false, noScripts: false });
42943
+ const outcome = await runInitFlow2(client, {
42944
+ cwd: process.cwd(),
42945
+ dryRun: false,
42946
+ noScripts: false
42947
+ });
42948
+ if (outcome.exitCode === 0) {
42949
+ ye("All set. Run keynv again anytime to manage secrets.");
42950
+ return 0;
42951
+ }
42864
42952
  }
42865
42953
  }
42866
42954
  }
@@ -42930,8 +43018,8 @@ var init_menu = __esm({
42930
43018
  "src/ui/menu.ts"() {
42931
43019
  init_dist5();
42932
43020
  init_http();
42933
- init_detect();
42934
43021
  init_store();
43022
+ init_detect();
42935
43023
  init_version();
42936
43024
  init_audit2();
42937
43025
  init_login();
@@ -44657,44 +44745,48 @@ var AuditListCommand = class extends Command {
44657
44745
  sinceId = options_exports.String("--since-id");
44658
44746
  json = options_exports.Boolean("--json", false);
44659
44747
  async execute() {
44660
- const client = new ApiClient();
44661
- const data = await client.request(
44662
- "/v1/audit",
44663
- {
44664
- query: {
44665
- event_type: this.eventType,
44666
- limit: this.limit,
44667
- since_id: this.sinceId
44748
+ try {
44749
+ const client = new ApiClient();
44750
+ const data = await client.request(
44751
+ "/v1/audit",
44752
+ {
44753
+ query: {
44754
+ event_type: this.eventType,
44755
+ limit: this.limit,
44756
+ since_id: this.sinceId
44757
+ }
44668
44758
  }
44669
- }
44670
- );
44671
- if (this.json) {
44672
- this.context.stdout.write(`${JSON.stringify(data, null, 2)}
44759
+ );
44760
+ if (this.json) {
44761
+ this.context.stdout.write(`${JSON.stringify(data, null, 2)}
44673
44762
  `);
44674
- return 0;
44675
- }
44676
- if (data.entries.length === 0) {
44677
- this.context.stdout.write("no audit entries\n");
44678
- return 0;
44679
- }
44680
- this.context.stdout.write(
44681
- `${table(
44682
- ["id", "ts", "actor", "agent", "event"],
44683
- data.entries.map((e2) => [
44684
- String(e2.id),
44685
- e2.ts,
44686
- e2.actor_user_id ?? "(none)",
44687
- e2.actor_agent,
44688
- e2.event_type
44689
- ])
44690
- )}
44763
+ return 0;
44764
+ }
44765
+ if (data.entries.length === 0) {
44766
+ this.context.stdout.write("no audit entries\n");
44767
+ return 0;
44768
+ }
44769
+ this.context.stdout.write(
44770
+ `${table(
44771
+ ["id", "ts", "actor", "agent", "event"],
44772
+ data.entries.map((e2) => [
44773
+ String(e2.id),
44774
+ e2.ts,
44775
+ e2.actor_user_id ?? "(none)",
44776
+ e2.actor_agent,
44777
+ e2.event_type
44778
+ ])
44779
+ )}
44691
44780
  `
44692
- );
44693
- if (data.next_cursor) {
44694
- this.context.stdout.write(`(next: --since-id ${data.next_cursor})
44781
+ );
44782
+ if (data.next_cursor) {
44783
+ this.context.stdout.write(`(next: --since-id ${data.next_cursor})
44695
44784
  `);
44785
+ }
44786
+ return 0;
44787
+ } catch (err) {
44788
+ return handleExecError(this.context.stderr, err);
44696
44789
  }
44697
- return 0;
44698
44790
  }
44699
44791
  };
44700
44792
  var AuditVerifyCommand = class extends Command {
@@ -44704,27 +44796,29 @@ var AuditVerifyCommand = class extends Command {
44704
44796
  });
44705
44797
  json = options_exports.Boolean("--json", false);
44706
44798
  async execute() {
44707
- const client = new ApiClient();
44708
- const data = await client.request("/v1/audit/verify", { method: "POST" });
44709
- if (this.json) {
44710
- this.context.stdout.write(`${JSON.stringify(data, null, 2)}
44799
+ try {
44800
+ const client = new ApiClient();
44801
+ const data = await client.request("/v1/audit/verify", { method: "POST" });
44802
+ if (this.json) {
44803
+ this.context.stdout.write(`${JSON.stringify(data, null, 2)}
44711
44804
  `);
44712
- return data.ok ? 0 : 1;
44713
- }
44714
- if (data.ok) {
44715
- this.context.stdout.write(`OK: ${data.checked} entries verified
44805
+ return data.ok ? 0 : 1;
44806
+ }
44807
+ if (data.ok) {
44808
+ this.context.stdout.write(`OK: ${data.checked} entries verified
44716
44809
  `);
44717
- return 0;
44718
- }
44719
- this.context.stdout.write(
44720
- `FAIL: chain broken at id ${data.broken_at_id} (${data.reason}); ${data.checked} entries verified before break
44810
+ return 0;
44811
+ }
44812
+ this.context.stdout.write(
44813
+ `FAIL: chain broken at id ${data.broken_at_id} (${data.reason}); ${data.checked} entries verified before break
44721
44814
  `
44722
- );
44723
- return 1;
44815
+ );
44816
+ return 1;
44817
+ } catch (err) {
44818
+ return handleExecError(this.context.stderr, err);
44819
+ }
44724
44820
  }
44725
44821
  };
44726
-
44727
- // src/commands/exec.ts
44728
44822
  init_http();
44729
44823
  init_envFile();
44730
44824
 
@@ -45073,7 +45167,9 @@ var ENV_ALLOWLIST = [
45073
45167
  "WINDIR",
45074
45168
  "COMSPEC",
45075
45169
  "APPDATA",
45076
- "LOCALAPPDATA"
45170
+ "LOCALAPPDATA",
45171
+ "PATHEXT"
45172
+ // needed so child processes can resolve executables by name
45077
45173
  ];
45078
45174
  function spawnPrivileged(opts) {
45079
45175
  const startedAt = Date.now();
@@ -45082,15 +45178,63 @@ function spawnPrivileged(opts) {
45082
45178
  const v2 = process.env[name];
45083
45179
  if (v2 !== void 0) env2[name] = v2;
45084
45180
  }
45181
+ const nmBin = findNodeModulesBin(process.cwd());
45182
+ if (nmBin) {
45183
+ const existingPath = env2.PATH ?? "";
45184
+ env2.PATH = existingPath.startsWith(nmBin + nodePath.delimiter) ? existingPath : nmBin + nodePath.delimiter + existingPath;
45185
+ }
45085
45186
  if (opts.injectedEnv) {
45086
45187
  for (const [k2, v2] of Object.entries(opts.injectedEnv)) env2[k2] = v2;
45087
45188
  }
45088
45189
  const stdio = ["inherit", "pipe", "pipe"];
45089
- const child = spawn(opts.command, opts.args, {
45190
+ const WIN_BUILTINS = /* @__PURE__ */ new Set([
45191
+ "echo",
45192
+ "dir",
45193
+ "type",
45194
+ "copy",
45195
+ "del",
45196
+ "move",
45197
+ "ren",
45198
+ "md",
45199
+ "mkdir",
45200
+ "rd",
45201
+ "rmdir",
45202
+ "cd",
45203
+ "cls",
45204
+ "set",
45205
+ "pause",
45206
+ "find",
45207
+ "where"
45208
+ ]);
45209
+ let spawnCmd = opts.command;
45210
+ let spawnArgs = opts.args;
45211
+ let windowsVerbatimArguments = false;
45212
+ if (process.platform === "win32") {
45213
+ const comspec = env2.COMSPEC ?? process.env.COMSPEC ?? "cmd.exe";
45214
+ if (WIN_BUILTINS.has(opts.command.toLowerCase())) {
45215
+ spawnCmd = comspec;
45216
+ spawnArgs = ["/d", "/s", "/c", opts.command, ...opts.args];
45217
+ } else {
45218
+ const resolved = resolveWindowsCmd(opts.command, env2);
45219
+ if (resolved !== null) {
45220
+ const ext = nodePath.extname(resolved).toLowerCase();
45221
+ if (ext === ".cmd" || ext === ".bat") {
45222
+ const q2 = (s) => s.includes(" ") ? `"${s}"` : s;
45223
+ const inner = [q2(resolved), ...opts.args.map(q2)].join(" ");
45224
+ spawnCmd = comspec;
45225
+ spawnArgs = ["/d", "/s", "/c", `"${inner}"`];
45226
+ windowsVerbatimArguments = true;
45227
+ } else {
45228
+ spawnCmd = resolved;
45229
+ }
45230
+ }
45231
+ }
45232
+ }
45233
+ const child = spawn(spawnCmd, spawnArgs, {
45090
45234
  env: env2,
45091
45235
  stdio,
45092
45236
  detached: false,
45093
- shell: process.platform === "win32"
45237
+ windowsVerbatimArguments
45094
45238
  });
45095
45239
  const literals = opts.resolved.map((r) => r.value).filter((v2) => v2.length > 0);
45096
45240
  if (!opts.noRedact && child.stdout) {
@@ -45111,14 +45255,14 @@ function spawnPrivileged(opts) {
45111
45255
  }, opts.timeoutS * 1e3);
45112
45256
  timer.unref();
45113
45257
  }
45114
- return new Promise((resolve3, reject) => {
45258
+ return new Promise((resolve4, reject) => {
45115
45259
  child.on("error", (err) => {
45116
45260
  if (timer) clearTimeout(timer);
45117
45261
  reject(err);
45118
45262
  });
45119
45263
  child.on("close", (code, signal) => {
45120
45264
  if (timer) clearTimeout(timer);
45121
- resolve3({
45265
+ resolve4({
45122
45266
  exitCode: code ?? 0,
45123
45267
  signal,
45124
45268
  durationMs: Date.now() - startedAt
@@ -45126,6 +45270,34 @@ function spawnPrivileged(opts) {
45126
45270
  });
45127
45271
  });
45128
45272
  }
45273
+ function resolveWindowsCmd(command, subprocessEnv) {
45274
+ if (nodePath.extname(command)) return null;
45275
+ if (command.includes("/") || command.includes("\\")) return null;
45276
+ const pathExt = (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").map((e2) => e2.toLowerCase()).filter(Boolean);
45277
+ const pathStr = subprocessEnv.PATH ?? process.env.PATH ?? "";
45278
+ const pathDirs = pathStr.split(nodePath.delimiter).filter(Boolean);
45279
+ for (const dir of pathDirs) {
45280
+ for (const ext of pathExt) {
45281
+ try {
45282
+ const full = nodePath.join(dir, command + ext);
45283
+ if (existsSync(full)) return full;
45284
+ } catch {
45285
+ }
45286
+ }
45287
+ }
45288
+ return null;
45289
+ }
45290
+ function findNodeModulesBin(cwd) {
45291
+ let dir = nodePath.resolve(cwd);
45292
+ for (let i = 0; i < 20; i++) {
45293
+ const candidate = nodePath.join(dir, "node_modules", ".bin");
45294
+ if (existsSync(candidate)) return candidate;
45295
+ const parent = nodePath.dirname(dir);
45296
+ if (parent === dir) break;
45297
+ dir = parent;
45298
+ }
45299
+ return null;
45300
+ }
45129
45301
 
45130
45302
  // src/commands/exec.ts
45131
45303
  var ExecCommand = class extends Command {
@@ -45182,6 +45354,10 @@ spelled \`--from\` to avoid the collision.)
45182
45354
  quiet = options_exports.Boolean("--quiet", false, {
45183
45355
  description: `Suppress the "loaded N vars from ${ENV_FILE_BASENAME}" status line.`
45184
45356
  });
45357
+ // Option.Rest: keynv options (e.g. --no-env-file) are parsed before `--`.
45358
+ // Everything after `--` is captured in rest verbatim, including subprocess
45359
+ // flags like `--port 3005` and `-v`. Always use `--` to separate keynv
45360
+ // options from the subprocess command.
45185
45361
  rest = options_exports.Rest();
45186
45362
  async execute() {
45187
45363
  if (!this.rest || this.rest.length === 0) {
@@ -45224,6 +45400,13 @@ spelled \`--from\` to avoid the collision.)
45224
45400
  );
45225
45401
  return 2;
45226
45402
  }
45403
+ if (!envFileLoaded && !this.noEnvFile && !this.envFile && !process.env.KEYNV_ENV_FILE) {
45404
+ this.context.stderr.write(
45405
+ `keynv: no ${ENV_FILE_BASENAME} found in this directory or any parent.
45406
+ Run \`keynv init\` in your project root to migrate secrets and create one.
45407
+ `
45408
+ );
45409
+ }
45227
45410
  const viaEnvSpecs = [];
45228
45411
  for (const spec of this.viaEnv ?? []) {
45229
45412
  const eq = spec.indexOf("=");
@@ -45348,7 +45531,9 @@ function signalNumber(sig) {
45348
45531
  init_dist();
45349
45532
  init_http();
45350
45533
  init_envFile();
45534
+ init_detect();
45351
45535
  init_heuristics();
45536
+ init_aiContext();
45352
45537
  init_init();
45353
45538
  init_cancel();
45354
45539
  init_tty();
@@ -45364,7 +45549,8 @@ async function resolveProjectId(client, input) {
45364
45549
  return input;
45365
45550
  }
45366
45551
  const data = await client.request("/v1/projects");
45367
- const match = data.projects.find((p2) => p2.name === input);
45552
+ const lowerInput = input.toLowerCase();
45553
+ const match = data.projects.find((p2) => p2.name.toLowerCase() === lowerInput);
45368
45554
  if (!match) throw new Error(`project not found: ${input}`);
45369
45555
  return match.id;
45370
45556
  }
@@ -45375,25 +45561,29 @@ var ProjectListCommand = class extends Command {
45375
45561
  });
45376
45562
  json = options_exports.Boolean("--json", false);
45377
45563
  async execute() {
45378
- const client = new ApiClient();
45379
- const data = await client.request("/v1/projects");
45380
- if (this.json) {
45381
- this.context.stdout.write(`${JSON.stringify(data, null, 2)}
45564
+ try {
45565
+ const client = new ApiClient();
45566
+ const data = await client.request("/v1/projects");
45567
+ if (this.json) {
45568
+ this.context.stdout.write(`${JSON.stringify(data, null, 2)}
45382
45569
  `);
45570
+ return 0;
45571
+ }
45572
+ if (data.projects.length === 0) {
45573
+ this.context.stdout.write("no projects\n");
45574
+ return 0;
45575
+ }
45576
+ this.context.stdout.write(
45577
+ `${table(
45578
+ ["name", "id", "created_at"],
45579
+ data.projects.map((p2) => [p2.name, p2.id, p2.created_at])
45580
+ )}
45581
+ `
45582
+ );
45383
45583
  return 0;
45584
+ } catch (err) {
45585
+ return handleExecError(this.context.stderr, err);
45384
45586
  }
45385
- if (data.projects.length === 0) {
45386
- this.context.stdout.write("no projects\n");
45387
- return 0;
45388
- }
45389
- this.context.stdout.write(
45390
- `${table(
45391
- ["name", "id", "created_at"],
45392
- data.projects.map((p2) => [p2.name, p2.id, p2.created_at])
45393
- )}
45394
- `
45395
- );
45396
- return 0;
45397
45587
  }
45398
45588
  };
45399
45589
  var ProjectCreateCommand = class extends Command {
@@ -45407,28 +45597,32 @@ var ProjectCreateCommand = class extends Command {
45407
45597
  description: 'Environment spec: name[:tier[:approval]]. Tier \u2208 {production,non-production}; "approval" sets require_approval=true.'
45408
45598
  });
45409
45599
  async execute() {
45410
- const envs = (this.envs ?? ["dev"]).map((spec) => {
45411
- const [name, tier, approval] = spec.split(":");
45412
- return {
45413
- name: name ?? "",
45414
- tier: tier ?? "non-production",
45415
- require_approval: approval === "approval"
45416
- };
45417
- });
45418
- const client = new ApiClient();
45419
- const result = await client.request("/v1/projects", {
45420
- method: "POST",
45421
- body: { name: this.name, environments: envs }
45422
- });
45423
- this.context.stdout.write(`created project ${result.name} (${result.id})
45600
+ try {
45601
+ const envs = (this.envs ?? ["dev"]).map((spec) => {
45602
+ const [name, tier, approval] = spec.split(":");
45603
+ return {
45604
+ name: name ?? "",
45605
+ tier: tier ?? "non-production",
45606
+ require_approval: approval === "approval"
45607
+ };
45608
+ });
45609
+ const client = new ApiClient();
45610
+ const result = await client.request("/v1/projects", {
45611
+ method: "POST",
45612
+ body: { name: this.name, environments: envs }
45613
+ });
45614
+ this.context.stdout.write(`created project ${result.name} (${result.id})
45424
45615
  `);
45425
- for (const e2 of envs) {
45426
- this.context.stdout.write(
45427
- ` env: ${e2.name} (tier=${e2.tier}, approval=${e2.require_approval})
45616
+ for (const e2 of envs) {
45617
+ this.context.stdout.write(
45618
+ ` env: ${e2.name} (tier=${e2.tier}, approval=${e2.require_approval})
45428
45619
  `
45429
- );
45620
+ );
45621
+ }
45622
+ return 0;
45623
+ } catch (err) {
45624
+ return handleExecError(this.context.stderr, err);
45430
45625
  }
45431
- return 0;
45432
45626
  }
45433
45627
  };
45434
45628
  var ProjectDescribeCommand = class extends Command {
@@ -45443,23 +45637,27 @@ var ProjectDescribeCommand = class extends Command {
45443
45637
  id = options_exports.String();
45444
45638
  json = options_exports.Boolean("--json", false);
45445
45639
  async execute() {
45446
- const client = new ApiClient();
45447
- const projectId2 = await resolveProjectId(client, this.id);
45448
- const data = await client.request(`/v1/projects/${projectId2}`);
45449
- if (this.json) {
45450
- this.context.stdout.write(`${JSON.stringify(data, null, 2)}
45640
+ try {
45641
+ const client = new ApiClient();
45642
+ const projectId2 = await resolveProjectId(client, this.id);
45643
+ const data = await client.request(`/v1/projects/${projectId2}`);
45644
+ if (this.json) {
45645
+ this.context.stdout.write(`${JSON.stringify(data, null, 2)}
45451
45646
  `);
45452
- return 0;
45453
- }
45454
- this.context.stdout.write(`project: ${data.name} (${data.id})
45647
+ return 0;
45648
+ }
45649
+ this.context.stdout.write(`project: ${data.name} (${data.id})
45455
45650
  `);
45456
- for (const e2 of data.environments) {
45457
- this.context.stdout.write(
45458
- ` env: ${e2.name} (tier=${e2.tier}, approval=${e2.require_approval})
45651
+ for (const e2 of data.environments) {
45652
+ this.context.stdout.write(
45653
+ ` env: ${e2.name} (tier=${e2.tier}, approval=${e2.require_approval})
45459
45654
  `
45460
- );
45655
+ );
45656
+ }
45657
+ return 0;
45658
+ } catch (err) {
45659
+ return handleExecError(this.context.stderr, err);
45461
45660
  }
45462
- return 0;
45463
45661
  }
45464
45662
  };
45465
45663
  var ProjectDeleteCommand = class extends Command {
@@ -45472,15 +45670,27 @@ var ProjectDeleteCommand = class extends Command {
45472
45670
  this.context.stderr.write("keynv: refusing to delete without --force\n");
45473
45671
  return 2;
45474
45672
  }
45475
- const client = new ApiClient();
45476
- await client.request(`/v1/projects/${this.id}`, { method: "DELETE" });
45477
- this.context.stdout.write(`deleted project ${this.id}
45673
+ try {
45674
+ const client = new ApiClient();
45675
+ await client.request(`/v1/projects/${this.id}`, { method: "DELETE" });
45676
+ this.context.stdout.write(`deleted project ${this.id}
45478
45677
  `);
45479
- return 0;
45678
+ return 0;
45679
+ } catch (err) {
45680
+ return handleExecError(this.context.stderr, err);
45681
+ }
45480
45682
  }
45481
45683
  };
45482
45684
 
45483
45685
  // src/commands/init.ts
45686
+ function toAliasKey2(name) {
45687
+ if (!name) return name;
45688
+ const KEY_RE3 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
45689
+ if (KEY_RE3.test(name)) return name;
45690
+ const normalised = name.toLowerCase().replace(/_/g, "-");
45691
+ if (KEY_RE3.test(normalised)) return normalised;
45692
+ return normalised.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 64) || "key";
45693
+ }
45484
45694
  var InitCommand = class extends Command {
45485
45695
  static paths = [["init"]];
45486
45696
  static usage = Command.Usage({
@@ -45499,15 +45709,19 @@ mappings that would be written to .keynv.env, then exits without
45499
45709
  touching any files or making any network calls. Use it to preview
45500
45710
  what init will do before committing.
45501
45711
 
45502
- Requires an interactive terminal (clack TUI). For scripted
45503
- migration, use the lower-level \`keynv project\` and \`keynv secret\`
45504
- commands directly.
45712
+ For scripted migration, use \`--env-file\` or \`--secret\` flags, or
45713
+ \`--yes\` to auto-scan the project directory and set up without
45714
+ any prompts.
45505
45715
  `,
45506
45716
  examples: [
45507
45717
  ["Walk the current project", "$0 init"],
45508
45718
  ["Preview without writing or uploading", "$0 init --dry-run"],
45509
45719
  ["Skip the package.json script-wrapping step", "$0 init --no-scripts"],
45510
- ["Non-interactive (CI/CD)", "$0 init --env-file .env --project myproject --env dev"]
45720
+ ["Non-interactive (CI/CD)", "$0 init --env-file .env --project myproject --env dev"],
45721
+ [
45722
+ "Auto-scan & set up without prompts (CI/CD)",
45723
+ "$0 init --yes"
45724
+ ]
45511
45725
  ]
45512
45726
  });
45513
45727
  dryRun = options_exports.Boolean("--dry-run", false, {
@@ -45528,6 +45742,9 @@ commands directly.
45528
45742
  secret = options_exports.Array("--secret", {
45529
45743
  description: "KEY=value secret to upload (non-interactive). Can be specified multiple times."
45530
45744
  });
45745
+ yes = options_exports.Boolean("--yes", false, {
45746
+ description: "Auto-scan .env files, classify, and set up without prompts. Implies non-interactive mode."
45747
+ });
45531
45748
  async execute() {
45532
45749
  const client = new ApiClient();
45533
45750
  await client.ensureHydrated();
@@ -45537,13 +45754,13 @@ commands directly.
45537
45754
  }
45538
45755
  const hasEnvFile = this.envFile != null;
45539
45756
  const hasSecrets = this.secret != null && this.secret.length > 0;
45540
- const isNonInteractive = hasEnvFile || hasSecrets;
45757
+ const isNonInteractive = hasEnvFile || hasSecrets || this.dryRun || this.yes;
45541
45758
  if (isNonInteractive) {
45542
45759
  return this.runNonInteractive(client);
45543
45760
  }
45544
45761
  if (!isInteractive()) {
45545
45762
  this.context.stderr.write(
45546
- "keynv init requires an interactive terminal. Use --env-file or --secret for scripted setup.\n"
45763
+ "keynv init requires an interactive terminal. Use --dry-run, --env-file, or --secret for scripted setup.\n"
45547
45764
  );
45548
45765
  return 1;
45549
45766
  }
@@ -45563,6 +45780,9 @@ commands directly.
45563
45780
  }
45564
45781
  }
45565
45782
  async runNonInteractive(client) {
45783
+ if (this.yes && !this.envFile && !this.secret) {
45784
+ return this.runAutoScan(client);
45785
+ }
45566
45786
  const projectName = this.project;
45567
45787
  if (!projectName) {
45568
45788
  this.context.stderr.write("keynv: --project is required in non-interactive mode.\n");
@@ -45582,7 +45802,7 @@ commands directly.
45582
45802
  const content = readFileSync(this.envFile, "utf8");
45583
45803
  const entries = parseEnvFile(content, this.envFile);
45584
45804
  for (const e2 of entries) {
45585
- if (classifyEntry(e2.name, e2.value).verdict !== "skip") {
45805
+ if (classifyEntry(e2.name, e2.value).verdict === "secret") {
45586
45806
  secrets.push({ name: e2.name, value: e2.value });
45587
45807
  }
45588
45808
  }
@@ -45612,34 +45832,134 @@ commands directly.
45612
45832
  return 0;
45613
45833
  }
45614
45834
  if (this.dryRun) {
45615
- this.context.stdout.write(
45616
- `keynv: dry-run \u2014 would upload ${secrets.length} secret(s) to project ${projectName} (${projectId2}) in env ${envName}
45835
+ if (this.envFile || this.secret && this.secret.length > 0) {
45836
+ this.context.stdout.write(
45837
+ `keynv: dry-run \u2014 would upload ${secrets.length} secret(s) to project ${projectName} (${projectId2}) in env ${envName}
45617
45838
  `
45839
+ );
45840
+ for (const { name } of secrets) {
45841
+ const aliasKey = toAliasKey2(name);
45842
+ this.context.stdout.write(` ${name}=@${projectName}.${envName}.${aliasKey}
45843
+ `);
45844
+ }
45845
+ return 0;
45846
+ }
45847
+ this.context.stdout.write(
45848
+ "keynv: dry-run mode \u2014 no --env-file or --secret provided. Nothing to scan.\n"
45618
45849
  );
45850
+ return 0;
45851
+ }
45852
+ const secretsWithKeys = secrets.map((s) => ({ ...s, aliasKey: toAliasKey2(s.name) }));
45853
+ return this.uploadSecrets(client, projectId2, projectName, envName, secretsWithKeys);
45854
+ }
45855
+ /**
45856
+ * Auto-scan mode (--yes without explicit --env-file). Finds .env files
45857
+ * in the project root, classifies entries, creates a project, uploads
45858
+ * secrets, and writes .keynv.env — all without prompts.
45859
+ */
45860
+ async runAutoScan(client) {
45861
+ const root = findProjectRoot(process.cwd());
45862
+ if (!root) {
45863
+ this.context.stderr.write(
45864
+ "keynv: no project root found (no package.json, .git, etc.).\n"
45865
+ );
45866
+ return 1;
45867
+ }
45868
+ const envFiles = findEnvFiles(root.path);
45869
+ if (envFiles.length === 0) {
45870
+ this.context.stdout.write("keynv: no .env files found. Nothing to migrate.\n");
45871
+ return 0;
45872
+ }
45873
+ const projectName = this.project ?? root.suggestedName;
45874
+ const envName = this.env ?? suggestedEnvForSuffix(envFiles[0]?.suffix ?? null);
45875
+ const secrets = [];
45876
+ for (const f of envFiles) {
45877
+ try {
45878
+ const entries = parseEnvFile(readFileSync(f.path, "utf8"), f.path);
45879
+ for (const e2 of entries) {
45880
+ if (classifyEntry(e2.name, e2.value).verdict === "secret") {
45881
+ secrets.push({ name: e2.name, value: e2.value });
45882
+ }
45883
+ }
45884
+ } catch {
45885
+ this.context.stderr.write(`keynv: warning \u2014 could not parse ${f.name}, skipping.
45886
+ `);
45887
+ }
45888
+ }
45889
+ if (secrets.length === 0) {
45890
+ this.context.stdout.write("keynv: no secrets detected in .env files. Nothing to upload.\n");
45891
+ return 0;
45892
+ }
45893
+ this.context.stdout.write(
45894
+ `keynv: auto-scan found ${secrets.length} secret(s) across ${envFiles.length} file(s).
45895
+ `
45896
+ );
45897
+ if (this.dryRun) {
45619
45898
  for (const { name } of secrets) {
45620
- const aliasKey = name.toLowerCase().replace(/_/g, "-");
45899
+ const aliasKey = toAliasKey2(name);
45621
45900
  this.context.stdout.write(` ${name}=@${projectName}.${envName}.${aliasKey}
45622
45901
  `);
45623
45902
  }
45624
45903
  return 0;
45625
45904
  }
45905
+ let projectId2;
45906
+ try {
45907
+ projectId2 = await resolveProjectId(client, projectName);
45908
+ } catch {
45909
+ const created = await client.request("/v1/projects", {
45910
+ method: "POST",
45911
+ body: { name: projectName, environments: [{ name: envName, tier: "non-production", require_approval: false }] }
45912
+ });
45913
+ projectId2 = created.id;
45914
+ this.context.stdout.write(`keynv: created project "${projectName}" (${projectId2}).
45915
+ `);
45916
+ }
45917
+ const secretsWithKeys = secrets.map((s) => ({ ...s, aliasKey: toAliasKey2(s.name) }));
45918
+ const result = await this.uploadSecrets(client, projectId2, projectName, envName, secretsWithKeys);
45919
+ if (result !== 0) return result;
45920
+ const aliasLines = secretsWithKeys.map((s) => `# ${s.name}
45921
+ ${s.name}=@${projectName}.${envName}.${s.aliasKey}`).join("\n");
45922
+ const keynvEnvPath = join(root.path, ".keynv.env");
45923
+ writeFileSync(keynvEnvPath, `# Auto-generated by keynv init --yes
45924
+ ${aliasLines}
45925
+ `);
45926
+ this.context.stdout.write(`keynv: wrote ${keynvEnvPath}
45927
+ `);
45928
+ try {
45929
+ const outcome = writeAiContext(root.path);
45930
+ if (outcome === "created") this.context.stdout.write("keynv: wrote AGENTS.md\n");
45931
+ } catch {
45932
+ this.context.stdout.write("keynv: warning \u2014 could not write AGENTS.md.\n");
45933
+ }
45934
+ for (const f of envFiles) {
45935
+ unlinkSync(f.path);
45936
+ this.context.stdout.write(`keynv: removed ${f.name} (secrets migrated to vault).
45937
+ `);
45938
+ }
45939
+ this.context.stdout.write("keynv: done. Use `keynv exec` to run commands with resolved secrets.\n");
45940
+ return 0;
45941
+ }
45942
+ /**
45943
+ * Upload secrets to the vault and print the result. Shared between
45944
+ * runNonInteractive and runAutoScan.
45945
+ */
45946
+ async uploadSecrets(client, projectId2, projectName, envName, secrets) {
45626
45947
  let uploaded = 0;
45627
45948
  const failed = [];
45628
- for (const { name, value } of secrets) {
45629
- const aliasKey = name.toLowerCase().replace(/_/g, "-");
45630
- const alias2 = buildAlias({ project: projectName, environment: envName, key: aliasKey });
45949
+ for (const s of secrets) {
45950
+ const alias2 = buildAlias({ project: projectName, environment: envName, key: s.aliasKey });
45631
45951
  if (!alias2) {
45632
- failed.push(`${name} (invalid alias key: ${aliasKey})`);
45952
+ failed.push({ name: s.name, reason: `invalid alias key: ${s.aliasKey}` });
45633
45953
  continue;
45634
45954
  }
45635
45955
  try {
45636
45956
  await client.request(`/v1/projects/${projectId2}/secrets`, {
45637
45957
  method: "POST",
45638
- body: { env: envName, key: aliasKey, value }
45958
+ body: { env: envName, key: s.aliasKey, value: s.value }
45639
45959
  });
45640
45960
  uploaded++;
45641
45961
  } catch (err) {
45642
- failed.push(`${name}: ${err instanceof Error ? err.message : String(err)}`);
45962
+ failed.push({ name: s.name, reason: err instanceof Error ? err.message : String(err) });
45643
45963
  }
45644
45964
  }
45645
45965
  this.context.stdout.write(
@@ -45647,7 +45967,7 @@ commands directly.
45647
45967
  `
45648
45968
  );
45649
45969
  if (failed.length > 0) {
45650
- for (const f of failed) this.context.stderr.write(` failed: ${f}
45970
+ for (const f of failed) this.context.stderr.write(` failed: ${f.name} \u2014 ${f.reason}
45651
45971
  `);
45652
45972
  return 1;
45653
45973
  }
@@ -45669,7 +45989,7 @@ async function promptHidden(prompt) {
45669
45989
  process.stdin.setRawMode(true);
45670
45990
  process.stdin.resume();
45671
45991
  process.stdin.setEncoding("utf8");
45672
- return new Promise((resolve3) => {
45992
+ return new Promise((resolve4) => {
45673
45993
  let buf = "";
45674
45994
  const onData = (chunk) => {
45675
45995
  for (const ch of chunk) {
@@ -45678,7 +45998,7 @@ async function promptHidden(prompt) {
45678
45998
  process.stdin.pause();
45679
45999
  process.stdin.removeListener("data", onData);
45680
46000
  process.stdout.write("\n");
45681
- resolve3(buf);
46001
+ resolve4(buf);
45682
46002
  return;
45683
46003
  }
45684
46004
  if (ch === "") {
@@ -45696,10 +46016,10 @@ async function promptHidden(prompt) {
45696
46016
  }
45697
46017
  async function promptLine(prompt) {
45698
46018
  const rl = createInterface({ input: process.stdin, output: process.stdout });
45699
- return new Promise((resolve3) => {
46019
+ return new Promise((resolve4) => {
45700
46020
  rl.question(prompt, (answer) => {
45701
46021
  rl.close();
45702
- resolve3(answer.trim());
46022
+ resolve4(answer.trim());
45703
46023
  });
45704
46024
  });
45705
46025
  }
@@ -45732,6 +46052,13 @@ var LoginCommand = class extends Command {
45732
46052
  });
45733
46053
  async execute() {
45734
46054
  const finalServerUrl = this.server ?? DEFAULT_SERVER_URL;
46055
+ try {
46056
+ new URL(finalServerUrl);
46057
+ } catch {
46058
+ this.context.stderr.write(`keynv: invalid server URL '${finalServerUrl}'
46059
+ `);
46060
+ return 1;
46061
+ }
45735
46062
  if (this.token) {
45736
46063
  return this.loginWithToken(finalServerUrl, this.token);
45737
46064
  }
@@ -45754,11 +46081,20 @@ var LoginCommand = class extends Command {
45754
46081
  }
45755
46082
  const email2 = this.email ?? await promptLine("email: ");
45756
46083
  const password = this.password ?? await promptHidden("password: ");
45757
- const res = await fetch(new URL("/v1/auth/login", finalServerUrl).toString(), {
45758
- method: "POST",
45759
- headers: { "content-type": "application/json", "x-keynv-agent": AGENT },
45760
- body: JSON.stringify({ email: email2, password })
45761
- });
46084
+ let res;
46085
+ try {
46086
+ res = await fetch(new URL("/v1/auth/login", finalServerUrl).toString(), {
46087
+ method: "POST",
46088
+ headers: { "content-type": "application/json", "x-keynv-agent": AGENT },
46089
+ body: JSON.stringify({ email: email2, password })
46090
+ });
46091
+ } catch (err) {
46092
+ this.context.stderr.write(
46093
+ `keynv: cannot reach server '${finalServerUrl}' \u2014 ${err instanceof Error ? err.message : String(err)}
46094
+ `
46095
+ );
46096
+ return 1;
46097
+ }
45762
46098
  if (!res.ok) {
45763
46099
  const text = await res.text();
45764
46100
  let msg = `login failed (${res.status})`;
@@ -45804,9 +46140,18 @@ var LoginCommand = class extends Command {
45804
46140
  return 0;
45805
46141
  }
45806
46142
  async loginWithToken(serverUrl, token) {
45807
- const res = await fetch(new URL("/v1/whoami", serverUrl).toString(), {
45808
- headers: { authorization: `Bearer ${token}`, "x-keynv-agent": AGENT }
45809
- });
46143
+ let res;
46144
+ try {
46145
+ res = await fetch(new URL("/v1/whoami", serverUrl).toString(), {
46146
+ headers: { authorization: `Bearer ${token}`, "x-keynv-agent": AGENT }
46147
+ });
46148
+ } catch (err) {
46149
+ this.context.stderr.write(
46150
+ `keynv: cannot reach server '${serverUrl}' \u2014 ${err instanceof Error ? err.message : String(err)}
46151
+ `
46152
+ );
46153
+ return 1;
46154
+ }
45810
46155
  if (!res.ok) {
45811
46156
  const text = await res.text();
45812
46157
  let msg = `token login failed (${res.status})`;
@@ -45884,36 +46229,40 @@ var WhoamiCommand = class extends Command {
45884
46229
  });
45885
46230
  json = options_exports.Boolean("--json", false);
45886
46231
  async execute() {
45887
- const client = new ApiClient();
45888
- await client.ensureHydrated();
45889
- if (!client.isLoggedIn) {
45890
- this.context.stderr.write("keynv: not logged in. Run `keynv login`.\n");
45891
- return 1;
45892
- }
45893
- const data = await client.request("/v1/whoami");
45894
- if (this.json) {
45895
- this.context.stdout.write(`${JSON.stringify(data, null, 2)}
46232
+ try {
46233
+ const client = new ApiClient();
46234
+ await client.ensureHydrated();
46235
+ if (!client.isLoggedIn) {
46236
+ this.context.stderr.write("keynv: not logged in. Run `keynv login`.\n");
46237
+ return 1;
46238
+ }
46239
+ const data = await client.request("/v1/whoami");
46240
+ if (this.json) {
46241
+ this.context.stdout.write(`${JSON.stringify(data, null, 2)}
45896
46242
  `);
45897
- return 0;
45898
- }
45899
- this.context.stdout.write(`user: ${data.email} (${data.id})
46243
+ return 0;
46244
+ }
46245
+ this.context.stdout.write(`user: ${data.email} (${data.id})
45900
46246
  `);
45901
- const orgDisplay = data.org_name ? `${data.org_name} (${data.org_id})` : data.org_id;
45902
- this.context.stdout.write(`org: ${orgDisplay}
46247
+ const orgDisplay = data.org_name ? `${data.org_name} (${data.org_id})` : data.org_id;
46248
+ this.context.stdout.write(`org: ${orgDisplay}
45903
46249
  `);
45904
- this.context.stdout.write(`role: ${data.org_role}
46250
+ this.context.stdout.write(`role: ${data.org_role}
45905
46251
  `);
45906
- if (data.memberships.length === 0) {
45907
- this.context.stdout.write("memberships: (none)\n");
45908
- } else {
45909
- this.context.stdout.write("memberships:\n");
45910
- for (const m of data.memberships) {
45911
- const proj = m.project_name ? `${m.project_name} (${m.project_id})` : m.project_id;
45912
- this.context.stdout.write(` ${proj}: ${m.role}
46252
+ if (data.memberships.length === 0) {
46253
+ this.context.stdout.write("memberships: (none)\n");
46254
+ } else {
46255
+ this.context.stdout.write("memberships:\n");
46256
+ for (const m of data.memberships) {
46257
+ const proj = m.project_name ? `${m.project_name} (${m.project_id})` : m.project_id;
46258
+ this.context.stdout.write(` ${proj}: ${m.role}
45913
46259
  `);
46260
+ }
45914
46261
  }
46262
+ return 0;
46263
+ } catch (err) {
46264
+ return handleExecError(this.context.stderr, err);
45915
46265
  }
45916
- return 0;
45917
46266
  }
45918
46267
  };
45919
46268
 
@@ -45935,15 +46284,19 @@ var MemberAddCommand = class extends Command {
45935
46284
  this.context.stderr.write("keynv: --role must be one of lead, developer, reader\n");
45936
46285
  return 1;
45937
46286
  }
45938
- const client = new ApiClient();
45939
- const projectId2 = await resolveProjectId(client, this.project);
45940
- await client.request(`/v1/projects/${projectId2}/members`, {
45941
- method: "POST",
45942
- body: { email: this.email, role: role2 }
45943
- });
45944
- this.context.stdout.write(`added ${this.email} to ${this.project} as ${role2}
46287
+ try {
46288
+ const client = new ApiClient();
46289
+ const projectId2 = await resolveProjectId(client, this.project);
46290
+ await client.request(`/v1/projects/${projectId2}/members`, {
46291
+ method: "POST",
46292
+ body: { email: this.email, role: role2 }
46293
+ });
46294
+ this.context.stdout.write(`added ${this.email} to ${this.project} as ${role2}
45945
46295
  `);
45946
- return 0;
46296
+ return 0;
46297
+ } catch (err) {
46298
+ return handleExecError(this.context.stderr, err);
46299
+ }
45947
46300
  }
45948
46301
  };
45949
46302
  var MemberRemoveCommand = class extends Command {
@@ -45952,21 +46305,25 @@ var MemberRemoveCommand = class extends Command {
45952
46305
  project = options_exports.String();
45953
46306
  email = options_exports.String();
45954
46307
  async execute() {
45955
- const client = new ApiClient();
45956
- const projectId2 = await resolveProjectId(client, this.project);
45957
- const members = await client.request(`/v1/projects/${projectId2}/members`);
45958
- const target = members.members.find((m) => m.email === this.email);
45959
- if (!target) {
45960
- this.context.stderr.write(`keynv: ${this.email} is not a member of ${this.project}
46308
+ try {
46309
+ const client = new ApiClient();
46310
+ const projectId2 = await resolveProjectId(client, this.project);
46311
+ const members = await client.request(`/v1/projects/${projectId2}/members`);
46312
+ const target = members.members.find((m) => m.email === this.email);
46313
+ if (!target) {
46314
+ this.context.stderr.write(`keynv: ${this.email} is not a member of ${this.project}
45961
46315
  `);
45962
- return 1;
45963
- }
45964
- await client.request(`/v1/projects/${projectId2}/members/${target.user_id}`, {
45965
- method: "DELETE"
45966
- });
45967
- this.context.stdout.write(`removed ${this.email} from ${this.project}
46316
+ return 1;
46317
+ }
46318
+ await client.request(`/v1/projects/${projectId2}/members/${target.user_id}`, {
46319
+ method: "DELETE"
46320
+ });
46321
+ this.context.stdout.write(`removed ${this.email} from ${this.project}
45968
46322
  `);
45969
- return 0;
46323
+ return 0;
46324
+ } catch (err) {
46325
+ return handleExecError(this.context.stderr, err);
46326
+ }
45970
46327
  }
45971
46328
  };
45972
46329
  var MemberListCommand = class extends Command {
@@ -45975,26 +46332,30 @@ var MemberListCommand = class extends Command {
45975
46332
  project = options_exports.String();
45976
46333
  json = options_exports.Boolean("--json", false);
45977
46334
  async execute() {
45978
- const client = new ApiClient();
45979
- const projectId2 = await resolveProjectId(client, this.project);
45980
- const data = await client.request(`/v1/projects/${projectId2}/members`);
45981
- if (this.json) {
45982
- this.context.stdout.write(`${JSON.stringify(data, null, 2)}
46335
+ try {
46336
+ const client = new ApiClient();
46337
+ const projectId2 = await resolveProjectId(client, this.project);
46338
+ const data = await client.request(`/v1/projects/${projectId2}/members`);
46339
+ if (this.json) {
46340
+ this.context.stdout.write(`${JSON.stringify(data, null, 2)}
45983
46341
  `);
46342
+ return 0;
46343
+ }
46344
+ if (data.members.length === 0) {
46345
+ this.context.stdout.write("no members\n");
46346
+ return 0;
46347
+ }
46348
+ this.context.stdout.write(
46349
+ `${table(
46350
+ ["email", "role", "granted_at"],
46351
+ data.members.map((m) => [m.email, m.role, m.granted_at])
46352
+ )}
46353
+ `
46354
+ );
45984
46355
  return 0;
46356
+ } catch (err) {
46357
+ return handleExecError(this.context.stderr, err);
45985
46358
  }
45986
- if (data.members.length === 0) {
45987
- this.context.stdout.write("no members\n");
45988
- return 0;
45989
- }
45990
- this.context.stdout.write(
45991
- `${table(
45992
- ["email", "role", "granted_at"],
45993
- data.members.map((m) => [m.email, m.role, m.granted_at])
45994
- )}
45995
- `
45996
- );
45997
- return 0;
45998
46359
  }
45999
46360
  };
46000
46361
  var RedactCommand = class extends Command {
@@ -46045,9 +46406,9 @@ here (see the streaming-mode limitation in the redactor package).
46045
46406
  `
46046
46407
  });
46047
46408
  async execute() {
46048
- return new Promise((resolve3, reject) => {
46409
+ return new Promise((resolve4, reject) => {
46049
46410
  const transform = createRedactStream();
46050
- this.context.stdin.pipe(transform).pipe(this.context.stdout).on("error", reject).on("finish", () => resolve3(0));
46411
+ this.context.stdin.pipe(transform).pipe(this.context.stdout).on("error", reject).on("finish", () => resolve4(0));
46051
46412
  this.context.stdin.on("error", reject);
46052
46413
  });
46053
46414
  }
@@ -46093,46 +46454,53 @@ var SecretCreateCommand = class extends Command {
46093
46454
  });
46094
46455
  stdin = options_exports.Boolean("--stdin", false);
46095
46456
  async execute() {
46096
- const client = new ApiClient();
46097
- await client.ensureHydrated();
46098
- let alias2 = this.alias;
46099
- let value = this.value;
46100
- if (!alias2) {
46101
- if (!isInteractive()) return missingAlias(this.context.stderr);
46102
- try {
46103
- const built = await promptNewSecret(client);
46104
- if (!built) return 1;
46105
- alias2 = built.alias;
46106
- value = built.value;
46107
- } catch (err) {
46108
- if (err instanceof UserCancelled) return 130;
46109
- throw err;
46457
+ try {
46458
+ const client = new ApiClient();
46459
+ await client.ensureHydrated();
46460
+ let alias2 = this.alias;
46461
+ let value = this.value;
46462
+ if (!alias2) {
46463
+ if (!isInteractive()) return missingAlias(this.context.stderr);
46464
+ try {
46465
+ const built = await promptNewSecret(client);
46466
+ if (!built) return 1;
46467
+ alias2 = built.alias;
46468
+ value = built.value;
46469
+ } catch (err) {
46470
+ if (err instanceof UserCancelled) return 130;
46471
+ throw err;
46472
+ }
46110
46473
  }
46111
- }
46112
- const parsed = parseAlias(alias2);
46113
- if (!parsed) {
46114
- this.context.stderr.write(`keynv: invalid alias '${alias2}'.
46474
+ const parsed = parseAlias(alias2);
46475
+ if (!parsed) {
46476
+ this.context.stderr.write(`keynv: invalid alias '${alias2}'.
46115
46477
  ${ALIAS_FORMAT_HINT}
46116
46478
  `);
46117
- return 1;
46118
- }
46119
- if (this.stdin) {
46120
- const chunks = [];
46121
- for await (const chunk of this.context.stdin) {
46122
- chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
46479
+ return 1;
46123
46480
  }
46124
- value = Buffer.concat(chunks).toString("utf8").replace(/\n$/, "");
46125
- } else if (value === void 0) {
46126
- value = await promptHidden("value: ");
46127
- }
46128
- const projectId2 = await resolveProjectId(client, parsed.project);
46129
- await client.request(`/v1/projects/${projectId2}/secrets`, {
46130
- method: "POST",
46131
- body: { env: parsed.environment, key: parsed.key, value }
46132
- });
46133
- this.context.stdout.write(`created ${parsed.literal}
46481
+ if (this.stdin) {
46482
+ const chunks = [];
46483
+ for await (const chunk of this.context.stdin) {
46484
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
46485
+ }
46486
+ value = Buffer.concat(chunks).toString("utf8").replace(/\n$/, "");
46487
+ } else if (value === void 0) {
46488
+ value = await promptHidden("value: ");
46489
+ }
46490
+ const projectId2 = await resolveProjectId(client, parsed.project);
46491
+ await client.request(
46492
+ `/v1/projects/${projectId2}/secrets`,
46493
+ {
46494
+ method: "POST",
46495
+ body: { env: parsed.environment, key: parsed.key, value }
46496
+ }
46497
+ );
46498
+ this.context.stdout.write(`created ${parsed.literal}
46134
46499
  `);
46135
- return 0;
46500
+ return 0;
46501
+ } catch (err) {
46502
+ return handleExecError(this.context.stderr, err);
46503
+ }
46136
46504
  }
46137
46505
  };
46138
46506
  var SecretGetCommand = class extends Command {
@@ -46143,40 +46511,44 @@ var SecretGetCommand = class extends Command {
46143
46511
  alias = options_exports.String({ required: false });
46144
46512
  json = options_exports.Boolean("--json", false);
46145
46513
  async execute() {
46146
- const client = new ApiClient();
46147
- await client.ensureHydrated();
46148
- let alias2 = this.alias;
46149
- if (!alias2) {
46150
- if (!isInteractive()) return missingAlias(this.context.stderr);
46151
- try {
46152
- alias2 = await pickAliasInteractive(client) ?? void 0;
46153
- } catch (err) {
46154
- if (err instanceof UserCancelled) return 130;
46155
- throw err;
46514
+ try {
46515
+ const client = new ApiClient();
46516
+ await client.ensureHydrated();
46517
+ let alias2 = this.alias;
46518
+ if (!alias2) {
46519
+ if (!isInteractive()) return missingAlias(this.context.stderr);
46520
+ try {
46521
+ alias2 = await pickAliasInteractive(client) ?? void 0;
46522
+ } catch (err) {
46523
+ if (err instanceof UserCancelled) return 130;
46524
+ throw err;
46525
+ }
46526
+ if (!alias2) return 1;
46156
46527
  }
46157
- if (!alias2) return 1;
46158
- }
46159
- const parsed = parseAlias(alias2);
46160
- if (!parsed) {
46161
- this.context.stderr.write(`keynv: invalid alias '${alias2}'.
46528
+ const parsed = parseAlias(alias2);
46529
+ if (!parsed) {
46530
+ this.context.stderr.write(`keynv: invalid alias '${alias2}'.
46162
46531
  ${ALIAS_FORMAT_HINT}
46163
46532
  `);
46164
- return 1;
46165
- }
46166
- const projectId2 = await resolveProjectId(client, parsed.project);
46167
- const data = await client.request(
46168
- `/v1/projects/${projectId2}/secrets/${parsed.environment}/${parsed.key}`
46169
- );
46170
- if (this.json) {
46171
- this.context.stdout.write(
46172
- `${JSON.stringify({ alias: data.alias, version: data.version, value: data.value })}
46173
- `
46533
+ return 1;
46534
+ }
46535
+ const projectId2 = await resolveProjectId(client, parsed.project);
46536
+ const data = await client.request(
46537
+ `/v1/projects/${projectId2}/secrets/${parsed.environment}/${parsed.key}`
46174
46538
  );
46175
- } else {
46176
- this.context.stdout.write(`${data.value}
46539
+ if (this.json) {
46540
+ this.context.stdout.write(
46541
+ `${JSON.stringify({ alias: data.alias, version: data.version, value: data.value })}
46542
+ `
46543
+ );
46544
+ } else {
46545
+ this.context.stdout.write(`${data.value}
46177
46546
  `);
46547
+ }
46548
+ return 0;
46549
+ } catch (err) {
46550
+ return handleExecError(this.context.stderr, err);
46178
46551
  }
46179
- return 0;
46180
46552
  }
46181
46553
  };
46182
46554
  var SecretListCommand = class extends Command {
@@ -46187,42 +46559,55 @@ var SecretListCommand = class extends Command {
46187
46559
  project = options_exports.String({ required: false });
46188
46560
  json = options_exports.Boolean("--json", false);
46189
46561
  async execute() {
46190
- const client = new ApiClient();
46191
- await client.ensureHydrated();
46192
- let projectName = this.project;
46193
- if (!projectName) {
46194
- if (!isInteractive()) {
46195
- this.context.stderr.write("keynv: missing <project>.\n");
46196
- return 1;
46562
+ try {
46563
+ const client = new ApiClient();
46564
+ await client.ensureHydrated();
46565
+ let projectName = this.project;
46566
+ if (!projectName) {
46567
+ if (!isInteractive()) {
46568
+ this.context.stderr.write("keynv: missing <project>.\n");
46569
+ return 1;
46570
+ }
46571
+ try {
46572
+ const picked = await pickProject(client, "Project");
46573
+ if (!picked) return 1;
46574
+ projectName = picked.name;
46575
+ } catch (err) {
46576
+ if (err instanceof UserCancelled) return 130;
46577
+ throw err;
46578
+ }
46197
46579
  }
46198
- try {
46199
- const picked = await pickProject(client, "Project");
46200
- if (!picked) return 1;
46201
- projectName = picked.name;
46202
- } catch (err) {
46203
- if (err instanceof UserCancelled) return 130;
46204
- throw err;
46580
+ let resolvedProjectName = projectName;
46581
+ if (projectName.startsWith("@")) {
46582
+ const parsed = parseAlias(projectName);
46583
+ if (parsed) {
46584
+ resolvedProjectName = parsed.project;
46585
+ } else {
46586
+ resolvedProjectName = projectName.slice(1).split(".")[0] ?? projectName;
46587
+ }
46205
46588
  }
46206
- }
46207
- const projectId2 = await resolveProjectId(client, projectName);
46208
- const data = await client.request(`/v1/projects/${projectId2}/secrets`);
46209
- if (this.json) {
46210
- this.context.stdout.write(`${JSON.stringify(data, null, 2)}
46589
+ const projectId2 = await resolveProjectId(client, resolvedProjectName);
46590
+ const data = await client.request(`/v1/projects/${projectId2}/secrets`);
46591
+ if (this.json) {
46592
+ this.context.stdout.write(`${JSON.stringify(data, null, 2)}
46211
46593
  `);
46594
+ return 0;
46595
+ }
46596
+ if (data.secrets.length === 0) {
46597
+ this.context.stdout.write("no secrets\n");
46598
+ return 0;
46599
+ }
46600
+ this.context.stdout.write(
46601
+ `${table(
46602
+ ["alias", "version", "created_at"],
46603
+ data.secrets.map((s) => [s.alias, String(s.version), s.created_at])
46604
+ )}
46605
+ `
46606
+ );
46212
46607
  return 0;
46608
+ } catch (err) {
46609
+ return handleExecError(this.context.stderr, err);
46213
46610
  }
46214
- if (data.secrets.length === 0) {
46215
- this.context.stdout.write("no secrets\n");
46216
- return 0;
46217
- }
46218
- this.context.stdout.write(
46219
- `${table(
46220
- ["alias", "version", "created_at"],
46221
- data.secrets.map((s) => [s.alias, String(s.version), s.created_at])
46222
- )}
46223
- `
46224
- );
46225
- return 0;
46226
46611
  }
46227
46612
  };
46228
46613
  var SecretRotateCommand = class extends Command {
@@ -46232,46 +46617,50 @@ var SecretRotateCommand = class extends Command {
46232
46617
  value = options_exports.String("--value");
46233
46618
  stdin = options_exports.Boolean("--stdin", false);
46234
46619
  async execute() {
46235
- const client = new ApiClient();
46236
- await client.ensureHydrated();
46237
- let alias2 = this.alias;
46238
- if (!alias2) {
46239
- if (!isInteractive()) return missingAlias(this.context.stderr);
46240
- try {
46241
- alias2 = await pickAliasInteractive(client) ?? void 0;
46242
- } catch (err) {
46243
- if (err instanceof UserCancelled) return 130;
46244
- throw err;
46620
+ try {
46621
+ const client = new ApiClient();
46622
+ await client.ensureHydrated();
46623
+ let alias2 = this.alias;
46624
+ if (!alias2) {
46625
+ if (!isInteractive()) return missingAlias(this.context.stderr);
46626
+ try {
46627
+ alias2 = await pickAliasInteractive(client) ?? void 0;
46628
+ } catch (err) {
46629
+ if (err instanceof UserCancelled) return 130;
46630
+ throw err;
46631
+ }
46632
+ if (!alias2) return 1;
46245
46633
  }
46246
- if (!alias2) return 1;
46247
- }
46248
- const parsed = parseAlias(alias2);
46249
- if (!parsed) {
46250
- this.context.stderr.write(`keynv: invalid alias '${alias2}'.
46634
+ const parsed = parseAlias(alias2);
46635
+ if (!parsed) {
46636
+ this.context.stderr.write(`keynv: invalid alias '${alias2}'.
46251
46637
  ${ALIAS_FORMAT_HINT}
46252
46638
  `);
46253
- return 1;
46254
- }
46255
- let value;
46256
- if (this.stdin) {
46257
- const chunks = [];
46258
- for await (const chunk of this.context.stdin) {
46259
- chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
46639
+ return 1;
46260
46640
  }
46261
- value = Buffer.concat(chunks).toString("utf8").replace(/\n$/, "");
46262
- } else if (this.value !== void 0) {
46263
- value = this.value;
46264
- } else {
46265
- value = await promptHidden("new value: ");
46266
- }
46267
- const projectId2 = await resolveProjectId(client, parsed.project);
46268
- const data = await client.request(
46269
- `/v1/projects/${projectId2}/secrets/${parsed.environment}/${parsed.key}/rotate`,
46270
- { method: "POST", body: { new_value: value } }
46271
- );
46272
- this.context.stdout.write(`rotated ${data.alias} \u2192 v${data.version}
46641
+ let value;
46642
+ if (this.stdin) {
46643
+ const chunks = [];
46644
+ for await (const chunk of this.context.stdin) {
46645
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
46646
+ }
46647
+ value = Buffer.concat(chunks).toString("utf8").replace(/\n$/, "");
46648
+ } else if (this.value !== void 0) {
46649
+ value = this.value;
46650
+ } else {
46651
+ value = await promptHidden("new value: ");
46652
+ }
46653
+ const projectId2 = await resolveProjectId(client, parsed.project);
46654
+ const data = await client.request(
46655
+ `/v1/projects/${projectId2}/secrets/${parsed.environment}/${parsed.key}/rotate`,
46656
+ { method: "POST", body: { new_value: value } }
46657
+ );
46658
+ this.context.stdout.write(`rotated ${data.alias} \u2192 v${data.version}
46273
46659
  `);
46274
- return 0;
46660
+ return 0;
46661
+ } catch (err) {
46662
+ return handleExecError(this.context.stderr, err);
46663
+ }
46275
46664
  }
46276
46665
  };
46277
46666
  var SecretDeleteCommand = class extends Command {
@@ -46279,33 +46668,40 @@ var SecretDeleteCommand = class extends Command {
46279
46668
  static usage = Command.Usage({ description: "Soft-delete a secret." });
46280
46669
  alias = options_exports.String({ required: false });
46281
46670
  async execute() {
46282
- const client = new ApiClient();
46283
- await client.ensureHydrated();
46284
- let alias2 = this.alias;
46285
- if (!alias2) {
46286
- if (!isInteractive()) return missingAlias(this.context.stderr);
46287
- try {
46288
- alias2 = await pickAliasInteractive(client) ?? void 0;
46289
- } catch (err) {
46290
- if (err instanceof UserCancelled) return 130;
46291
- throw err;
46671
+ try {
46672
+ const client = new ApiClient();
46673
+ await client.ensureHydrated();
46674
+ let alias2 = this.alias;
46675
+ if (!alias2) {
46676
+ if (!isInteractive()) return missingAlias(this.context.stderr);
46677
+ try {
46678
+ alias2 = await pickAliasInteractive(client) ?? void 0;
46679
+ } catch (err) {
46680
+ if (err instanceof UserCancelled) return 130;
46681
+ throw err;
46682
+ }
46683
+ if (!alias2) return 1;
46292
46684
  }
46293
- if (!alias2) return 1;
46294
- }
46295
- const parsed = parseAlias(alias2);
46296
- if (!parsed) {
46297
- this.context.stderr.write(`keynv: invalid alias '${alias2}'.
46685
+ const parsed = parseAlias(alias2);
46686
+ if (!parsed) {
46687
+ this.context.stderr.write(`keynv: invalid alias '${alias2}'.
46298
46688
  ${ALIAS_FORMAT_HINT}
46299
46689
  `);
46300
- return 1;
46301
- }
46302
- const projectId2 = await resolveProjectId(client, parsed.project);
46303
- await client.request(`/v1/projects/${projectId2}/secrets/${parsed.environment}/${parsed.key}`, {
46304
- method: "DELETE"
46305
- });
46306
- this.context.stdout.write(`deleted ${parsed.literal}
46690
+ return 1;
46691
+ }
46692
+ const projectId2 = await resolveProjectId(client, parsed.project);
46693
+ await client.request(
46694
+ `/v1/projects/${projectId2}/secrets/${parsed.environment}/${parsed.key}`,
46695
+ {
46696
+ method: "DELETE"
46697
+ }
46698
+ );
46699
+ this.context.stdout.write(`deleted ${parsed.literal}
46307
46700
  `);
46308
- return 0;
46701
+ return 0;
46702
+ } catch (err) {
46703
+ return handleExecError(this.context.stderr, err);
46704
+ }
46309
46705
  }
46310
46706
  };
46311
46707
  function generateSecret(bytes = 32) {
@@ -46367,8 +46763,8 @@ Non-interactive with --yes to skip prompts.
46367
46763
  "# KEYNV_ARGON2_MEMORY_KIB=46080",
46368
46764
  "# KEYNV_ARGON2_TIME_COST=3"
46369
46765
  ].join("\n");
46370
- const { writeFileSync: writeFileSync4 } = await import('fs');
46371
- writeFileSync4(outPath, `${contents}
46766
+ const { writeFileSync: writeFileSync5 } = await import('fs');
46767
+ writeFileSync5(outPath, `${contents}
46372
46768
  `);
46373
46769
  this.context.stdout.write(`Wrote ${outPath}
46374
46770
 
@@ -46434,7 +46830,7 @@ services:
46434
46830
  volumes:
46435
46831
  keynv-data:
46436
46832
  `;
46437
- writeFileSync4("docker-compose.yml", composeContent);
46833
+ writeFileSync5("docker-compose.yml", composeContent);
46438
46834
  this.context.stdout.write(
46439
46835
  "\nWrote docker-compose.yml (update Litestream S3 config before deploying).\n"
46440
46836
  );
@@ -46670,7 +47066,7 @@ var sshTester = {
46670
47066
  async test(secret, target) {
46671
47067
  const start = Date.now();
46672
47068
  const { Client: Client2 } = await import('ssh2');
46673
- return new Promise((resolve3) => {
47069
+ return new Promise((resolve4) => {
46674
47070
  const client = new Client2();
46675
47071
  let settled = false;
46676
47072
  const settle = (result) => {
@@ -46681,7 +47077,7 @@ var sshTester = {
46681
47077
  client.end();
46682
47078
  } catch {
46683
47079
  }
46684
- resolve3(result);
47080
+ resolve4(result);
46685
47081
  };
46686
47082
  client.once("ready", () => {
46687
47083
  client.exec("true", (err, stream) => {
@@ -46747,12 +47143,12 @@ function sanitizeResult(result, secret) {
46747
47143
 
46748
47144
  // ../../packages/testers/dist/run.js
46749
47145
  function withTimeout(promise, ms) {
46750
- return new Promise((resolve3, reject) => {
47146
+ return new Promise((resolve4, reject) => {
46751
47147
  const t = setTimeout(() => reject(new Error(`tester timed out after ${ms}ms`)), ms);
46752
47148
  t.unref();
46753
47149
  promise.then((v2) => {
46754
47150
  clearTimeout(t);
46755
- resolve3(v2);
47151
+ resolve4(v2);
46756
47152
  }, (err) => {
46757
47153
  clearTimeout(t);
46758
47154
  reject(err);