@vapi-network/cli 0.2.1 → 0.2.3

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
@@ -45329,8 +45329,8 @@ var DEFAULT_DISCOVERY_URL = `${DEFAULT_REGISTRY_URL}/api/call/services`;
45329
45329
  var DEFAULT_MARKETPLACE_DISCOVERY_URL = `${DEFAULT_REGISTRY_URL}/api/call/discovery`;
45330
45330
  var DEFAULT_REGISTRY_FALLBACKS = [
45331
45331
  {
45332
- discoveryUrl: "https://console.vapinetwork.ai/api/call/services",
45333
- marketplaceDiscoveryUrl: "https://console.vapinetwork.ai/api/call/discovery"
45332
+ discoveryUrl: DEFAULT_DISCOVERY_URL,
45333
+ marketplaceDiscoveryUrl: DEFAULT_MARKETPLACE_DISCOVERY_URL
45334
45334
  }
45335
45335
  ];
45336
45336
  var DEFAULT_SPEND_CAPS = {
@@ -45435,6 +45435,83 @@ async function migrateLegacyVapiHome(options = {}) {
45435
45435
  }
45436
45436
  return copied;
45437
45437
  }
45438
+ var LEGACY_REGISTRY_HOSTS = /* @__PURE__ */ new Map([
45439
+ ["console.vapinetwork.ai", "api.vapinetwork.ai"],
45440
+ ["console-staging.vapinetwork.ai", "api-staging.vapinetwork.ai"]
45441
+ ]);
45442
+ var LEGACY_REGISTRY_PATHS = /* @__PURE__ */ new Map([
45443
+ ["/api/network/services", "/api/call/services"],
45444
+ ["/api/marketplace/discovery", "/api/call/discovery"]
45445
+ ]);
45446
+ var REGISTRY_DOMAIN = "vapinetwork.ai";
45447
+ function rewriteLegacyRegistryUrl(value) {
45448
+ let url2;
45449
+ try {
45450
+ url2 = new URL(value);
45451
+ } catch {
45452
+ return value;
45453
+ }
45454
+ let rewritten = false;
45455
+ const host = LEGACY_REGISTRY_HOSTS.get(url2.hostname.toLowerCase());
45456
+ if (host) {
45457
+ url2.hostname = host;
45458
+ rewritten = true;
45459
+ }
45460
+ const hostname3 = url2.hostname.toLowerCase();
45461
+ if (hostname3 === REGISTRY_DOMAIN || hostname3.endsWith(`.${REGISTRY_DOMAIN}`)) {
45462
+ const path = LEGACY_REGISTRY_PATHS.get(url2.pathname.replace(/\/+$/, ""));
45463
+ if (path) {
45464
+ url2.pathname = path;
45465
+ rewritten = true;
45466
+ }
45467
+ }
45468
+ return rewritten ? url2.href : value;
45469
+ }
45470
+ function rewriteLegacyRegistryUrls(config2) {
45471
+ const changes = [];
45472
+ const rewrite = (field, from16) => {
45473
+ const to = rewriteLegacyRegistryUrl(from16);
45474
+ if (to !== from16) changes.push({ field, from: from16, to });
45475
+ return to;
45476
+ };
45477
+ const next = {
45478
+ ...config2,
45479
+ discoveryUrl: rewrite("discoveryUrl", config2.discoveryUrl),
45480
+ marketplaceDiscoveryUrl: rewrite("marketplaceDiscoveryUrl", config2.marketplaceDiscoveryUrl),
45481
+ ...config2.registryFallbacks ? {
45482
+ registryFallbacks: config2.registryFallbacks.map((fallback, index2) => ({
45483
+ discoveryUrl: rewrite(
45484
+ `registryFallbacks[${index2}].discoveryUrl`,
45485
+ fallback.discoveryUrl
45486
+ ),
45487
+ marketplaceDiscoveryUrl: rewrite(
45488
+ `registryFallbacks[${index2}].marketplaceDiscoveryUrl`,
45489
+ fallback.marketplaceDiscoveryUrl
45490
+ )
45491
+ }))
45492
+ } : {}
45493
+ };
45494
+ return changes.length === 0 ? { config: config2, changes } : { config: next, changes };
45495
+ }
45496
+ function formatLegacyRegistryRewrites(changes) {
45497
+ return [
45498
+ "Rewrote retired vAPI registry URLs in the local config:",
45499
+ ...changes.map((change) => ` ${change.field}: ${change.from} -> ${change.to}`)
45500
+ ].join("\n");
45501
+ }
45502
+ async function migrateLegacyRegistryConfig(path = getVapiPaths().config) {
45503
+ let raw;
45504
+ try {
45505
+ raw = await readFile(path, "utf8");
45506
+ } catch (error61) {
45507
+ if (isMissingFile(error61)) return [];
45508
+ throw error61;
45509
+ }
45510
+ const { config: config2, changes } = rewriteLegacyRegistryUrls(configSchema.parse(JSON.parse(raw)));
45511
+ if (changes.length === 0) return [];
45512
+ await writeConfigFile(path, config2);
45513
+ return changes;
45514
+ }
45438
45515
  function getDefaultConfig(source = process.env, options = {}) {
45439
45516
  const registry2 = registryEndpoints(source.VAPI_REGISTRY_URL?.trim() || DEFAULT_REGISTRY_URL);
45440
45517
  const requested = new Set(options.networks ?? ["base"]);
@@ -45473,7 +45550,7 @@ function getDefaultConfig(source = process.env, options = {}) {
45473
45550
  spendCaps: { ...DEFAULT_SPEND_CAPS }
45474
45551
  };
45475
45552
  }
45476
- async function loadConfig(path = getVapiPaths().config, source = process.env) {
45553
+ async function loadConfig(path = getVapiPaths().config, source = process.env, options = {}) {
45477
45554
  if (!process.env.VAPI_HOME?.trim() && path === getVapiPaths(join(homedir(), ".vapi")).config) {
45478
45555
  await migrateLegacyVapiHome({ targetDirectory: join(homedir(), ".vapi") });
45479
45556
  }
@@ -45484,8 +45561,16 @@ async function loadConfig(path = getVapiPaths().config, source = process.env) {
45484
45561
  if (isMissingFile(error61)) return getDefaultConfig(source);
45485
45562
  throw error61;
45486
45563
  }
45487
- const config2 = configSchema.parse(JSON.parse(raw));
45488
- config2.registryFallbacks ??= DEFAULT_REGISTRY_FALLBACKS.map((fallback) => ({ ...fallback }));
45564
+ const parsed = configSchema.parse(JSON.parse(raw));
45565
+ parsed.registryFallbacks ??= DEFAULT_REGISTRY_FALLBACKS.map((fallback) => ({ ...fallback }));
45566
+ const migrated = rewriteLegacyRegistryUrls(parsed);
45567
+ const config2 = migrated.config;
45568
+ if (migrated.changes.length > 0 && options.notice) {
45569
+ options.notice(
45570
+ `${formatLegacyRegistryRewrites(migrated.changes)}
45571
+ Run vapi init to write the new URLs to ${path}.`
45572
+ );
45573
+ }
45489
45574
  const baseRpcUrl = source.BASE_RPC_URL?.trim();
45490
45575
  const arcRpcUrl = source.ARC_TESTNET_RPC_URL?.trim();
45491
45576
  const solanaRpcUrl = source.SOLANA_RPC_URL?.trim();
@@ -45541,15 +45626,7 @@ async function writeDefaultConfig(path = getVapiPaths().config, source = process
45541
45626
  if (copied.includes(path)) return await loadConfig(path, source);
45542
45627
  }
45543
45628
  const config2 = getDefaultConfig(source, options);
45544
- await mkdir(dirname(path), { recursive: true, mode: 448 });
45545
- const temporaryPath = `${path}.${process.pid}.tmp`;
45546
- await writeFile(temporaryPath, `${JSON.stringify(config2, null, 2)}
45547
- `, {
45548
- encoding: "utf8",
45549
- mode: 384,
45550
- flag: "wx"
45551
- });
45552
- await rename(temporaryPath, path);
45629
+ await writeConfigFile(path, config2);
45553
45630
  return config2;
45554
45631
  }
45555
45632
  async function enableDefaultNetwork(network, path = getVapiPaths().config, source = process.env) {
@@ -45560,6 +45637,10 @@ async function enableDefaultNetwork(network, path = getVapiPaths().config, sourc
45560
45637
  usdc: NETWORKS[SOLANA_MAINNET_CAIP2].usdc
45561
45638
  };
45562
45639
  }
45640
+ await writeConfigFile(path, config2);
45641
+ return config2;
45642
+ }
45643
+ async function writeConfigFile(path, config2) {
45563
45644
  await mkdir(dirname(path), { recursive: true, mode: 448 });
45564
45645
  const temporaryPath = `${path}.${process.pid}.tmp`;
45565
45646
  await writeFile(temporaryPath, `${JSON.stringify(config2, null, 2)}
@@ -45569,7 +45650,6 @@ async function enableDefaultNetwork(network, path = getVapiPaths().config, sourc
45569
45650
  flag: "wx"
45570
45651
  });
45571
45652
  await rename(temporaryPath, path);
45572
- return config2;
45573
45653
  }
45574
45654
  async function pathExists(path) {
45575
45655
  try {
@@ -45990,6 +46070,49 @@ async function unlockKeystore(passphrase, path = getVapiPaths().keystore) {
45990
46070
  }
45991
46071
  return await paymentAccountFromKeys(keys);
45992
46072
  }
46073
+ async function readKeystoreAddress(path = getVapiPaths().keystore) {
46074
+ let raw;
46075
+ try {
46076
+ raw = await readFile3(path, "utf8");
46077
+ } catch {
46078
+ return void 0;
46079
+ }
46080
+ let parsed;
46081
+ try {
46082
+ parsed = JSON.parse(raw);
46083
+ } catch {
46084
+ return void 0;
46085
+ }
46086
+ const address2 = typeof parsed === "object" && parsed !== null ? Reflect.get(parsed, "address") : void 0;
46087
+ return typeof address2 === "string" ? address2 : void 0;
46088
+ }
46089
+ async function exportKeystoreKeys(passphrase, path = getVapiPaths().keystore) {
46090
+ let raw;
46091
+ try {
46092
+ raw = await readFile3(path, "utf8");
46093
+ } catch (error61) {
46094
+ if (isMissingFile(error61)) {
46095
+ throw new KeystoreError(`No vAPI keystore found at ${path}. Run vapi init.`);
46096
+ }
46097
+ throw error61;
46098
+ }
46099
+ const keys = await decryptKeys(parseAnyKeystore(JSON.parse(raw)), passphrase);
46100
+ const evmPrivateKey = keys.evm;
46101
+ const exported = {
46102
+ evm: { address: privateKeyToAccount(evmPrivateKey).address, privateKey: evmPrivateKey }
46103
+ };
46104
+ if (!keys.solana) return exported;
46105
+ const seed = Uint8Array.from(Buffer.from(keys.solana, "base64"));
46106
+ const signer = await createSolanaSigner(Uint8Array.from(seed));
46107
+ const publicKey = Uint8Array.from(getBase58Encoder().encode(signer.address));
46108
+ const secretKey = new Uint8Array(seed.length + publicKey.length);
46109
+ secretKey.set(seed);
46110
+ secretKey.set(publicKey, seed.length);
46111
+ const encoded = getBase58Decoder().decode(secretKey);
46112
+ seed.fill(0);
46113
+ secretKey.fill(0);
46114
+ return { ...exported, solana: { address: signer.address, secretKey: encoded } };
46115
+ }
45993
46116
  async function enableSolanaKey(passphrase, path = getVapiPaths().keystore) {
45994
46117
  let raw;
45995
46118
  try {
@@ -46669,7 +46792,7 @@ function csvCell(value) {
46669
46792
  import { mkdir as mkdir6, writeFile as writeFile4 } from "node:fs/promises";
46670
46793
  import { arch, platform, release } from "node:os";
46671
46794
  import { join as join2 } from "node:path";
46672
- var VAPI_CLIENT_VERSION = "0.2.1";
46795
+ var VAPI_CLIENT_VERSION = "0.2.3";
46673
46796
  async function createSupportReport(options) {
46674
46797
  const message = options.message.trim();
46675
46798
  if (!message) throw new Error("Support report message must not be empty.");
@@ -48803,132 +48926,122 @@ function asRecord(value) {
48803
48926
  var MARK_SOURCE_WIDTH = 743;
48804
48927
  var MARK_SOURCE_HEIGHT = 659;
48805
48928
  var MARK_SOURCE_ROW_HEIGHT = 217;
48806
- var MARK_COLUMNS = 28;
48807
- var MARK_ROWS = 12;
48808
- var PLAIN_BLOCK = "\u2588";
48809
- var MARK_STEP_MS = 70;
48929
+ var MARK_COLUMNS = 21;
48930
+ var MARK_ROWS = 9;
48931
+ var BLOCK = "\u2588";
48810
48932
  var WORDMARK = "vAPI Network";
48811
48933
  var WELCOME = "Welcome to the vAPI Network";
48812
48934
  var TAGLINE = [
48813
- "The trusted network where agents and humans do business.",
48814
- "Search APIs, pay per call, keep receipts. More coming soon."
48935
+ "The trusted network where agents",
48936
+ "and humans do business.",
48937
+ "",
48938
+ "Search APIs, pay per call, keep",
48939
+ "receipts. More coming soon."
48815
48940
  ];
48816
- var ESC = "\x1B";
48941
+ var ESC = String.fromCharCode(27);
48817
48942
  var RESET = `${ESC}[0m`;
48818
- var REVERSE = `${ESC}[7m`;
48819
48943
  var BOLD = `${ESC}[1m`;
48820
48944
  var DIM = `${ESC}[2m`;
48821
- var HIDE_CURSOR = `${ESC}[?25l`;
48822
- var SHOW_CURSOR = `${ESC}[?25h`;
48945
+ var DEFAULT_FOREGROUND = `${ESC}[39m`;
48823
48946
  var MARK_PALETTE = {
48824
- orange: "#ff7300",
48825
- pink: "#ff337c",
48826
- lime: "#c3ff3d",
48827
- cyan: "#97efff",
48828
- blue: "#0041eb",
48829
- purple: "#8a37fb",
48947
+ orange: { hex: "#ff7300", ansi16: 33 },
48948
+ pink: { hex: "#ff337c", ansi16: 95 },
48949
+ lime: { hex: "#c3ff3d", ansi16: 92 },
48950
+ cyan: { hex: "#97efff", ansi16: 96 },
48951
+ blue: { hex: "#0041eb", ansi16: 34 },
48952
+ purple: { hex: "#8a37fb", ansi16: 35 },
48830
48953
  ink: null
48831
48954
  };
48832
48955
  var MARK_BLOCKS = [
48833
- { row: 0, x: 2, width: 90, color: "orange", delay: 0 },
48834
- { row: 0, x: 94, width: 35, color: "pink", delay: 1 },
48835
- { row: 0, x: 131, width: 16, color: "lime", delay: 2 },
48836
- { row: 0, x: 522, width: 219, color: "ink", delay: 1 },
48837
- { row: 1, x: 124, width: 50, color: "cyan", delay: 3 },
48838
- { row: 1, x: 176, width: 24, color: "blue", delay: 4 },
48839
- { row: 1, x: 202, width: 17, color: "purple", delay: 5 },
48840
- { row: 1, x: 402, width: 219, color: "blue", delay: 4 },
48841
- { row: 2, x: 282, width: 219, color: "ink", delay: 7 }
48956
+ { row: 0, x: 2, width: 90, color: "orange" },
48957
+ { row: 0, x: 94, width: 35, color: "pink" },
48958
+ { row: 0, x: 131, width: 16, color: "lime" },
48959
+ { row: 0, x: 522, width: 219, color: "ink" },
48960
+ { row: 1, x: 124, width: 50, color: "cyan" },
48961
+ { row: 1, x: 176, width: 24, color: "blue" },
48962
+ { row: 1, x: 202, width: 17, color: "purple" },
48963
+ { row: 1, x: 402, width: 219, color: "blue" },
48964
+ { row: 2, x: 282, width: 219, color: "ink" }
48842
48965
  ];
48843
- function markColorEnabled(environment = {}) {
48966
+ function detectColorLevel(environment = {}) {
48844
48967
  const env = environment.env ?? process.env;
48845
48968
  const isTty = environment.isTty ?? Boolean(process.stdout.isTTY);
48846
- return isTty && !env.NO_COLOR;
48847
- }
48848
- function shouldAnimateMark(environment = {}) {
48849
- const env = environment.env ?? process.env;
48850
- if (environment.json) return false;
48851
- if (env.NO_COLOR || env.CI) return false;
48852
- return markColorEnabled(environment);
48853
- }
48854
- function renderMarkFrames(options = {}) {
48855
- const steps = [...new Set(MARK_BLOCKS.map((block) => block.delay))].sort(
48856
- (left, right) => left - right
48857
- );
48858
- return steps.map(
48859
- (step) => renderFrame(
48860
- MARK_BLOCKS.filter((block) => block.delay <= step),
48861
- options.color === true
48862
- )
48863
- );
48864
- }
48865
- function renderBanner(options) {
48866
- const frames = renderMarkFrames(options);
48867
- return renderBox(frames[frames.length - 1], options).join("\n");
48868
- }
48869
- async function animateBanner(options) {
48870
- const frames = renderMarkFrames({ color: options.color !== false });
48871
- const sleep = options.sleep ?? defaultSleep;
48872
- const stepMs = options.stepMs ?? MARK_STEP_MS;
48873
- const boxes = frames.map((frame) => renderBox(frame, options));
48874
- const height = boxes[0].length;
48875
- options.write(HIDE_CURSOR);
48876
- try {
48877
- for (const [index2, box] of boxes.entries()) {
48878
- if (index2 > 0) options.write(`${ESC}[${height}A`);
48879
- options.write(box.map((line) => `\r${ESC}[2K${line}
48880
- `).join(""));
48881
- if (index2 < boxes.length - 1) await sleep(stepMs);
48882
- }
48883
- } finally {
48884
- options.write(SHOW_CURSOR);
48885
- }
48886
- }
48887
- function renderBox(frame, options) {
48888
- const color = options.color === true;
48889
- const text = [
48890
- { value: WELCOME, style: BOLD },
48891
- { value: "", style: "" },
48892
- ...TAGLINE.map((line) => ({ value: line, style: "" })),
48893
- { value: "", style: "" },
48894
- { value: `${WORDMARK} v${options.version}`, style: DIM }
48895
- ];
48896
- const textWidth = Math.max(...text.map((line) => line.value.length));
48897
- const gap = 3;
48898
- const inner = 2 + MARK_COLUMNS + gap + textWidth + 2;
48899
- const markLines = frame.split("\n");
48900
- const textTop = Math.floor((MARK_ROWS - text.length) / 2);
48901
- const lines = [];
48902
- lines.push(`\u256D${"\u2500".repeat(inner)}\u256E`);
48903
- lines.push(`\u2502${" ".repeat(inner)}\u2502`);
48904
- for (let row = 0; row < MARK_ROWS; row += 1) {
48905
- const mark = markLines[row] ?? "";
48906
- const markPad = " ".repeat(Math.max(0, MARK_COLUMNS - visibleLength(mark)));
48907
- const entry = text[row - textTop];
48908
- const raw = entry?.value ?? "";
48909
- const styled = color && entry && entry.style && raw ? `${entry.style}${raw}${RESET}` : raw;
48910
- const textPad = " ".repeat(textWidth - raw.length);
48911
- lines.push(`\u2502 ${mark}${markPad}${" ".repeat(gap)}${styled}${textPad} \u2502`);
48969
+ if (env.NO_COLOR) return 0;
48970
+ const forced = env.FORCE_COLOR;
48971
+ if (forced !== void 0) {
48972
+ if (forced === "0" || forced === "false") return 0;
48973
+ if (forced === "2") return 2;
48974
+ if (forced === "3") return 3;
48975
+ return 1;
48912
48976
  }
48913
- lines.push(`\u2502${" ".repeat(inner)}\u2502`);
48914
- lines.push(`\u2570${"\u2500".repeat(inner)}\u256F`);
48915
- return lines;
48916
- }
48917
- function renderFrame(blocks, color) {
48977
+ if (!isTty) return 0;
48978
+ const term = env.TERM ?? "";
48979
+ const program = env.TERM_PROGRAM ?? "";
48980
+ if (term === "dumb") return 0;
48981
+ if (/^(truecolor|24bit)$/i.test(env.COLORTERM ?? "")) return 3;
48982
+ if (/kitty|wezterm|ghostty|alacritty/i.test(term)) return 3;
48983
+ if (/^(iTerm\.app|vscode|Hyper|WezTerm|ghostty)$/i.test(program)) return 3;
48984
+ if (/-256(?:color)?$/i.test(term) || program === "Apple_Terminal") return 2;
48985
+ return 1;
48986
+ }
48987
+ function renderMark(colorLevel = 0) {
48918
48988
  const rows = [];
48919
48989
  for (let row = 0; row < MARK_ROWS; row += 1) {
48920
48990
  const sourceY = row * MARK_SOURCE_HEIGHT / MARK_ROWS;
48921
48991
  const band = Math.min(2, Math.floor(sourceY / MARK_SOURCE_ROW_HEIGHT));
48922
48992
  rows.push(
48923
48993
  renderRow(
48924
- blocks.filter((block) => block.row === band),
48925
- color
48994
+ MARK_BLOCKS.filter((block) => block.row === band),
48995
+ colorLevel
48926
48996
  )
48927
48997
  );
48928
48998
  }
48929
48999
  return rows.join("\n");
48930
49000
  }
48931
- function renderRow(blocks, color) {
49001
+ function bannerWidth() {
49002
+ return frameInnerWidth() + 2;
49003
+ }
49004
+ function renderBanner(options) {
49005
+ const colorLevel = options.colorLevel ?? 0;
49006
+ const columns = options.columns ?? Number.POSITIVE_INFINITY;
49007
+ const text = bannerText(options.version, colorLevel);
49008
+ if (columns < bannerWidth()) {
49009
+ return text.map((line) => line.styled).join("\n");
49010
+ }
49011
+ const inner = frameInnerWidth();
49012
+ const markLines = renderMark(colorLevel).split("\n");
49013
+ const lines = [];
49014
+ lines.push(`\u256D${"\u2500".repeat(inner)}\u256E`);
49015
+ lines.push(`\u2502${" ".repeat(inner)}\u2502`);
49016
+ for (let row = 0; row < MARK_ROWS; row += 1) {
49017
+ const entry = text[row];
49018
+ const value = entry?.value ?? "";
49019
+ const styled = entry?.styled ?? "";
49020
+ const pad4 = " ".repeat(TEXT_WIDTH - value.length);
49021
+ lines.push(`\u2502 ${markLines[row]}${" ".repeat(GAP)}${styled}${pad4} \u2502`);
49022
+ }
49023
+ lines.push(`\u2502${" ".repeat(inner)}\u2502`);
49024
+ lines.push(`\u2570${"\u2500".repeat(inner)}\u256F`);
49025
+ return lines.join("\n");
49026
+ }
49027
+ var GAP = 3;
49028
+ var TEXT_WIDTH = Math.max(WELCOME.length, ...TAGLINE.map((line) => line.length));
49029
+ function frameInnerWidth() {
49030
+ return 2 + MARK_COLUMNS + GAP + TEXT_WIDTH + 2;
49031
+ }
49032
+ function bannerText(version5, colorLevel) {
49033
+ const style = (value, code) => colorLevel > 0 && value ? `${code}${value}${RESET}` : value;
49034
+ const rows = [
49035
+ { value: WELCOME, styled: style(WELCOME, BOLD) },
49036
+ { value: "", styled: "" },
49037
+ ...TAGLINE.map((line) => ({ value: line, styled: line })),
49038
+ { value: "", styled: "" },
49039
+ { value: `${WORDMARK} v${version5}`, styled: style(`${WORDMARK} v${version5}`, DIM) }
49040
+ ];
49041
+ if (rows.length > MARK_ROWS) throw new Error("banner text is taller than the mark");
49042
+ return rows;
49043
+ }
49044
+ function renderRow(blocks, colorLevel) {
48932
49045
  const ordered = [...blocks].sort((left, right) => left.x - right.x);
48933
49046
  let column = 0;
48934
49047
  let line = "";
@@ -48939,7 +49052,8 @@ function renderRow(blocks, color) {
48939
49052
  column = start;
48940
49053
  }
48941
49054
  const width = scaleWidth(block.width);
48942
- line += color ? `${cellPrefix(block.color)}${" ".repeat(width)}${RESET}` : PLAIN_BLOCK.repeat(width);
49055
+ const cells = BLOCK.repeat(width);
49056
+ line += colorLevel > 0 ? `${foreground(block.color, colorLevel)}${cells}${RESET}` : cells;
48943
49057
  column += width;
48944
49058
  }
48945
49059
  return line + " ".repeat(Math.max(0, MARK_COLUMNS - column));
@@ -48950,23 +49064,28 @@ function scaleColumn(x) {
48950
49064
  function scaleWidth(width) {
48951
49065
  return Math.max(1, Math.round(width * MARK_COLUMNS / MARK_SOURCE_WIDTH));
48952
49066
  }
48953
- function cellPrefix(color) {
48954
- const hex3 = MARK_PALETTE[color];
48955
- if (hex3 === null) return REVERSE;
48956
- const value = Number.parseInt(hex3.slice(1), 16);
48957
- return `${ESC}[48;2;${value >> 16 & 255};${value >> 8 & 255};${value & 255}m`;
48958
- }
48959
- function visibleLength(line) {
48960
- return line.replace(new RegExp(`${ESC}\\[[0-9;?]*[A-Za-z]`, "g"), "").length;
49067
+ function foreground(color, colorLevel) {
49068
+ const entry = MARK_PALETTE[color];
49069
+ if (entry === null) return DEFAULT_FOREGROUND;
49070
+ const value = Number.parseInt(entry.hex.slice(1), 16);
49071
+ const red = value >> 16 & 255;
49072
+ const green = value >> 8 & 255;
49073
+ const blue = value & 255;
49074
+ if (colorLevel === 3) return `${ESC}[38;2;${red};${green};${blue}m`;
49075
+ if (colorLevel === 2) return `${ESC}[38;5;${rgbToAnsi256(red, green, blue)}m`;
49076
+ return `${ESC}[${entry.ansi16}m`;
48961
49077
  }
48962
- function defaultSleep(milliseconds) {
48963
- return new Promise((resolve) => {
48964
- setTimeout(resolve, milliseconds);
48965
- });
49078
+ function rgbToAnsi256(red, green, blue) {
49079
+ if (red === green && green === blue) {
49080
+ if (red < 8) return 16;
49081
+ if (red > 248) return 231;
49082
+ return Math.round((red - 8) / 247 * 24) + 232;
49083
+ }
49084
+ return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
48966
49085
  }
48967
49086
 
48968
49087
  // src/version.ts
48969
- var CLI_VERSION = "0.2.1";
49088
+ var CLI_VERSION = "0.2.3";
48970
49089
 
48971
49090
  // src/cli.ts
48972
49091
  var HELP_HEADING = "vAPI Network";
@@ -48984,6 +49103,7 @@ Usage:
48984
49103
  vapi receipts export --format <json|csv> [--range <24h|7d|30d>]
48985
49104
  vapi stats [--range <24h|7d|30d>] [--json]
48986
49105
  vapi sweep <address> [--network <caip2>] [--json]
49106
+ vapi export-key [--network <caip2>] [--json]
48987
49107
  vapi report "<what happened>" [--include-addresses] [--send] [--json]
48988
49108
  vapi mcp [--json]
48989
49109
  vapi serve [--json]
@@ -48995,8 +49115,7 @@ var processIo = {
48995
49115
  stdout: (message) => process.stdout.write(`${message}
48996
49116
  `),
48997
49117
  stderr: (message) => process.stderr.write(`${message}
48998
- `),
48999
- write: (chunk) => process.stdout.write(chunk)
49118
+ `)
49000
49119
  };
49001
49120
  var UsageError = class extends Error {
49002
49121
  };
@@ -49015,7 +49134,7 @@ async function runCli(argv = process.argv.slice(2), io = processIo, dependencies
49015
49134
  if (command === void 0 || command === "help" || command === "--help" || command === "-h") {
49016
49135
  requireNoArguments(args.slice(command === void 0 ? 0 : 1), command ?? "help");
49017
49136
  if (command === void 0 && !json2) {
49018
- io.stdout(staticBanner());
49137
+ showBanner(io);
49019
49138
  io.stdout(HELP.slice(HELP_HEADING.length + 2));
49020
49139
  return 0;
49021
49140
  }
@@ -49053,6 +49172,9 @@ async function runCli(argv = process.argv.slice(2), io = processIo, dependencies
49053
49172
  case "sweep":
49054
49173
  await sweepCommand(args.slice(1), json2, io);
49055
49174
  return 0;
49175
+ case "export-key":
49176
+ await exportKeyCommand(args.slice(1), json2, io);
49177
+ return 0;
49056
49178
  case "report":
49057
49179
  await reportCommand(args.slice(1), json2, io, dependencies);
49058
49180
  return 0;
@@ -49086,14 +49208,24 @@ async function initCommand(argv, json2, io, dependencies) {
49086
49208
  });
49087
49209
  const networks = parseInitNetworks(parsed.one("--networks") ?? "base");
49088
49210
  const enableSolana = networks.includes("solana");
49089
- if (!json2) await showBanner(io);
49211
+ if (!json2) showBanner(io);
49090
49212
  const paths = getVapiPaths();
49091
49213
  let migrated = [];
49092
49214
  if (!process.env.VAPI_HOME?.trim()) {
49093
49215
  migrated = await migrateLegacyVapiHome({ targetDirectory: paths.directory, notice: io.stderr });
49094
49216
  }
49217
+ const adopted = migrated.includes(paths.keystore);
49218
+ if (!adopted && await fileExists(paths.keystore)) {
49219
+ const address2 = await readKeystoreAddress(paths.keystore);
49220
+ throw new Error(
49221
+ [
49222
+ `Keystore already exists at ${paths.keystore}. Refusing to replace the local payment key.`,
49223
+ ...address2 ? [`Address: ${address2}`] : []
49224
+ ].join("\n")
49225
+ );
49226
+ }
49095
49227
  const passphrase = await getKeystorePassphrase({ confirm: true });
49096
- let account = migrated.includes(paths.keystore) ? await unlockKeystore(passphrase, paths.keystore) : await createKeystore(passphrase, paths.keystore, { enableSolana });
49228
+ let account = adopted ? await unlockKeystore(passphrase, paths.keystore) : await createKeystore(passphrase, paths.keystore, { enableSolana });
49097
49229
  if (enableSolana && !account.solana) {
49098
49230
  account = await enableSolanaKey(passphrase, paths.keystore);
49099
49231
  }
@@ -49102,7 +49234,8 @@ async function initCommand(argv, json2, io, dependencies) {
49102
49234
  } else if (enableSolana) {
49103
49235
  await enableDefaultNetwork("solana", paths.config);
49104
49236
  }
49105
- const config2 = await loadConfig(paths.config);
49237
+ const configRewrites = await migrateLegacyRegistryConfig(paths.config);
49238
+ const config2 = await readConfig(paths.config, io);
49106
49239
  const accounts = await listAccounts({
49107
49240
  address: account.address,
49108
49241
  ...account.solana ? { solanaAddress: account.solana.address } : {},
@@ -49114,6 +49247,7 @@ async function initCommand(argv, json2, io, dependencies) {
49114
49247
  accounts,
49115
49248
  config: paths.config,
49116
49249
  keystore: paths.keystore,
49250
+ ...configRewrites.length > 0 ? { configRewrites } : {},
49117
49251
  message: "vAPI wallet created. Its encrypted key stays on this machine.",
49118
49252
  nextSteps: buildNextSteps(account.address)
49119
49253
  };
@@ -49121,6 +49255,7 @@ async function initCommand(argv, json2, io, dependencies) {
49121
49255
  io.stdout(JSON.stringify(result));
49122
49256
  return;
49123
49257
  }
49258
+ if (configRewrites.length > 0) io.stdout(formatLegacyRegistryRewrites(configRewrites));
49124
49259
  io.stdout(result.message);
49125
49260
  io.stdout(`Address: ${result.address}`);
49126
49261
  io.stdout(
@@ -49145,7 +49280,7 @@ async function fundCommand(argv, json2, io, dependencies) {
49145
49280
  });
49146
49281
  const fiatAmount = optionalUsdAmount(parsed.one("--amount"), "--amount");
49147
49282
  const paths = getVapiPaths();
49148
- const config2 = await loadConfig(paths.config);
49283
+ const config2 = await readConfig(paths.config, io);
49149
49284
  const account = await unlockKeystore(await getKeystorePassphrase(), paths.keystore);
49150
49285
  const session = await createOnrampSession({
49151
49286
  address: account.address,
@@ -49165,7 +49300,7 @@ async function searchCommand(argv, json2, io, dependencies) {
49165
49300
  maximumPositionals: 1
49166
49301
  });
49167
49302
  const limit = optionalPositiveInteger(parsed.one("--limit"), "--limit");
49168
- const config2 = await loadConfig(getVapiPaths().config);
49303
+ const config2 = await readConfig(getVapiPaths().config, io);
49169
49304
  const page = await searchMarketplace(
49170
49305
  {
49171
49306
  ...parsed.positionals[0] ? { query: parsed.positionals[0] } : {},
@@ -49189,7 +49324,7 @@ async function inspectCommand(argv, json2, io, dependencies) {
49189
49324
  parsed.positionals[0],
49190
49325
  "Usage: vapi inspect <id> [--endpoint <name>]"
49191
49326
  );
49192
- const config2 = await loadConfig(getVapiPaths().config);
49327
+ const config2 = await readConfig(getVapiPaths().config, io);
49193
49328
  const result = await inspectService(
49194
49329
  { id, ...parsed.one("--endpoint") ? { endpoint: parsed.one("--endpoint") } : {} },
49195
49330
  config2,
@@ -49213,7 +49348,7 @@ async function payCommand(argv, json2, io) {
49213
49348
  });
49214
49349
  const target = requiredPositional(parsed.positionals[0], "Usage: vapi pay <id-or-url> [options]");
49215
49350
  const paths = getVapiPaths();
49216
- const config2 = await loadConfig(paths.config);
49351
+ const config2 = await readConfig(paths.config, io);
49217
49352
  const account = await unlockKeystore(await getKeystorePassphrase(), paths.keystore);
49218
49353
  const bodyText = parsed.one("--body");
49219
49354
  const maxPriceUsd = aliasedOption(parsed, "--max", "--max-price-usd");
@@ -49239,7 +49374,7 @@ async function payCommand(argv, json2, io) {
49239
49374
  async function balanceCommand(argv, json2, io, dependencies) {
49240
49375
  requireNoArguments(argv, "balance");
49241
49376
  const paths = getVapiPaths();
49242
- const config2 = await loadConfig(paths.config);
49377
+ const config2 = await readConfig(paths.config, io);
49243
49378
  const account = await unlockKeystore(await getKeystorePassphrase(), paths.keystore);
49244
49379
  const wallet = await getWallet(account, config2, dependencies);
49245
49380
  output2(io, json2, wallet, formatWallet(wallet));
@@ -49257,7 +49392,7 @@ async function accountsCommand(argv, json2, io, dependencies) {
49257
49392
  const passphrase = await getKeystorePassphrase();
49258
49393
  const account = enable ? await enableSolanaKey(passphrase, paths.keystore) : await unlockKeystore(passphrase, paths.keystore);
49259
49394
  if (enable) await enableDefaultNetwork("solana", paths.config);
49260
- const config2 = await loadConfig(paths.config);
49395
+ const config2 = await readConfig(paths.config, io);
49261
49396
  const accounts = await listAccounts({
49262
49397
  address: account.address,
49263
49398
  ...account.solana ? { solanaAddress: account.solana.address } : {},
@@ -49326,7 +49461,7 @@ async function sweepCommand(argv, json2, io) {
49326
49461
  );
49327
49462
  const requestedNetwork = parsed.one("--network");
49328
49463
  const paths = getVapiPaths();
49329
- const config2 = await loadConfig(paths.config);
49464
+ const config2 = await readConfig(paths.config, io);
49330
49465
  const account = await unlockKeystore(await getKeystorePassphrase(), paths.keystore);
49331
49466
  if (requestedNetwork && !isNetworkConfigured(config2.networks, requestedNetwork)) {
49332
49467
  throw new Error(`Network ${requestedNetwork} is not configured.`);
@@ -49370,6 +49505,33 @@ async function reportCommand(argv, json2, io, dependencies) {
49370
49505
  });
49371
49506
  output2(io, json2, result, formatSupportReport(result));
49372
49507
  }
49508
+ var EXPORT_KEY_WARNING = "Anyone with this key can spend the wallet. Never paste it into a website or chat.";
49509
+ async function exportKeyCommand(argv, json2, io) {
49510
+ const parsed = parseArguments(argv, {
49511
+ valueOptions: /* @__PURE__ */ new Set(["--network"]),
49512
+ maximumPositionals: 0
49513
+ });
49514
+ const network = parsed.one("--network") ?? BASE_MAINNET_CAIP2;
49515
+ const solana = isSolanaNetwork(network);
49516
+ if (!solana && !network.startsWith("eip155:")) {
49517
+ throw new UsageError("--network must be an eip155:<chainId> or Solana network identifier.");
49518
+ }
49519
+ const paths = getVapiPaths();
49520
+ const keys = await exportKeystoreKeys(await getKeystorePassphrase(), paths.keystore);
49521
+ if (solana && !keys.solana) {
49522
+ throw new Error(
49523
+ `No Solana key is enabled in ${paths.keystore}. Run vapi accounts --enable solana first.`
49524
+ );
49525
+ }
49526
+ const selected = solana && keys.solana ? keys.solana : keys.evm;
49527
+ const result = {
49528
+ network,
49529
+ address: selected.address,
49530
+ privateKey: "secretKey" in selected ? selected.secretKey : selected.privateKey
49531
+ };
49532
+ io.stderr(EXPORT_KEY_WARNING);
49533
+ io.stdout(json2 ? JSON.stringify(result) : result.privateKey);
49534
+ }
49373
49535
  async function mcpCommand(argv) {
49374
49536
  requireNoArguments(argv, "mcp");
49375
49537
  const paths = getVapiPaths();
@@ -49383,6 +49545,9 @@ async function mcpCommand(argv) {
49383
49545
  searchesPath: paths.searches
49384
49546
  });
49385
49547
  }
49548
+ async function readConfig(path, io) {
49549
+ return await loadConfig(path, process.env, { notice: io.stderr });
49550
+ }
49386
49551
  function output2(io, json2, value, human) {
49387
49552
  io.stdout(json2 ? JSON.stringify(value) : human);
49388
49553
  }
@@ -49448,16 +49613,14 @@ function formatNextStep(label, value, note) {
49448
49613
  const step = `${label.padEnd(10)}${value}`;
49449
49614
  return note === void 0 ? step : `${step.padEnd(52)} ${note}`;
49450
49615
  }
49451
- async function showBanner(io) {
49452
- const write = io.write;
49453
- if (write === void 0 || !shouldAnimateMark()) {
49454
- io.stdout(staticBanner());
49455
- return;
49456
- }
49457
- await animateBanner({ version: CLI_VERSION, write });
49458
- }
49459
- function staticBanner() {
49460
- return renderBanner({ version: CLI_VERSION, color: markColorEnabled() });
49616
+ function showBanner(io) {
49617
+ io.stdout(
49618
+ renderBanner({
49619
+ version: CLI_VERSION,
49620
+ colorLevel: detectColorLevel(),
49621
+ columns: process.stdout.columns
49622
+ })
49623
+ );
49461
49624
  }
49462
49625
  function formatAccounts(accounts) {
49463
49626
  if (accounts.length === 0) return "No configured network accounts.";