@keynv/cli 0.1.0-rc.15 → 0.1.0-rc.17

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
@@ -1057,7 +1057,7 @@ var require_lib = __commonJS({
1057
1057
  var VERSION, AGENT;
1058
1058
  var init_version = __esm({
1059
1059
  "src/version.ts"() {
1060
- VERSION = "0.1.0-rc.15" ;
1060
+ VERSION = "0.1.0-rc.17" ;
1061
1061
  AGENT = `keynv-cli/${VERSION}`;
1062
1062
  }
1063
1063
  });
@@ -5734,7 +5734,7 @@ var init_http = __esm({
5734
5734
  async request(path, opts = {}) {
5735
5735
  if (this.hydrated) await this.hydrated;
5736
5736
  if (!this.creds && opts.authed !== false) {
5737
- throw clientError(401, "auth.missing_token", "Not logged in. Run `keynv login` first.");
5737
+ throw clientError(401, "auth.missing_token", "Not connected. Run `keynv` first.");
5738
5738
  }
5739
5739
  const headers = {
5740
5740
  "content-type": "application/json",
@@ -5994,7 +5994,7 @@ When the user asks about secrets or env vars, follow this decision tree:
5994
5994
  | User intent | Run / suggest |
5995
5995
  |---|---|
5996
5996
  | "Add a new API key" / "set up a secret" | \`keynv secret create\` (interactive prompt picks project + env + key) |
5997
- | "I have a \`.env\`, migrate it" | \`keynv init\` (you're seeing this file because that already happened) |
5997
+ | "I have a \`.env\`, migrate it" | Run \`keynv\` and choose **Set up this project** |
5998
5998
  | "Run the app / dev server / tests" | \`keynv exec -- <their existing command>\` (auto-loads \`.keynv.env\`) |
5999
5999
  | "Show me the value of X" | \`keynv secret get @alias\` \u2014 but copy to clipboard, do NOT print the value into chat / terminal |
6000
6000
  | "Rotate this key" | \`keynv secret rotate @alias\` |
@@ -6021,7 +6021,7 @@ keynv whoami # who am I logged in as
6021
6021
  keynv --help # full command list
6022
6022
  \`\`\`
6023
6023
 
6024
- 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\`.`;
6024
+ If \`.keynv.env\` is missing or empty, the user probably hasn't run setup yet \u2014 suggest running \`keynv\` and choosing **Set up this project** before they paste a secret into a \`.env\`.`;
6025
6025
  }
6026
6026
  function renderKeynvBlock() {
6027
6027
  return `${KEYNV_BLOCK_START}
@@ -6060,7 +6060,7 @@ var AGENTS_FILE_BASENAME, KEYNV_BLOCK_START, KEYNV_BLOCK_END;
6060
6060
  var init_ai_context = __esm({
6061
6061
  "src/init/ai-context.ts"() {
6062
6062
  AGENTS_FILE_BASENAME = "AGENTS.md";
6063
- KEYNV_BLOCK_START = "<!-- keynv:start -- generated by `keynv init`; safe to leave intact, will be refreshed on re-run -->";
6063
+ KEYNV_BLOCK_START = "<!-- keynv:start -- generated by keynv setup; safe to leave intact, will be refreshed on re-run -->";
6064
6064
  KEYNV_BLOCK_END = "<!-- keynv:end -->";
6065
6065
  }
6066
6066
  });
@@ -8605,11 +8605,11 @@ function toAliasKey(name) {
8605
8605
  return normalised.replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 64) || "key";
8606
8606
  }
8607
8607
  async function runInitFlow(client, opts) {
8608
- ge("keynv init");
8608
+ ge("Set up this project");
8609
8609
  const root = findProjectRoot(opts.cwd);
8610
8610
  if (root === null) {
8611
8611
  me(
8612
- "Couldn't find a project root (no package.json, pyproject.toml, Cargo.toml, go.mod, or .git anywhere up the tree). Run `keynv init` inside a project directory."
8612
+ 'Couldn\'t find a project root (no package.json, pyproject.toml, Cargo.toml, go.mod, or .git anywhere up the tree). Run `keynv` inside a project directory and choose "Set up this project".'
8613
8613
  );
8614
8614
  return { exitCode: 1 };
8615
8615
  }
@@ -9063,7 +9063,7 @@ function composeKeynvEnv(opts) {
9063
9063
  lines.push(...trimmed.split("\n"));
9064
9064
  lines.push("");
9065
9065
  }
9066
- lines.push(`# >>> keynv init ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)} >>>`);
9066
+ lines.push(`# >>> keynv setup ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)} >>>`);
9067
9067
  } else {
9068
9068
  lines.push("# .keynv.env \u2014 alias references to vault secrets.");
9069
9069
  lines.push("# Safe to commit: this file contains references, not values.");
@@ -9085,7 +9085,7 @@ function composeKeynvEnv(opts) {
9085
9085
  }
9086
9086
  }
9087
9087
  if (mergeWithExisting !== null) {
9088
- lines.push("# <<< keynv init <<<");
9088
+ lines.push("# <<< keynv setup <<<");
9089
9089
  }
9090
9090
  return lines;
9091
9091
  }
@@ -9227,7 +9227,7 @@ async function runBrowserAuth(serverUrl) {
9227
9227
  access_expires_at: new Date(Date.now() + data.expires_in * 1e3).toISOString()
9228
9228
  };
9229
9229
  }
9230
- throw new BrowserAuthError("Browser auth timed out. Run `keynv login` to try again.");
9230
+ throw new BrowserAuthError("Browser auth timed out. Run `keynv` to try again.");
9231
9231
  }
9232
9232
  var BrowserAuthError;
9233
9233
  var init_browser_auth = __esm({
@@ -43651,7 +43651,7 @@ var init_audit2 = __esm({
43651
43651
  async function runLoginFlow(client, options = {}) {
43652
43652
  const server = options.server ?? DEFAULT_SERVER_URL;
43653
43653
  const s = ft();
43654
- s.start("Waiting for authorization");
43654
+ s.start(`Opening browser for ${server}`);
43655
43655
  let creds;
43656
43656
  try {
43657
43657
  creds = await runBrowserAuth(server);
@@ -43891,17 +43891,21 @@ async function runMenu() {
43891
43891
  await client.ensureHydrated();
43892
43892
  let didLogin = false;
43893
43893
  if (!client.isLoggedIn) {
43894
- R2.info("Not logged in.");
43894
+ const server = await pickConnectionTarget();
43895
+ if (server === null) {
43896
+ ye("Bye.");
43897
+ return 0;
43898
+ }
43895
43899
  try {
43896
- const ok = await runLoginFlow(client);
43900
+ const ok = await runLoginFlow(client, { server });
43897
43901
  if (!ok) {
43898
- ye("Login cancelled.");
43902
+ ye("Connection cancelled.");
43899
43903
  return 1;
43900
43904
  }
43901
43905
  didLogin = true;
43902
43906
  } catch (err) {
43903
43907
  if (err instanceof UserCancelled) {
43904
- me("Login cancelled.");
43908
+ me("Connection cancelled.");
43905
43909
  return 130;
43906
43910
  }
43907
43911
  throw err;
@@ -43938,7 +43942,7 @@ async function runMenu() {
43938
43942
  const value = await Ee({
43939
43943
  message: "What now?",
43940
43944
  options: [
43941
- { value: "init", label: "Initialize this project (migrate .env)", hint: "keynv init" },
43945
+ { value: "init", label: "Set up this project", hint: "migrate .env into keynv" },
43942
43946
  { value: "projects", label: "Projects" },
43943
43947
  { value: "secrets", label: "Secrets" },
43944
43948
  { value: "members", label: "Members" },
@@ -43994,9 +43998,41 @@ async function runMenu() {
43994
43998
  }
43995
43999
  }
43996
44000
  }
44001
+ async function pickConnectionTarget() {
44002
+ R2.info("Connect once, then manage projects and secrets from this menu.");
44003
+ const target = await Ee({
44004
+ message: "Connect to keynv",
44005
+ options: [
44006
+ { value: "cloud", label: "keynv.dev", hint: "recommended" },
44007
+ { value: "self-hosted", label: "Self-hosted server", hint: "enter your API URL" },
44008
+ { value: "exit", label: "Exit" }
44009
+ ]
44010
+ });
44011
+ if (q(target) || target === "exit") return null;
44012
+ if (target === "cloud") return DEFAULT_SERVER_URL;
44013
+ const server = await Re({
44014
+ message: "Server API URL",
44015
+ placeholder: "https://api.keynv.example.com",
44016
+ validate: (value) => {
44017
+ if (!value) return "Enter a server URL.";
44018
+ try {
44019
+ const parsed = new URL(value);
44020
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
44021
+ return "Use an http:// or https:// URL.";
44022
+ }
44023
+ return void 0;
44024
+ } catch {
44025
+ return "Enter a valid URL.";
44026
+ }
44027
+ }
44028
+ });
44029
+ if (q(server)) return null;
44030
+ return String(server);
44031
+ }
43997
44032
  var init_menu = __esm({
43998
44033
  "src/ui/menu.ts"() {
43999
44034
  init_dist5();
44035
+ init_defaults();
44000
44036
  init_http();
44001
44037
  init_store();
44002
44038
  init_detect();
@@ -46015,7 +46051,7 @@ function defaultRender(name) {
46015
46051
  function preview(matched) {
46016
46052
  if (matched.length <= 4)
46017
46053
  return "****";
46018
- return `${matched.slice(0, 4)}...`;
46054
+ return `${matched.slice(0, 3)}...`;
46019
46055
  }
46020
46056
  function escapeRegExp(s) {
46021
46057
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -46364,7 +46400,7 @@ spelled \`--from\` to avoid the collision.)
46364
46400
  const client = new ApiClient();
46365
46401
  await client.ensureHydrated();
46366
46402
  if (!client.isLoggedIn) {
46367
- this.context.stderr.write("keynv: not logged in. Run `keynv login` first.\n");
46403
+ this.context.stderr.write("keynv: not connected. Run `keynv` first.\n");
46368
46404
  return 1;
46369
46405
  }
46370
46406
  let envFileLoaded = null;
@@ -46393,7 +46429,7 @@ spelled \`--from\` to avoid the collision.)
46393
46429
  if (!envFileLoaded && !this.noEnvFile && !this.envFile && !process.env.KEYNV_ENV_FILE) {
46394
46430
  this.context.stderr.write(
46395
46431
  `keynv: no ${ENV_FILE_BASENAME} found in this directory or any parent.
46396
- Run \`keynv init\` in your project root to migrate secrets and create one.
46432
+ Run \`keynv\` in your project root and choose "Set up this project" to create one.
46397
46433
  `
46398
46434
  );
46399
46435
  }
@@ -46737,7 +46773,7 @@ any prompts.
46737
46773
  const client = new ApiClient();
46738
46774
  await client.ensureHydrated();
46739
46775
  if (!client.isLoggedIn) {
46740
- this.context.stderr.write("keynv: not logged in. Run `keynv login` first.\n");
46776
+ this.context.stderr.write("keynv: not connected. Run `keynv` first.\n");
46741
46777
  return 1;
46742
46778
  }
46743
46779
  const hasEnvFile = this.envFile != null;
@@ -47242,7 +47278,7 @@ var WhoamiCommand = class extends Command {
47242
47278
  const client = new ApiClient();
47243
47279
  await client.ensureHydrated();
47244
47280
  if (!client.isLoggedIn) {
47245
- this.context.stderr.write("keynv: not logged in. Run `keynv login`.\n");
47281
+ this.context.stderr.write("keynv: not connected. Run `keynv`.\n");
47246
47282
  return 1;
47247
47283
  }
47248
47284
  const data = await client.request("/v1/whoami");
@@ -47819,11 +47855,11 @@ Non-interactive with --yes to skip prompts.
47819
47855
  this.context.stdout.write(" --owner-email alice@example.com \\\n");
47820
47856
  this.context.stdout.write(' --owner-password "<a long random password>" \\\n');
47821
47857
  this.context.stdout.write(' --org-name "Acme Inc"\n');
47822
- this.context.stdout.write(" 3. Install the CLI and log in:\n");
47858
+ this.context.stdout.write(" 3. Install the CLI and connect from the TUI:\n");
47823
47859
  this.context.stdout.write(" npm install -g @keynv/cli\n");
47824
- this.context.stdout.write(" keynv login --server https://keynv.example.com\n");
47825
- this.context.stdout.write(" 4. Onboard your first project:\n");
47826
- this.context.stdout.write(" cd your-project && keynv init\n");
47860
+ this.context.stdout.write(" keynv\n");
47861
+ this.context.stdout.write(" 4. Onboard your first project from the same TUI:\n");
47862
+ this.context.stdout.write(" cd your-project && keynv\n");
47827
47863
  if (this.compose) {
47828
47864
  const composeContent = `# keynv server + Litestream sidecar
47829
47865
  # Generated by \`keynv server init\`.
@@ -48409,7 +48445,7 @@ the error message.
48409
48445
  const client = new ApiClient();
48410
48446
  await client.ensureHydrated();
48411
48447
  if (!client.isLoggedIn) {
48412
- this.context.stderr.write("keynv: not logged in. Run `keynv login` first.\n");
48448
+ this.context.stderr.write("keynv: not connected. Run `keynv` first.\n");
48413
48449
  return 1;
48414
48450
  }
48415
48451
  let value;