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