@vibiz/cli 0.2.0 → 0.2.1

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/vibiz.js CHANGED
@@ -6,11 +6,12 @@ import {
6
6
  formatUnits,
7
7
  formatUsd,
8
8
  mergeEnvFile
9
- } from "./chunk-GSHNECVT.js";
9
+ } from "./chunk-J4RTAA72.js";
10
10
 
11
11
  // packages/cli/src/main.ts
12
12
  import { spawn } from "node:child_process";
13
- import { chmod, mkdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
13
+ import { chmod, mkdir as mkdir2, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
14
+ import { dirname as dirname5, join as join8 } from "node:path";
14
15
  import { format } from "node:util";
15
16
 
16
17
  // packages/cli/src/commands.ts
@@ -1639,7 +1640,7 @@ async function browserLogin(io, api, deps) {
1639
1640
  await forget(io, pendingPath);
1640
1641
  io.log(
1641
1642
  `
1642
- \u2713 Logged in to ${body.account?.name ?? "your account"} as "${body.key?.name ?? "cli"}" (${body.key?.access ?? "agent"} key). Saved to ${configFile(dir)}`
1643
+ \u2713 Logged in to ${body.account?.name ?? "your account"} as "${body.key?.name ?? "cli"}" (${body.key?.access === "agent" ? "Limited access" : "full access"}). Saved to ${configFile(dir)}`
1643
1644
  );
1644
1645
  return;
1645
1646
  }
@@ -2424,7 +2425,8 @@ var PROJECT_FILE = "vibiz.json";
2424
2425
  var HELP = `vibiz \u2014 website, database and sign-in for a new business, in one command
2425
2426
 
2426
2427
  vibiz login log in from the browser: prints a link, you click
2427
- Authorize, a new agent key is saved here
2428
+ Authorize (Full access by default, or Limited),
2429
+ and the new key is saved here
2428
2430
  [--key <vz_sk_\u2026>] [--api <url>] [--no-browser] or save a key you already have
2429
2431
  vibiz signup the same as login: no account yet? one is opened
2430
2432
  for you on the way
@@ -2448,43 +2450,44 @@ var HELP = `vibiz \u2014 website, database and sign-in for a new business, in on
2448
2450
  schema and no production rows, own sign-in, own AI
2449
2451
  key) into .env.development.local
2450
2452
  vibiz dev -- <command\u2026> run a command with the development env, no file
2451
- vibiz env [--write <file>] the PRODUCTION env (owner keys only), to paste into
2453
+ vibiz env [--write <file>] the PRODUCTION env (full-access keys only), to paste into
2452
2454
  a host outside Vibiz; agents use \`vibiz dev\`
2453
2455
  vibiz export [--code] [--db] [--csv] [--env production|development] [-o file.zip]
2454
2456
  take the app elsewhere, or keep a backup: its source
2455
2457
  with a guide (VIBIZ-EXPORT.md, .env.example), the
2456
2458
  database as SQL that psql restores (--csv: tables as
2457
- CSV). Default: all there is. Production data needs an
2458
- owner key; agents default to development
2459
+ CSV). Default: all there is. Production data needs a
2460
+ full-access key; Limited keys default to development
2459
2461
  [--deployment <id>] [--secrets] [--no-wait] another deployment's code; --secrets also
2460
2462
  writes the env's values to their own file (owner, asks)
2461
2463
  vibiz domains [--json] your own domains: status, and the DNS records to add
2462
- vibiz domains add <domain> [--elsewhere] connect one you own (agent keys: analytics counts it now;
2464
+ vibiz domains add <domain> [--elsewhere] connect one you own (Limited keys: analytics counts it now;
2463
2465
  sign-in trusts it once its TXT record is in, or an owner
2464
2466
  confirms); HTTPS turns on by
2465
2467
  itself. --elsewhere: the app runs on another host
2466
2468
  vibiz domains verify <domain> check its DNS (and its TXT proof) again now
2467
- vibiz domains remove <domain> disconnect it (owner keys)
2469
+ vibiz domains remove <domain> disconnect it (full-access keys)
2468
2470
  vibiz domains search <name> find a domain to buy, with prices (sellshelf, sellshelf.app)
2469
2471
  vibiz domains buy <domain> [--years 1] [--yes]
2470
- buy it from your credits for this project (owner keys;
2472
+ buy it from your credits for this project (full-access keys,
2473
+ or Limited keys up to the owner's per-domain limit;
2471
2474
  registered to the saved domain owner details)
2472
2475
  vibiz domains owned [--json] domains this account bought: expiry, auto-renew
2473
- vibiz domains renew <domain> [--years 1] renew now from credits (owner keys)
2476
+ vibiz domains renew <domain> [--years 1] renew now from credits (full-access keys)
2474
2477
  vibiz domains auto-renew <domain> on|off renew from credits 30 days before expiry (default on)
2475
- vibiz domains transfer-code <domain> the code to move it to another registrar (owner keys)
2478
+ vibiz domains transfer-code <domain> the code to move it to another registrar (full-access keys)
2476
2479
  vibiz domains owner [--input <json>] [--open]
2477
2480
  the domain owner details (the legal registrant), saved
2478
2481
  once; --input sets them, --open edits in the console
2479
2482
  vibiz auth [--dev] [--json] how people sign in: providers, callback URLs, email
2480
- (production for owner keys; --dev the development copy)
2483
+ (production for full-access keys; --dev the development copy)
2481
2484
  vibiz auth providers add <google|github|vercel> [--own --client-id <id>] [--dev]
2482
2485
  turn on a social sign-in; --own uses your OAuth app,
2483
2486
  its secret from <PROVIDER>_CLIENT_SECRET or a prompt
2484
2487
  vibiz auth providers rm <provider> [--dev] turn one off
2485
2488
  vibiz auth domains <a.com,b.com|none> [--dev] only these email domains may sign up
2486
2489
  vibiz company [--dev] [--json] the business behind this project: status, what blocks
2487
- filing, the next step (production for owner keys)
2490
+ filing, the next step (production for full-access keys)
2488
2491
  vibiz company draft --file company.json [--dev] create or replace the draft (docs/COMPANY.md)
2489
2492
  vibiz company submit [--dev] file it; production shows the price and asks you to
2490
2493
  type the company's name (real filing, real fees)
@@ -2492,7 +2495,7 @@ var HELP = `vibiz \u2014 website, database and sign-in for a new business, in on
2492
2495
  vibiz company docs [download <id>] [--dev] formation documents, or a short-lived download link
2493
2496
  vibiz company simulate <formation|ein> development only: complete that step at the sandbox
2494
2497
  vibiz payments [--dev] [--json] take payments: balance, getting paid, the next step
2495
- (production for owner keys; --dev test mode)
2498
+ (production for full-access keys; --dev test mode)
2496
2499
  vibiz payments products [--dev] the catalog; add one with
2497
2500
  products add <name> --amount <cents> [--interval month|year] [--lookup-key k]
2498
2501
  vibiz payments checkout <price_id|lookup_key> --success-url <u> --cancel-url <u> [--user id]
@@ -2524,7 +2527,7 @@ var HELP = `vibiz \u2014 website, database and sign-in for a new business, in on
2524
2527
  vibiz social accounts [--dev] [--json] connected accounts and their ids
2525
2528
  vibiz social post "<text>" --to <account,\u2026> [--media <file|url>]\u2026 [--at <iso>] [--draft]
2526
2529
  [--opt key=value]\u2026 [--dev] publish now, schedule or draft; a live post asks you to
2527
- confirm (an agent key's post waits for the owner)
2530
+ confirm (a Limited key's post waits for the owner)
2528
2531
  vibiz social posts [--status s] [--dev] posts, newest first
2529
2532
  vibiz social approve|reject|cancel <post> [--dev] decide a waiting post, or cancel one
2530
2533
  vibiz social campaigns [--dev] ad campaigns with budget and spend
@@ -2540,13 +2543,13 @@ var HELP = `vibiz \u2014 website, database and sign-in for a new business, in on
2540
2543
  vibiz connectors ops <name> [--json] its operations: risk, on/off, parameters
2541
2544
  vibiz connectors enable|disable <name> <op\u2026> allow (or stop) operations
2542
2545
  vibiz connectors secret <name> <VAR> [--dev] set a key from $VAR or a hidden prompt; never printed.
2543
- Production needs an owner key
2546
+ Production needs a full-access key
2544
2547
  vibiz connectors call <name> <op> [key=value\u2026] [--body '<json>'] [--dev] [--approval <id>]
2545
2548
  call it; dangerous operations (and production writes)
2546
- by an agent key wait for the owner's approval
2549
+ by a Limited key wait for the owner's approval
2547
2550
  vibiz connectors check <name> [--dev] does the key work
2548
2551
  vibiz connectors logs <name> [--dev] recent calls (no content)
2549
- vibiz connectors approvals | approve <id> | deny <id> calls waiting for the owner (owner key)
2552
+ vibiz connectors approvals | approve <id> | deny <id> calls waiting for the owner (full-access key)
2550
2553
  vibiz connect where does this app deploy? how that host gets its env
2551
2554
  vibiz run -- <command\u2026> with VIBIZ_APP_KEY set (a server, a container, CI): run
2552
2555
  the command with the app's env; any language
@@ -2555,7 +2558,7 @@ var HELP = `vibiz \u2014 website, database and sign-in for a new business, in on
2555
2558
  vibiz hosts hosts outside Vibiz that get the env server to server
2556
2559
  vibiz hosts add <host> <app> [field=value\u2026] [--dev]
2557
2560
  connect your own host so Vibiz keeps its env in sync
2558
- (owner key): vercel, netlify, render, railway, fly,
2561
+ (full-access key): vercel, netlify, render, railway, fly,
2559
2562
  heroku, cloudflare-workers, cloudflare-pages,
2560
2563
  github-actions. The token comes from the host's usual
2561
2564
  variable (VERCEL_TOKEN, FLY_API_TOKEN\u2026) or a hidden
@@ -2569,7 +2572,7 @@ var HELP = `vibiz \u2014 website, database and sign-in for a new business, in on
2569
2572
  what went wrong for visitors, then sessions to watch
2570
2573
  vibiz replay <id> [--json] one session's signals and a link to watch it
2571
2574
  vibiz projects list your projects
2572
- Web data (billed per call at cost; every run is kept: vibiz runs, console \u25B8 Web data)
2575
+ Web data (billed per call; every run is kept: vibiz runs, console \u25B8 Web data)
2573
2576
  vibiz scrape <url> [--json] one page as markdown
2574
2577
  vibiz design <url> [--out design.md] [--tailwind] [--shadcn] [--css] [--own] [--pages /a,/b]
2575
2578
  a site's design: type scale, colors, radii, spacing,
@@ -2634,7 +2637,7 @@ var HELP = `vibiz \u2014 website, database and sign-in for a new business, in on
2634
2637
  recent messages (sender and subject only)
2635
2638
  vibiz email unforward <address@domain|domain> [inbox]
2636
2639
  stop forwarding to one inbox, one address, or (domain
2637
- alone) the whole domain (owner keys)
2640
+ alone) the whole domain (full-access keys)
2638
2641
  vibiz email setup set up newsletters: the sending address news.<project>\u2026
2639
2642
  (verifies in minutes). Then the owner adds the postal
2640
2643
  address: vibiz email settings set --postal-address "\u2026"
@@ -2654,7 +2657,7 @@ var HELP = `vibiz \u2014 website, database and sign-in for a new business, in on
2654
2657
  vibiz email broadcast list|stats <id>|review <id>|test <id> [--to a,b]|cancel <id>|resume <id>
2655
2658
  vibiz email broadcast create --subject s --file body.md [--list l] [--segment s] [--html]
2656
2659
  [--preview-text t] [--from-name n] [--name n] (edit <id> takes the same flags)
2657
- vibiz email broadcast send <id> [--at <ISO time>] $0.001 an email; agent keys get the owner's
2660
+ vibiz email broadcast send <id> [--at <ISO time>] $0.001 an email; Limited keys get the owner's
2658
2661
  review link unless the owner set an allowance
2659
2662
  vibiz email automation list|runs <id>|activate <id>|pause <id>
2660
2663
  vibiz email automation create --file automation.json {name, trigger, steps, exit_event}
@@ -2687,11 +2690,12 @@ var HELP = `vibiz \u2014 website, database and sign-in for a new business, in on
2687
2690
  vibiz billing [--json] the account's credits: balance, card, auto-recharge
2688
2691
  vibiz billing top-up <dollars> [--open] a payment link to add credits (a person pays there)
2689
2692
  vibiz billing history [--kind usage,topup] what came in and what used it
2690
- vibiz billing auto-recharge on|off [--threshold 5] [--amount 25] (owner key)
2693
+ vibiz billing auto-recharge on|off [--threshold 5] [--amount 25] (full-access key)
2691
2694
  vibiz metrics [--period 7d] [--json] request counts, error rate and latency by capability
2692
- vibiz keys [create <name> [--owner] | revoke <id>]
2693
- named API keys, one per person or agent; agent keys
2694
- (the default) never read production secrets
2695
+ vibiz keys [create <name> [--limited] | access <id> full|limited | revoke <id>]
2696
+ named API keys, one per person or agent: full
2697
+ access by default; Limited ones never move live
2698
+ money or read production secrets
2695
2699
  vibiz admin metrics [--period 7d] [--json] [--open] the platform view (admin key)
2696
2700
  vibiz mcp serve the Vibiz tools to AI agents (MCP, stdio)
2697
2701
  vibiz mcp add --clients "<client>[,\u2026]" connect a coding agent to the remote MCP server once:
@@ -2757,6 +2761,7 @@ function printDomains(io, list2, only) {
2757
2761
  io.log(` ${x.next_step}`);
2758
2762
  }
2759
2763
  }
2764
+ var accessLabel = (access) => access === "agent" ? "Limited access" : "full access";
2760
2765
  var BUY_DOMAIN_COMMANDS = /* @__PURE__ */ new Set([
2761
2766
  "search",
2762
2767
  "buy",
@@ -3339,6 +3344,7 @@ async function runCli(argv2, io) {
3339
3344
  "keep-values": { type: "boolean", default: false },
3340
3345
  grace: { type: "string" },
3341
3346
  owner: { type: "boolean", default: false },
3347
+ limited: { type: "boolean", default: false },
3342
3348
  own: { type: "boolean", default: false },
3343
3349
  "client-id": { type: "string" },
3344
3350
  file: { type: "string" },
@@ -3472,7 +3478,7 @@ async function runCli(argv2, io) {
3472
3478
  return;
3473
3479
  }
3474
3480
  io.log(`${me.account.name} (${me.account.id})`);
3475
- io.log(` key ${me.key.name} ${me.key.prefix}\u2026 ${me.key.access}`);
3481
+ io.log(` key ${me.key.name} ${me.key.prefix}\u2026 ${accessLabel(me.key.access)}`);
3476
3482
  const saved = await readLogin(io, io.configDir ?? CONFIG_DIR);
3477
3483
  io.log(` api ${io.env.VIBIZ_API_URL || saved.apiUrl || DEFAULT_API_URL}`);
3478
3484
  return;
@@ -4269,7 +4275,7 @@ ${link.url}`
4269
4275
  ${JSON.stringify(a.request)}`
4270
4276
  );
4271
4277
  }
4272
- if (list2.length) io.log("Approve with an owner key: vibiz connectors approve <id>");
4278
+ if (list2.length) io.log("Approve with a full-access key: vibiz connectors approve <id>");
4273
4279
  });
4274
4280
  return;
4275
4281
  }
@@ -5072,16 +5078,25 @@ The credits show in \`vibiz billing\` a few seconds after paying.`
5072
5078
  const vibiz2 = await io.client();
5073
5079
  const [sub, arg] = positionals;
5074
5080
  if (sub === "create") {
5075
- if (!arg) throw new Error("usage: vibiz keys create <name> [--owner]");
5076
- const key = await vibiz2.apiKeys.create(arg, { access: values.owner ? "owner" : "agent" });
5081
+ if (!arg) throw new Error("usage: vibiz keys create <name> [--limited]");
5082
+ const key = await vibiz2.apiKeys.create(arg, { access: values.limited ? "agent" : "owner" });
5077
5083
  io.log(
5078
- `${key.name} ${key.id} ${key.access}
5084
+ `${key.name} ${key.id} ${accessLabel(key.access)}
5079
5085
  ${key.secret}
5080
5086
 
5081
5087
  Store the key now: it is not shown again.`
5082
5088
  );
5083
5089
  return;
5084
5090
  }
5091
+ if (sub === "access") {
5092
+ const level = positionals[2];
5093
+ if (!arg || level !== "full" && level !== "limited") {
5094
+ throw new Error("usage: vibiz keys access <key id> full|limited");
5095
+ }
5096
+ const k = await vibiz2.apiKeys.setAccess(arg, level === "full" ? "owner" : "agent");
5097
+ io.log(`${k.name} (${k.id}) now has ${accessLabel(k.access)}.`);
5098
+ return;
5099
+ }
5085
5100
  if (sub === "revoke") {
5086
5101
  if (!arg) throw new Error("usage: vibiz keys revoke <key id>");
5087
5102
  await vibiz2.apiKeys.revoke(arg);
@@ -5090,7 +5105,7 @@ Store the key now: it is not shown again.`
5090
5105
  }
5091
5106
  for (const k of await vibiz2.apiKeys.list()) {
5092
5107
  io.log(
5093
- `${k.id} ${k.name.padEnd(20)} ${k.prefix}\u2026 ${(k.access ?? "owner").padEnd(5)} ${k.revoked_at ? "revoked" : "active"}`
5108
+ `${k.id} ${k.name.padEnd(20)} ${k.prefix}\u2026 ${accessLabel(k.access).padEnd(14)} ${k.revoked_at ? "revoked" : "active"}`
5094
5109
  );
5095
5110
  }
5096
5111
  return;
@@ -5110,7 +5125,7 @@ Store the key now: it is not shown again.`
5110
5125
  return;
5111
5126
  }
5112
5127
  case "docs": {
5113
- const { DOC_TOPICS, DOCS } = await import("./src-2CVAECWM.js");
5128
+ const { DOC_TOPICS, DOCS } = await import("./src-IAT2AUWC.js");
5114
5129
  const topic = positionals[0];
5115
5130
  if (!topic || !DOC_TOPICS.includes(topic)) {
5116
5131
  for (const t of DOC_TOPICS) io.log(` vibiz docs ${t.padEnd(13)} ${DOCS[t].title}`);
@@ -5135,7 +5150,7 @@ ${DOCS[topic].body}`);
5135
5150
  if (positionals[0])
5136
5151
  throw new Error('usage: vibiz mcp (serve over stdio) | vibiz mcp add --clients "<client>"');
5137
5152
  io.local();
5138
- const { serveStdio } = await import("./src-2CVAECWM.js");
5153
+ const { serveStdio } = await import("./src-IAT2AUWC.js");
5139
5154
  await serveStdio({ version: cliVersion() });
5140
5155
  return;
5141
5156
  }
@@ -5158,6 +5173,13 @@ function cliErrorLines(err) {
5158
5173
  if (err instanceof VibizApiError) {
5159
5174
  const out = [`\u2715 ${err.message} (${err.code})`];
5160
5175
  const d = err.details;
5176
+ const problems = (Array.isArray(d?.problems) ? d.problems : []).filter(
5177
+ (p) => typeof p?.message === "string" && !err.message.includes(p.message.replace(/[.\s]+$/, ""))
5178
+ );
5179
+ for (const p of problems.slice(0, 10)) out.push(` \u2022 ${p.message}`);
5180
+ if (typeof d?.field === "string" && d.field && !err.message.includes(d.field) && !problems.length) {
5181
+ out.push(` field: ${d.field}`);
5182
+ }
5161
5183
  if (d?.approval_id) out.push(` approval_id: ${d.approval_id}`);
5162
5184
  if (d?.next_step) out.push(` ${d.next_step}`);
5163
5185
  if (d?.console_url && !d.next_step?.includes(d.console_url)) out.push(` ${d.console_url}`);
@@ -5254,10 +5276,54 @@ async function aiKeysCommand(io, args, values) {
5254
5276
  }
5255
5277
  }
5256
5278
 
5279
+ // packages/cli/src/update-check.ts
5280
+ import { mkdir, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
5281
+ import { join as join7 } from "node:path";
5282
+ var DAY_MS = 24 * 60 * 60 * 1e3;
5283
+ var LATEST_URL = "https://registry.npmjs.org/@vibiz/cli/latest";
5284
+ function isNewer(latest, current) {
5285
+ const parse = (v) => /^\d+\.\d+\.\d+$/.test(v) ? v.split(".").map(Number) : null;
5286
+ const a = parse(latest);
5287
+ const b = parse(current);
5288
+ if (!a || !b) return false;
5289
+ for (let i = 0; i < 3; i++) {
5290
+ if (a[i] !== b[i]) return (a[i] ?? 0) > (b[i] ?? 0);
5291
+ }
5292
+ return false;
5293
+ }
5294
+ function updateNotice(latest, current) {
5295
+ if (!isNewer(latest, current)) return null;
5296
+ return [
5297
+ `A newer Vibiz CLI is out: ${current} \u2192 ${latest}. Some commands may be missing from this one.`,
5298
+ "Update: npm install -g @vibiz/cli@latest (then refresh the agent skills: vibiz skills add --global)"
5299
+ ].join("\n");
5300
+ }
5301
+ async function latestVersion(configDir, env, fetchImpl = fetch, now = Date.now()) {
5302
+ if (env.VIBIZ_NO_UPDATE_CHECK || env.CI) return null;
5303
+ const file = join7(configDir, "update-check.json");
5304
+ let cache = null;
5305
+ try {
5306
+ cache = JSON.parse(await readFile2(file, "utf8"));
5307
+ } catch {
5308
+ }
5309
+ if (cache && now - cache.checkedAt < DAY_MS) return cache.latest;
5310
+ try {
5311
+ const res = await fetchImpl(LATEST_URL, { signal: AbortSignal.timeout(1500) });
5312
+ if (!res.ok) return cache?.latest ?? null;
5313
+ const { version } = await res.json();
5314
+ if (typeof version !== "string") return cache?.latest ?? null;
5315
+ await mkdir(configDir, { recursive: true });
5316
+ await writeFile2(file, JSON.stringify({ checkedAt: now, latest: version }));
5317
+ return version;
5318
+ } catch {
5319
+ return cache?.latest ?? null;
5320
+ }
5321
+ }
5322
+
5257
5323
  // packages/cli/src/main.ts
5258
5324
  async function readJson2(path) {
5259
5325
  try {
5260
- return JSON.parse(await readFile2(path, "utf8"));
5326
+ return JSON.parse(await readFile3(path, "utf8"));
5261
5327
  } catch {
5262
5328
  return null;
5263
5329
  }
@@ -5316,7 +5382,7 @@ var terminal = {
5316
5382
  out: (text) => void process.stdout.write(text),
5317
5383
  err: (text) => void process.stderr.write(text),
5318
5384
  env: process.env,
5319
- client: async () => new Vibiz(await login()),
5385
+ client: async () => new Vibiz({ ...await login(), client: `vibiz-cli/${cliVersion()}` }),
5320
5386
  aiClient: async (project) => {
5321
5387
  const { apiKey, baseUrl } = await login();
5322
5388
  const headers = project ? { "x-vibiz-project": project } : void 0;
@@ -5332,19 +5398,46 @@ var terminal = {
5332
5398
  });
5333
5399
  },
5334
5400
  project: async () => {
5335
- const linked = await readJson2(PROJECT_FILE);
5336
- if (!linked?.project_id) throw new Error(`No ${PROJECT_FILE} here. Run: vibiz init <name>`);
5337
- return linked.project_id;
5401
+ for (let dir = process.cwd(); ; dir = dirname5(dir)) {
5402
+ const linked = await readJson2(join8(dir, PROJECT_FILE));
5403
+ if (linked?.project_id) return linked.project_id;
5404
+ if (dirname5(dir) === dir) break;
5405
+ }
5406
+ const list2 = await new Vibiz(await login()).projects.list();
5407
+ const wanted = process.env.VIBIZ_PROJECT?.trim().toLowerCase();
5408
+ if (wanted) {
5409
+ const p = list2.find((x) => [x.id, x.slug, x.name.toLowerCase()].includes(wanted));
5410
+ if (p) return p.id;
5411
+ throw new Error(`No project "${process.env.VIBIZ_PROJECT}" on this account.`);
5412
+ }
5413
+ const lines = list2.map((p, i) => ` ${i + 1}. ${p.name} (${p.slug}, ${p.id})`);
5414
+ if (list2.length && process.stdin.isTTY) {
5415
+ console.error(`No ${PROJECT_FILE} here. Which project?
5416
+ ${lines.join("\n")}`);
5417
+ const n = Number(await promptLine("Number (Enter to cancel): "));
5418
+ const p = list2[n - 1];
5419
+ if (!p) throw new Error("Cancelled.");
5420
+ const link = (await promptLine(`Link this folder to ${p.name} (writes ${PROJECT_FILE})? [y/N] `)).trim().toLowerCase();
5421
+ if (link === "y" || link === "yes") {
5422
+ await writeFile3(PROJECT_FILE, `${JSON.stringify({ project_id: p.id }, null, 2)}
5423
+ `);
5424
+ }
5425
+ return p.id;
5426
+ }
5427
+ throw new Error(
5428
+ list2.length ? `No ${PROJECT_FILE} here. Run it in the app's folder, or name the project: VIBIZ_PROJECT=<slug> vibiz \u2026
5429
+ ${lines.join("\n")}` : `No ${PROJECT_FILE} here and no projects yet. Run: vibiz init <name>`
5430
+ );
5338
5431
  },
5339
5432
  promptHidden,
5340
5433
  promptLine,
5341
5434
  openUrl,
5342
5435
  local: () => ({
5343
5436
  cwd: () => process.cwd(),
5344
- readFile: readFile2,
5345
- writeFile: writeFile2,
5437
+ readFile: readFile3,
5438
+ writeFile: writeFile3,
5346
5439
  chmod,
5347
- mkdir,
5440
+ mkdir: mkdir2,
5348
5441
  exec: (cmd, args, env, opts) => {
5349
5442
  const child = spawn(cmd, args, { stdio: "inherit", env });
5350
5443
  if (opts?.forwardSignals) {
@@ -5364,8 +5457,16 @@ var argv = process.argv.slice(2);
5364
5457
  if (argv[0] === "--version" || argv[0] === "-v") {
5365
5458
  console.log(cliVersion());
5366
5459
  } else {
5367
- runCli(argv, terminal).catch((err) => {
5460
+ const latest = latestVersion(CONFIG_DIR, process.env);
5461
+ const notice = async () => {
5462
+ const v = await latest;
5463
+ const text = v && updateNotice(v, cliVersion());
5464
+ if (text) console.error(`
5465
+ ${text}`);
5466
+ };
5467
+ runCli(argv, terminal).then(notice).catch(async (err) => {
5368
5468
  for (const line of cliErrorLines(err)) console.error(line);
5469
+ await notice();
5369
5470
  process.exit(1);
5370
5471
  });
5371
5472
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibiz/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "The Vibiz Stack CLI and MCP server: website, database, sign-in, email and AI for a new business, from your terminal or your AI agent.",
5
5
  "keywords": [
6
6
  "vibiz",