apiblaze 0.20.10 → 0.20.11

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.
Files changed (2) hide show
  1. package/dist/index.js +547 -357
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -137,8 +137,8 @@ async function createProxyAnonymous(body) {
137
137
  }
138
138
  return res.json();
139
139
  }
140
- async function apiFetch(path8, options = {}, auth) {
141
- const url = `${DASHBOARD_BASE}${path8}`;
140
+ async function apiFetch(path9, options = {}, auth) {
141
+ const url = `${DASHBOARD_BASE}${path9}`;
142
142
  const res = await fetch(url, {
143
143
  ...options,
144
144
  headers: {
@@ -164,12 +164,12 @@ async function apiFetch(path8, options = {}, auth) {
164
164
  }
165
165
  return res.json();
166
166
  }
167
- async function agentCall(path8, method, body) {
167
+ async function agentCall(path9, method, body) {
168
168
  const token = getAccessToken();
169
169
  const res = await fetch(`${DASHBOARD_BASE}/api/cli/agents`, {
170
170
  method: "POST",
171
171
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
172
- body: JSON.stringify({ path: path8, method, body })
172
+ body: JSON.stringify({ path: path9, method, body })
173
173
  });
174
174
  let data = null;
175
175
  try {
@@ -1021,10 +1021,10 @@ var init_tenant_pick = __esm({
1021
1021
 
1022
1022
  // src/index.ts
1023
1023
  var import_commander = require("commander");
1024
- var import_chalk52 = __toESM(require("chalk"));
1024
+ var import_chalk53 = __toESM(require("chalk"));
1025
1025
 
1026
1026
  // package.json
1027
- var version = "0.20.10";
1027
+ var version = "0.20.11";
1028
1028
 
1029
1029
  // src/index.ts
1030
1030
  init_types();
@@ -1290,11 +1290,11 @@ function decodeJwt(token) {
1290
1290
  return null;
1291
1291
  }
1292
1292
  }
1293
- function maskPath(path8) {
1294
- const q = path8.indexOf("?");
1295
- if (q < 0) return path8;
1296
- const base2 = path8.slice(0, q);
1297
- const query = path8.slice(q + 1);
1293
+ function maskPath(path9) {
1294
+ const q = path9.indexOf("?");
1295
+ if (q < 0) return path9;
1296
+ const base2 = path9.slice(0, q);
1297
+ const query = path9.slice(q + 1);
1298
1298
  const masked = query.split("&").map((pair) => {
1299
1299
  const eq = pair.indexOf("=");
1300
1300
  if (eq < 0) return pair;
@@ -2328,7 +2328,7 @@ async function runCreate(opts = {}) {
2328
2328
  }
2329
2329
  let openapiContent = null;
2330
2330
  if (opts.openapi !== void 0) {
2331
- if (opts.target !== void 0) fail("Provide only one of --target or --openapi.");
2331
+ if (opts.target !== void 0) fail("Provide only one source (the smart --target covers servers, spec files and spec URLs).");
2332
2332
  openapiContent = await loadOpenapiSource(opts.openapi);
2333
2333
  }
2334
2334
  let targetUrl = "";
@@ -2352,7 +2352,7 @@ async function runCreate(opts = {}) {
2352
2352
  break;
2353
2353
  }
2354
2354
  } else {
2355
- fail("--target or --openapi is required in non-interactive mode.");
2355
+ fail("--target is required in non-interactive mode (a server base URL, a local OpenAPI file, or a remote OpenAPI URL).");
2356
2356
  }
2357
2357
  if (interactive && !opts.yes) {
2358
2358
  const { default: inquirer3 } = await import("inquirer");
@@ -3529,8 +3529,8 @@ function resolveRecipeName(raw, githubHandle, proxyName) {
3529
3529
  function normalizeName2(raw) {
3530
3530
  return (raw || "").toLowerCase().replace(/[^a-z0-9]/g, "");
3531
3531
  }
3532
- async function publicFetch(path8) {
3533
- const res = await fetch(`${RECIPES_BASE}/api/recipes${path8}`, {
3532
+ async function publicFetch(path9) {
3533
+ const res = await fetch(`${RECIPES_BASE}/api/recipes${path9}`, {
3534
3534
  headers: { accept: "application/json" }
3535
3535
  }).catch((err) => {
3536
3536
  throw new Error(`Could not reach the recipe registry at ${RECIPES_BASE} \u2014 ${err.message}`);
@@ -3583,11 +3583,11 @@ async function fetchRecipeFile(ref, caller) {
3583
3583
  Private recipes are visible only to the publisher's team \u2014 run \`apiblaze login\` if you are on it.`
3584
3584
  );
3585
3585
  }
3586
- const path8 = revision !== void 0 ? `/recipes/${ref.handle}/${ref.slug}/${revision}` : `/recipes/${ref.handle}/${ref.slug}/file`;
3586
+ const path9 = revision !== void 0 ? `/recipes/${ref.handle}/${ref.slug}/${revision}` : `/recipes/${ref.handle}/${ref.slug}/file`;
3587
3587
  try {
3588
3588
  return await producer(caller, {
3589
3589
  method: "GET",
3590
- path: path8,
3590
+ path: path9,
3591
3591
  summary: `Read private recipe ${ref.name}${revision !== void 0 ? `@${revision}` : ""}`
3592
3592
  });
3593
3593
  } catch (err) {
@@ -4739,9 +4739,9 @@ function printEnvelopeViolations(violations) {
4739
4739
  console.log("bring-your-own-key case. Change the rules above, then publish again.");
4740
4740
  console.log();
4741
4741
  }
4742
- async function askPromotion(path8) {
4742
+ async function askPromotion(path9) {
4743
4743
  const { default: inquirer3 } = await import("inquirer");
4744
- const suggestedId = path8.split(/[.[\]]/).filter(Boolean).slice(-2).join("_").toLowerCase().replace(/[^a-z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "") || "value";
4744
+ const suggestedId = path9.split(/[.[\]]/).filter(Boolean).slice(-2).join("_").toLowerCase().replace(/[^a-z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "") || "value";
4745
4745
  const answers = await inquirer3.prompt([
4746
4746
  { type: "input", name: "prompt", message: " prompt them with:", validate: (v) => v.trim() ? true : "Required." },
4747
4747
  { type: "input", name: "example", message: " example:" },
@@ -4752,7 +4752,7 @@ async function askPromotion(path8) {
4752
4752
  const id = String(answers.id || suggestedId).toLowerCase().replace(/[^a-z0-9_]/g, "_");
4753
4753
  console.log(import_chalk27.default.dim(` \u2192 replaced with {{${id}}}`));
4754
4754
  return {
4755
- path: path8,
4755
+ path: path9,
4756
4756
  id,
4757
4757
  prompt: String(answers.prompt).trim(),
4758
4758
  ...answers.example ? { example: String(answers.example).trim() } : {},
@@ -7802,11 +7802,11 @@ async function resolveTransport(opts) {
7802
7802
  const token = getAccessToken();
7803
7803
  return {
7804
7804
  tenant: tenant2,
7805
- call: async (path8, method = "GET", body) => {
7805
+ call: async (path9, method = "GET", body) => {
7806
7806
  const res = await fetch(`${DASHBOARD_BASE6}/api/cli/iam`, {
7807
7807
  method: "POST",
7808
7808
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
7809
- body: JSON.stringify({ tenant: tenant2, path: path8, method, body })
7809
+ body: JSON.stringify({ tenant: tenant2, path: path9, method, body })
7810
7810
  });
7811
7811
  const data = await res.json().catch(() => ({}));
7812
7812
  if (!res.ok) throw new ApiError(res.status, data?.details ?? data?.error ?? res.statusText, data);
@@ -7824,8 +7824,8 @@ async function resolveTransport(opts) {
7824
7824
  return {
7825
7825
  tenant: fresh.tenant,
7826
7826
  selfEmail: fresh.email,
7827
- call: async (path8, method = "GET", body) => {
7828
- const res = await fetch(`${IAM_BASE}${path8}`, {
7827
+ call: async (path9, method = "GET", body) => {
7828
+ const res = await fetch(`${IAM_BASE}${path9}`, {
7829
7829
  method,
7830
7830
  headers: {
7831
7831
  "Content-Type": "application/json",
@@ -8177,12 +8177,12 @@ init_admin();
8177
8177
  init_resolve();
8178
8178
  init_types();
8179
8179
  var DASHBOARD_BASE7 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
8180
- async function iamCall(tenant2, path8, method = "GET", body) {
8180
+ async function iamCall(tenant2, path9, method = "GET", body) {
8181
8181
  const token = getAccessToken();
8182
8182
  const res = await fetch(`${DASHBOARD_BASE7}/api/cli/iam`, {
8183
8183
  method: "POST",
8184
8184
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
8185
- body: JSON.stringify({ tenant: tenant2, path: path8, method, body })
8185
+ body: JSON.stringify({ tenant: tenant2, path: path9, method, body })
8186
8186
  });
8187
8187
  const data = await res.json().catch(() => ({}));
8188
8188
  if (!res.ok) throw new ApiError(res.status, data?.details ?? data?.error ?? res.statusText, data);
@@ -8269,10 +8269,10 @@ async function runPreapprove(who, opts) {
8269
8269
  }
8270
8270
 
8271
8271
  // src/commands/apichat.ts
8272
- var fs10 = __toESM(require("fs"));
8273
- var path6 = __toESM(require("path"));
8272
+ var fs11 = __toESM(require("fs"));
8273
+ var path7 = __toESM(require("path"));
8274
8274
  var crypto2 = __toESM(require("crypto"));
8275
- var import_chalk46 = __toESM(require("chalk"));
8275
+ var import_chalk47 = __toESM(require("chalk"));
8276
8276
  var import_ora23 = __toESM(require("ora"));
8277
8277
  var import_yaml3 = require("yaml");
8278
8278
  init_auth();
@@ -8353,11 +8353,134 @@ async function runLlmClearKey() {
8353
8353
 
8354
8354
  // src/commands/apichat.ts
8355
8355
  init_trace();
8356
+
8357
+ // src/lib/external-mcp.ts
8358
+ var fs10 = __toESM(require("fs"));
8359
+ var os4 = __toESM(require("os"));
8360
+ var path6 = __toESM(require("path"));
8361
+ var import_child_process2 = require("child_process");
8362
+ var import_chalk46 = __toESM(require("chalk"));
8363
+ var run = (cmd, args, opts = {}) => (0, import_child_process2.spawnSync)(cmd, args, {
8364
+ encoding: "utf-8",
8365
+ stdio: opts.inherit ? ["ignore", "inherit", "inherit"] : ["ignore", "pipe", "pipe"],
8366
+ timeout: opts.inherit ? void 0 : 15e3,
8367
+ shell: process.platform === "win32"
8368
+ // .cmd shims on Windows
8369
+ });
8370
+ function detectExternalClis() {
8371
+ const found = [];
8372
+ for (const [kind, label3] of [["claude", "Claude CLI"], ["codex", "Codex CLI"]]) {
8373
+ try {
8374
+ const r = run(kind, ["--version"]);
8375
+ if (r.status === 0) found.push({ kind, label: label3, version: (r.stdout || "").trim().split("\n")[0] || void 0 });
8376
+ } catch {
8377
+ }
8378
+ }
8379
+ return found;
8380
+ }
8381
+ function claudeInstallArgs(spec2) {
8382
+ const args = ["mcp", "add", "--transport", "http", spec2.name, spec2.url];
8383
+ if (spec2.apiKey) args.push("--header", `X-API-Key: ${spec2.apiKey}`);
8384
+ return args;
8385
+ }
8386
+ function installIntoClaude(spec2) {
8387
+ run("claude", ["mcp", "remove", spec2.name]);
8388
+ const r = run("claude", claudeInstallArgs(spec2));
8389
+ if (r.status === 0) return { ok: true };
8390
+ return { ok: false, error: (r.stderr || r.stdout || `exit ${r.status}`).trim().slice(0, 400) };
8391
+ }
8392
+ function claudeOneShot(spec2, prompt) {
8393
+ const argv = ["claude", "-p", prompt, "--allowedTools", `mcp__${spec2.name}__*`];
8394
+ const r = run(argv[0], argv.slice(1), { inherit: true });
8395
+ return { argv, status: r.status };
8396
+ }
8397
+ function codexConfigPath() {
8398
+ return path6.join(process.env.CODEX_HOME || path6.join(os4.homedir(), ".codex"), "config.toml");
8399
+ }
8400
+ var tomlStr = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
8401
+ function codexServerBlock(spec2) {
8402
+ const lines = [`[mcp_servers.${tomlStr(spec2.name)}]`, `url = ${tomlStr(spec2.url)}`];
8403
+ if (spec2.apiKey) lines.push(`http_headers = { "X-API-Key" = ${tomlStr(spec2.apiKey)} }`);
8404
+ return lines.join("\n") + "\n";
8405
+ }
8406
+ function installIntoCodex(spec2) {
8407
+ const file = codexConfigPath();
8408
+ try {
8409
+ fs10.mkdirSync(path6.dirname(file), { recursive: true });
8410
+ let text = "";
8411
+ try {
8412
+ text = fs10.readFileSync(file, "utf-8");
8413
+ } catch {
8414
+ }
8415
+ const esc = spec2.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8416
+ const section = new RegExp(`(^|\\n)\\[mcp_servers\\.(?:"${esc}"|${esc})\\][^\\[]*`, "g");
8417
+ const cleaned = text.replace(section, "$1");
8418
+ const sep = cleaned.length && !cleaned.endsWith("\n\n") ? cleaned.endsWith("\n") ? "\n" : "\n\n" : "";
8419
+ fs10.writeFileSync(file, cleaned + sep + codexServerBlock(spec2), "utf-8");
8420
+ return { ok: true, path: file };
8421
+ } catch (err) {
8422
+ return { ok: false, error: err instanceof Error ? err.message : String(err), path: file };
8423
+ }
8424
+ }
8425
+ function codexOneShot(_spec, prompt) {
8426
+ const argv = ["codex", "exec", prompt];
8427
+ const r = run(argv[0], argv.slice(1), { inherit: true });
8428
+ return { argv, status: r.status };
8429
+ }
8430
+ var shellQuote = (s) => `"${s.replace(/(["\\$`])/g, "\\$1")}"`;
8431
+ function renderCommand(argv) {
8432
+ return argv.map((a, i) => i === 0 || /^[A-Za-z0-9_@%+=:,./-]+$/.test(a) ? a : shellQuote(a)).join(" ");
8433
+ }
8434
+ function installAndDemo(cli, spec2, question, log = console.log) {
8435
+ if (cli.kind === "claude") {
8436
+ log(`
8437
+ ${import_chalk46.default.dim("$")} ${renderCommand(["claude", ...claudeInstallArgs(spec2)])}`);
8438
+ const r = installIntoClaude(spec2);
8439
+ if (!r.ok) {
8440
+ log(import_chalk46.default.red(` Install failed: ${r.error}`));
8441
+ return false;
8442
+ }
8443
+ log(` ${import_chalk46.default.green("\u2714")} MCP ${import_chalk46.default.bold(spec2.name)} added to Claude CLI (local scope \u2014 this directory).`);
8444
+ } else {
8445
+ const r = installIntoCodex(spec2);
8446
+ if (!r.ok) {
8447
+ log(import_chalk46.default.red(` Could not write ${r.path}: ${r.error}`));
8448
+ return false;
8449
+ }
8450
+ log(` ${import_chalk46.default.green("\u2714")} MCP ${import_chalk46.default.bold(spec2.name)} added to ${r.path}.`);
8451
+ }
8452
+ if (!spec2.apiKey) {
8453
+ log(import_chalk46.default.dim(` This proxy authenticates by login: the first call from ${cli.label} will open its sign-in.`));
8454
+ log(`
8455
+ ${import_chalk46.default.bold(`Your ${cli.label} is now able to talk to the ${spec2.projectLabel} API.`)}`);
8456
+ return true;
8457
+ }
8458
+ const oneShot = cli.kind === "claude" ? claudeOneShot : codexOneShot;
8459
+ const abilities = `What are the tool abilities of the MCP server "${spec2.name}"? List them briefly.`;
8460
+ log(`
8461
+ ${import_chalk46.default.dim("Checking what the MCP exposes\u2026")}`);
8462
+ log(` ${import_chalk46.default.dim("$")} ${renderCommand(cli.kind === "claude" ? ["claude", "-p", abilities, "--allowedTools", `mcp__${spec2.name}__*`] : ["codex", "exec", abilities])}
8463
+ `);
8464
+ oneShot(spec2, abilities);
8465
+ if (question) {
8466
+ log(`
8467
+ ${import_chalk46.default.dim("Your question, through " + cli.label + ":")}`);
8468
+ const shown = cli.kind === "claude" ? ["claude", "-p", question, "--allowedTools", `mcp__${spec2.name}__*`] : ["codex", "exec", question];
8469
+ log(` ${import_chalk46.default.dim("$")} ${renderCommand(shown)}
8470
+ `);
8471
+ oneShot(spec2, question);
8472
+ }
8473
+ log(`
8474
+ ${import_chalk46.default.bold(`Your ${cli.label} is now able to talk to the ${spec2.projectLabel} API.`)}`);
8475
+ return true;
8476
+ }
8477
+
8478
+ // src/commands/apichat.ts
8356
8479
  init_types();
8357
8480
  function fail4(message, hint) {
8358
- console.error(import_chalk46.default.red(`
8481
+ console.error(import_chalk47.default.red(`
8359
8482
  Error: ${message}`));
8360
- if (hint) console.error(import_chalk46.default.dim(hint));
8483
+ if (hint) console.error(import_chalk47.default.dim(hint));
8361
8484
  process.exit(1);
8362
8485
  }
8363
8486
  function normalizeName3(raw) {
@@ -8388,7 +8511,7 @@ function parseSpec(text) {
8388
8511
  }
8389
8512
  return parsed;
8390
8513
  }
8391
- var GENERATOR_HINT = "Provide one with --openapispec <file|url>, or build one from real traffic:\n apiblaze create --target <url> then apiblaze agent openapi <project>";
8514
+ var GENERATOR_HINT = "Pass --target <server-url | spec-file | spec-url>, or build a spec from real traffic:\n apiblaze create --target <url> then apiblaze agent openapi <project>";
8392
8515
  async function fetchText(url) {
8393
8516
  try {
8394
8517
  const res = await fetch(url, { headers: { accept: "application/json, application/yaml, text/yaml, */*" } });
@@ -8421,7 +8544,7 @@ async function loadSpec(opts) {
8421
8544
  }
8422
8545
  let text;
8423
8546
  try {
8424
- text = fs10.readFileSync(opts.openapispec, "utf-8");
8547
+ text = fs11.readFileSync(opts.openapispec, "utf-8");
8425
8548
  } catch {
8426
8549
  fail4(`Cannot read spec file: ${opts.openapispec}`);
8427
8550
  }
@@ -8435,7 +8558,7 @@ async function loadSpec(opts) {
8435
8558
  }
8436
8559
  return { spec: found.spec, sourceUrl: found.sourceUrl };
8437
8560
  }
8438
- fail4("No spec source. Pass --openapispec <file|url> or --target <url>.", GENERATOR_HINT);
8561
+ fail4("No spec source. Pass --target <server-url | openapi-file | openapi-url>.", GENERATOR_HINT);
8439
8562
  }
8440
8563
  function resolveTarget(spec2, opts, sourceUrl) {
8441
8564
  if (opts.target) {
@@ -8505,7 +8628,7 @@ async function resolveTargetAuth(spec2, opts) {
8505
8628
  "Re-run with --force to provision anyway (configure target auth later with `apiblaze config`),\nor use an api_key / bearer / basic scheme."
8506
8629
  );
8507
8630
  }
8508
- if (sawOAuth) console.log(import_chalk46.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
8631
+ if (sawOAuth) console.log(import_chalk47.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
8509
8632
  return null;
8510
8633
  }
8511
8634
  if (candidates.length === 1 && !noneAllowed) return candidates[0];
@@ -8579,7 +8702,7 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
8579
8702
  const fresh = await validConsumerToken(existing);
8580
8703
  if (fresh) {
8581
8704
  if (fresh.accessToken !== existing.accessToken) saveConsumer({ ...fresh, resource });
8582
- console.log(import_chalk46.default.dim(` Using your consumer session on ${import_chalk46.default.bold(tenant2)}${fresh.email ? ` (${fresh.email})` : ""}.`));
8705
+ console.log(import_chalk47.default.dim(` Using your consumer session on ${import_chalk47.default.bold(tenant2)}${fresh.email ? ` (${fresh.email})` : ""}.`));
8583
8706
  return fresh;
8584
8707
  }
8585
8708
  }
@@ -8598,13 +8721,13 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
8598
8721
  );
8599
8722
  }
8600
8723
  const clientId = pick2.client_id ?? pick2.clientId;
8601
- console.log(`${import_chalk46.default.cyan("\u2192")} This proxy signs consumers in with OAuth \u2014 logging you in to ${import_chalk46.default.bold(tenant2)}...`);
8724
+ console.log(`${import_chalk47.default.cyan("\u2192")} This proxy signs consumers in with OAuth \u2014 logging you in to ${import_chalk47.default.bold(tenant2)}...`);
8602
8725
  const result = await deviceLogin(clientId, "openid email profile offline_access", ({ verificationUri, userCode }) => {
8603
8726
  console.log(`
8604
- Open: ${import_chalk46.default.underline(verificationUri)}`);
8605
- console.log(` Code: ${import_chalk46.default.bold(userCode)}
8727
+ Open: ${import_chalk47.default.underline(verificationUri)}`);
8728
+ console.log(` Code: ${import_chalk47.default.bold(userCode)}
8606
8729
  `);
8607
- console.log(import_chalk46.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
8730
+ console.log(import_chalk47.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
8608
8731
  }, resource);
8609
8732
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
8610
8733
  const creds = {
@@ -8620,16 +8743,16 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
8620
8743
  resource
8621
8744
  };
8622
8745
  saveConsumer(creds);
8623
- console.log(` ${import_chalk46.default.green("\u2714")} Signed in as${creds.email ? ` ${import_chalk46.default.bold(creds.email)}` : " a consumer"} on ${tenant2}.`);
8746
+ console.log(` ${import_chalk47.default.green("\u2714")} Signed in as${creds.email ? ` ${import_chalk47.default.bold(creds.email)}` : " a consumer"} on ${tenant2}.`);
8624
8747
  return creds;
8625
8748
  }
8626
- async function cpPost(anon, path8, body, summary) {
8749
+ async function cpPost(anon, path9, body, summary) {
8627
8750
  if (anon) {
8628
8751
  const cred = loadAnonCred();
8629
8752
  if (!cred) throw new Error("Anonymous workspace credential missing.");
8630
- return cpFetch(cred.cp_key, path8, { method: "POST", body: JSON.stringify(body) });
8753
+ return cpFetch(cred.cp_key, path9, { method: "POST", body: JSON.stringify(body) });
8631
8754
  }
8632
- return admin({ method: "POST", path: path8, body, summary });
8755
+ return admin({ method: "POST", path: path9, body, summary });
8633
8756
  }
8634
8757
  async function provision(spec2, target, opts) {
8635
8758
  const loggedIn = !!loadCredentials();
@@ -8649,7 +8772,7 @@ async function provision(spec2, target, opts) {
8649
8772
  let name = opts.name ? base2 : `${base2}${salt()}`;
8650
8773
  const access = anon ? "open" : opts.access === "open" ? "open" : "invite";
8651
8774
  if (anon && opts.access === "invite") {
8652
- console.log(import_chalk46.default.dim(" Note: --access invite needs an account to pre-approve people. Staying open for this anonymous proxy \u2014 run `apiblaze login`, then `apiblaze apichat --access invite`."));
8775
+ console.log(import_chalk47.default.dim(" Note: --access invite needs an account to pre-approve people. Staying open for this anonymous proxy \u2014 run `apiblaze login`, then `apiblaze apichat --access invite`."));
8653
8776
  }
8654
8777
  const DUAL_AUTH = {
8655
8778
  mode: "authenticate",
@@ -8748,7 +8871,7 @@ async function provision(spec2, target, opts) {
8748
8871
  try {
8749
8872
  await addPreapprovalRule(tenant2, email);
8750
8873
  } catch {
8751
- console.log(import_chalk46.default.dim(` (Could not auto-approve your email for sign-in \u2014 add it later: apiblaze preapprove ${email})`));
8874
+ console.log(import_chalk47.default.dim(` (Could not auto-approve your email for sign-in \u2014 add it later: apiblaze preapprove ${email})`));
8752
8875
  }
8753
8876
  }
8754
8877
  }
@@ -8792,7 +8915,7 @@ async function uploadSpec(p, specText, opts) {
8792
8915
  throw err;
8793
8916
  }
8794
8917
  if (out && out.reused === true) {
8795
- console.log(import_chalk46.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
8918
+ console.log(import_chalk47.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
8796
8919
  } else if (out && out.changed === true && out.previous_spec_hash) {
8797
8920
  const interactive = !!process.stdin.isTTY && !opts.yes;
8798
8921
  if (interactive) {
@@ -8800,7 +8923,7 @@ async function uploadSpec(p, specText, opts) {
8800
8923
  const { go } = await inquirer3.prompt([
8801
8924
  { type: "confirm", name: "go", message: "The spec changed since the last provision \u2014 re-publish the MCP catalogue?", default: true }
8802
8925
  ]);
8803
- if (!go) console.log(import_chalk46.default.dim(" Keeping the existing MCP catalogue."));
8926
+ if (!go) console.log(import_chalk47.default.dim(" Keeping the existing MCP catalogue."));
8804
8927
  }
8805
8928
  }
8806
8929
  }
@@ -8842,9 +8965,9 @@ function billingLine(info) {
8842
8965
  if (typeof info.free_turns_remaining === "number") return null;
8843
8966
  const cents = info.charged_cents;
8844
8967
  const usd = (cents / 100).toFixed(Math.abs(cents - Math.round(cents)) < 1e-9 ? 2 : 4);
8845
- let line = import_chalk46.default.magenta(` \u{1F4B3} $${usd}`);
8968
+ let line = import_chalk47.default.magenta(` \u{1F4B3} $${usd}`);
8846
8969
  if (typeof info.credits_remaining === "number") {
8847
- line += import_chalk46.default.dim(` \xB7 balance $${(info.credits_remaining / 100).toFixed(2)}`);
8970
+ line += import_chalk47.default.dim(` \xB7 balance $${(info.credits_remaining / 100).toFixed(2)}`);
8848
8971
  }
8849
8972
  return line;
8850
8973
  }
@@ -8852,15 +8975,15 @@ function freeBudgetWarning(info, anon) {
8852
8975
  if (!anon || !info) return null;
8853
8976
  if (typeof info.free_turns_remaining === "number") {
8854
8977
  const left2 = info.free_turns_remaining;
8855
- if (left2 <= 0) return import_chalk46.default.yellow(" Free chats used up \u2014 `npx apiblaze login` (free) to keep going.");
8856
- return import_chalk46.default.dim(` ${left2} free chat${left2 === 1 ? "" : "s"} left \xB7 /login to get more`);
8978
+ if (left2 <= 0) return import_chalk47.default.yellow(" Free chats used up \u2014 `npx apiblaze login` (free) to keep going.");
8979
+ return import_chalk47.default.dim(` ${left2} free chat${left2 === 1 ? "" : "s"} left \xB7 /login to get more`);
8857
8980
  }
8858
8981
  if (typeof info.free_remaining_cents !== "number") return null;
8859
8982
  const perTurn = Math.max(info.charged_cents || 0, 0.02);
8860
8983
  const left = Math.floor(info.free_remaining_cents / perTurn);
8861
8984
  if (left > 8) return null;
8862
- if (left <= 0) return import_chalk46.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
8863
- return import_chalk46.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
8985
+ if (left <= 0) return import_chalk47.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
8986
+ return import_chalk47.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
8864
8987
  }
8865
8988
  async function readSse(body, onEvent) {
8866
8989
  const reader = body.getReader();
@@ -8905,7 +9028,7 @@ async function replTurn(p, messages, userText) {
8905
9028
  });
8906
9029
  } catch (err) {
8907
9030
  spinner.fail("Network error.");
8908
- console.log(import_chalk46.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
9031
+ console.log(import_chalk47.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
8909
9032
  return;
8910
9033
  }
8911
9034
  if ((res.headers.get("content-type") ?? "").includes("text/event-stream") && res.ok && res.body) break;
@@ -8928,12 +9051,12 @@ async function replTurn(p, messages, userText) {
8928
9051
  spinner.start("retrying on the " + (p.anon ? "trial" : "claimed") + " plane\u2026");
8929
9052
  continue;
8930
9053
  }
8931
- console.log(import_chalk46.default.red(` No proxy named ${p.projectId} was found (tried both abz.run and tryabz.run).`));
9054
+ console.log(import_chalk47.default.red(` No proxy named ${p.projectId} was found (tried both abz.run and tryabz.run).`));
8932
9055
  return;
8933
9056
  }
8934
9057
  if (code === "identity_required" || /identif/i.test(msg) && !code) {
8935
9058
  if (!p.endUserId && tty) {
8936
- console.log(import_chalk46.default.yellow(" This API requires every call to say WHO is calling."));
9059
+ console.log(import_chalk47.default.yellow(" This API requires every call to say WHO is calling."));
8937
9060
  const { default: inquirer3 } = await import("inquirer");
8938
9061
  const { id } = await inquirer3.prompt([{ type: "input", name: "id", message: "Your end-user id (usually your email):" }]);
8939
9062
  if (typeof id === "string" && id.trim()) {
@@ -8943,27 +9066,27 @@ async function replTurn(p, messages, userText) {
8943
9066
  continue;
8944
9067
  }
8945
9068
  }
8946
- console.log(import_chalk46.default.red(" This API requires an identified caller."));
8947
- console.log(import_chalk46.default.dim(" Re-run with --xenduserid <your id> (usually your email)."));
9069
+ console.log(import_chalk47.default.red(" This API requires an identified caller."));
9070
+ console.log(import_chalk47.default.dim(" Re-run with --xenduserid <your id> (usually your email)."));
8948
9071
  return;
8949
9072
  }
8950
9073
  if (code === "user_not_preapproved") {
8951
- console.log(import_chalk46.default.yellow(` ${msg || "You are not pre-approved on this API."}`));
8952
- if (p.endUserId) console.log(import_chalk46.default.dim(` Identity sent: ${p.endUserId}`));
9074
+ console.log(import_chalk47.default.yellow(` ${msg || "You are not pre-approved on this API."}`));
9075
+ if (p.endUserId) console.log(import_chalk47.default.dim(` Identity sent: ${p.endUserId}`));
8953
9076
  const accessUrl = errObj && errObj.request_access_url;
8954
- if (accessUrl) console.log(` Request access: ${import_chalk46.default.bold(String(accessUrl))}`);
8955
- console.log(import_chalk46.default.dim(" Or ask the producer to pre-approve you: `apiblaze preapprove <your-email> --tenant <tenant>`."));
9077
+ if (accessUrl) console.log(` Request access: ${import_chalk47.default.bold(String(accessUrl))}`);
9078
+ console.log(import_chalk47.default.dim(" Or ask the producer to pre-approve you: `apiblaze preapprove <your-email> --tenant <tenant>`."));
8956
9079
  return;
8957
9080
  }
8958
9081
  if (code === "user_frozen") {
8959
- console.log(import_chalk46.default.red(` ${msg || "Your access to this API has been frozen by the producer."}`));
9082
+ console.log(import_chalk47.default.red(` ${msg || "Your access to this API has been frozen by the producer."}`));
8960
9083
  return;
8961
9084
  }
8962
9085
  const oauthWanted = /oauth token required|authorization: bearer/i.test(msg);
8963
9086
  const keyWanted = /api key required|x-api-key/i.test(msg);
8964
9087
  if (oauthWanted && !p.consumerAuth) {
8965
9088
  if (p.teamId && p.tenant && loadCredentials()) {
8966
- console.log(import_chalk46.default.dim(" This proxy signs consumers in with OAuth \u2014 starting the login\u2026"));
9089
+ console.log(import_chalk47.default.dim(" This proxy signs consumers in with OAuth \u2014 starting the login\u2026"));
8967
9090
  try {
8968
9091
  await ensureConsumerLogin(p.teamId, p.tenant, p.version);
8969
9092
  p.consumerAuth = true;
@@ -8972,17 +9095,17 @@ async function replTurn(p, messages, userText) {
8972
9095
  spinner.start("retrying\u2026");
8973
9096
  continue;
8974
9097
  } catch (err) {
8975
- console.log(import_chalk46.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9098
+ console.log(import_chalk47.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
8976
9099
  return;
8977
9100
  }
8978
9101
  }
8979
- console.log(import_chalk46.default.red(" This proxy signs consumers in with OAuth (a login), not an API key."));
8980
- console.log(import_chalk46.default.dim(" Sign in with: `apiblaze consumer login --tenant <tenant> --client <app-client-id>`, then re-run apichat."));
9102
+ console.log(import_chalk47.default.red(" This proxy signs consumers in with OAuth (a login), not an API key."));
9103
+ console.log(import_chalk47.default.dim(" Sign in with: `apiblaze consumer login --tenant <tenant> --client <app-client-id>`, then re-run apichat."));
8981
9104
  return;
8982
9105
  }
8983
9106
  if (keyWanted) {
8984
9107
  if (tty) {
8985
- console.log(import_chalk46.default.yellow(` ${msg || "This API requires an API key."}`));
9108
+ console.log(import_chalk47.default.yellow(` ${msg || "This API requires an API key."}`));
8986
9109
  const { default: inquirer3 } = await import("inquirer");
8987
9110
  const { key } = await inquirer3.prompt([{ type: "password", name: "key", mask: "*", message: "API key for this proxy:" }]);
8988
9111
  if (typeof key === "string" && key.trim()) {
@@ -8993,8 +9116,8 @@ async function replTurn(p, messages, userText) {
8993
9116
  continue;
8994
9117
  }
8995
9118
  }
8996
- console.log(import_chalk46.default.red(` ${msg || "This API requires an API key."}`));
8997
- console.log(import_chalk46.default.dim(" Re-run with --apikey <key> (mint one from the producer's site or dev portal)."));
9119
+ console.log(import_chalk47.default.red(` ${msg || "This API requires an API key."}`));
9120
+ console.log(import_chalk47.default.dim(" Re-run with --apikey <key> (mint one from the producer's site or dev portal)."));
8998
9121
  return;
8999
9122
  }
9000
9123
  if (res && (res.status === 402 || res.status === 403)) {
@@ -9002,16 +9125,16 @@ async function replTurn(p, messages, userText) {
9002
9125
  return;
9003
9126
  }
9004
9127
  if (res && res.status === 401) {
9005
- console.log(import_chalk46.default.red(` The proxy rejected the request (401)${msg ? `: ${msg}` : "."}`));
9006
- console.log(import_chalk46.default.dim(p.consumerAuth ? " Sent your consumer OAuth token. Run `apiblaze consumer login` again." : " Sent an API key. Pass a different one with --apikey <key>."));
9128
+ console.log(import_chalk47.default.red(` The proxy rejected the request (401)${msg ? `: ${msg}` : "."}`));
9129
+ console.log(import_chalk47.default.dim(p.consumerAuth ? " Sent your consumer OAuth token. Run `apiblaze consumer login` again." : " Sent an API key. Pass a different one with --apikey <key>."));
9007
9130
  return;
9008
9131
  }
9009
- console.log(import_chalk46.default.red(` Chat error: ${msg || (res ? `HTTP ${res.status}` : "request failed")}`));
9132
+ console.log(import_chalk47.default.red(` Chat error: ${msg || (res ? `HTTP ${res.status}` : "request failed")}`));
9010
9133
  return;
9011
9134
  }
9012
9135
  if (!res || !res.body || !(res.headers.get("content-type") ?? "").includes("text/event-stream")) {
9013
9136
  spinner.stop();
9014
- console.log(import_chalk46.default.red(" Chat error: could not authenticate to this proxy after several attempts."));
9137
+ console.log(import_chalk47.default.red(" Chat error: could not authenticate to this proxy after several attempts."));
9015
9138
  return;
9016
9139
  }
9017
9140
  let spinnerLive = true;
@@ -9052,7 +9175,7 @@ async function replTurn(p, messages, userText) {
9052
9175
  const name = String(ev.toolName ?? "tool");
9053
9176
  parts.push({ type: `tool-${name}`, toolCallId: String(ev.toolCallId ?? ""), state: "input-streaming" });
9054
9177
  toolMeta.set(String(ev.toolCallId ?? ""), { name, startedAt: Date.now(), partIdx: parts.length - 1 });
9055
- console.log(` ${import_chalk46.default.cyan("\u2699")} ${import_chalk46.default.cyan(name)}${import_chalk46.default.dim("\u2026")}`);
9178
+ console.log(` ${import_chalk47.default.cyan("\u2699")} ${import_chalk47.default.cyan(name)}${import_chalk47.default.dim("\u2026")}`);
9056
9179
  break;
9057
9180
  }
9058
9181
  case "tool-input-available": {
@@ -9064,9 +9187,9 @@ async function replTurn(p, messages, userText) {
9064
9187
  Object.assign(parts[meta.partIdx], { state: "input-available", input });
9065
9188
  }
9066
9189
  if (isVerbose()) {
9067
- console.log(import_chalk46.default.dim(` args ${JSON.stringify(input)}`));
9190
+ console.log(import_chalk47.default.dim(` args ${JSON.stringify(input)}`));
9068
9191
  const hint = credHint();
9069
- if (hint) console.log(import_chalk46.default.dim(` auth ${hint}`) + (revealAuth ? "" : import_chalk46.default.yellow(" \u2190 /showauth reveals")));
9192
+ if (hint) console.log(import_chalk47.default.dim(` auth ${hint}`) + (revealAuth ? "" : import_chalk47.default.yellow(" \u2190 /showauth reveals")));
9070
9193
  }
9071
9194
  break;
9072
9195
  }
@@ -9077,8 +9200,8 @@ async function replTurn(p, messages, userText) {
9077
9200
  const meta = toolMeta.get(id);
9078
9201
  const ok = ev.type === "tool-output-available";
9079
9202
  const ms = meta ? Date.now() - meta.startedAt : void 0;
9080
- const mark = ok ? import_chalk46.default.green("\u2713") : import_chalk46.default.red("\u2717");
9081
- console.log(` ${mark} ${import_chalk46.default.cyan(meta?.name ?? "tool")} ${import_chalk46.default.dim(`(${ok ? "ok" : "error"}${ms != null ? `, ${ms}ms` : ""})`)}`);
9203
+ const mark = ok ? import_chalk47.default.green("\u2713") : import_chalk47.default.red("\u2717");
9204
+ console.log(` ${mark} ${import_chalk47.default.cyan(meta?.name ?? "tool")} ${import_chalk47.default.dim(`(${ok ? "ok" : "error"}${ms != null ? `, ${ms}ms` : ""})`)}`);
9082
9205
  const detail = ok ? String(ev.output ?? "") : String(ev.errorText ?? "Tool call failed.");
9083
9206
  if (meta) {
9084
9207
  Object.assign(parts[meta.partIdx], ok ? { state: "output-available", output: detail } : { state: "output-error", errorText: detail });
@@ -9093,9 +9216,9 @@ async function replTurn(p, messages, userText) {
9093
9216
  })();
9094
9217
  const lines = pretty.split("\n");
9095
9218
  const cap = ok ? 12 : 24;
9096
- console.log(import_chalk46.default.dim(" response:"));
9097
- for (const line of lines.slice(0, cap)) console.log(import_chalk46.default.dim(` ${line}`));
9098
- if (lines.length > cap) console.log(import_chalk46.default.dim(` \u2026${lines.length - cap} more lines`));
9219
+ console.log(import_chalk47.default.dim(" response:"));
9220
+ for (const line of lines.slice(0, cap)) console.log(import_chalk47.default.dim(` ${line}`));
9221
+ if (lines.length > cap) console.log(import_chalk47.default.dim(` \u2026${lines.length - cap} more lines`));
9099
9222
  }
9100
9223
  break;
9101
9224
  }
@@ -9104,7 +9227,7 @@ async function replTurn(p, messages, userText) {
9104
9227
  parts.push({ type: "text", text: "" });
9105
9228
  openTextIdx = parts.length - 1;
9106
9229
  if (!assistantOpen) {
9107
- process.stdout.write("\n" + import_chalk46.default.green("assistant \u203A "));
9230
+ process.stdout.write("\n" + import_chalk47.default.green("assistant \u203A "));
9108
9231
  assistantOpen = true;
9109
9232
  }
9110
9233
  break;
@@ -9135,12 +9258,12 @@ async function replTurn(p, messages, userText) {
9135
9258
  });
9136
9259
  } catch (err) {
9137
9260
  stopSpinner();
9138
- console.log(import_chalk46.default.red(` Stream error: ${err instanceof Error ? err.message : String(err)}`));
9261
+ console.log(import_chalk47.default.red(` Stream error: ${err instanceof Error ? err.message : String(err)}`));
9139
9262
  }
9140
9263
  stopSpinner();
9141
9264
  if (assistantOpen) process.stdout.write("\n\n");
9142
9265
  if (parts.length) messages.push({ id: messageId, role: "assistant", parts });
9143
- if (errorText) console.log(import_chalk46.default.red(` ${errorText}`));
9266
+ if (errorText) console.log(import_chalk47.default.red(` ${errorText}`));
9144
9267
  if (upsell) {
9145
9268
  renderUpsell(p, upsell, { messageAlreadyShown: true });
9146
9269
  }
@@ -9152,39 +9275,39 @@ async function replTurn(p, messages, userText) {
9152
9275
  function renderUpsell(p, upsell, opts = {}) {
9153
9276
  const loggedIn = !!loadCredentials();
9154
9277
  if (upsell.reason === "CAPPED" && !loggedIn) {
9155
- console.log("\n" + import_chalk46.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
9156
- console.log(import_chalk46.default.dim(" (or `/login` right here \u2014 your chat is preserved \u2014 or `apiblaze llm set-key` for your own model key.)"));
9278
+ console.log("\n" + import_chalk47.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
9279
+ console.log(import_chalk47.default.dim(" (or `/login` right here \u2014 your chat is preserved \u2014 or `apiblaze llm set-key` for your own model key.)"));
9157
9280
  console.log();
9158
9281
  return;
9159
9282
  }
9160
9283
  if (!opts.messageAlreadyShown) {
9161
- console.log("\n" + import_chalk46.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
9284
+ console.log("\n" + import_chalk47.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
9162
9285
  }
9163
9286
  if (upsell.reason === "INSUFFICIENT" || upsell.reason === "BREAKER" || upsell.reason === "CAPPED" || upsell.reason === "QUOTA" || upsell.reason === "PROXY_CAP" || upsell.reason === "PAUSED" || upsell.reason === "BYO_REQUIRED") {
9164
9287
  if (!loggedIn) {
9165
- console.log(import_chalk46.default.dim(" Options: `/login` for more free chats and requests, or `apiblaze llm set-key` to bring your own model key."));
9288
+ console.log(import_chalk47.default.dim(" Options: `/login` for more free chats and requests, or `apiblaze llm set-key` to bring your own model key."));
9166
9289
  } else {
9167
- console.log(import_chalk46.default.dim(" Options: top up your wallet, or `apiblaze llm set-key` to bring your own model key (bypasses platform limits)."));
9290
+ console.log(import_chalk47.default.dim(" Options: top up your wallet, or `apiblaze llm set-key` to bring your own model key (bypasses platform limits)."));
9168
9291
  }
9169
9292
  } else if (upsell.reason === "INFLIGHT") {
9170
- console.log(import_chalk46.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
9293
+ console.log(import_chalk47.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
9171
9294
  }
9172
9295
  console.log();
9173
9296
  }
9174
- var apichatsPath = () => path6.join(getApiblazeDir(), "apichats.json");
9297
+ var apichatsPath = () => path7.join(getApiblazeDir(), "apichats.json");
9175
9298
  function loadApichats() {
9176
9299
  try {
9177
- const list = JSON.parse(fs10.readFileSync(apichatsPath(), "utf-8"));
9300
+ const list = JSON.parse(fs11.readFileSync(apichatsPath(), "utf-8"));
9178
9301
  return Array.isArray(list) ? list : [];
9179
9302
  } catch {
9180
9303
  return [];
9181
9304
  }
9182
9305
  }
9183
9306
  function writeApichats(list) {
9184
- fs10.mkdirSync(getApiblazeDir(), { recursive: true });
9185
- fs10.writeFileSync(apichatsPath(), JSON.stringify(list, null, 2), "utf-8");
9307
+ fs11.mkdirSync(getApiblazeDir(), { recursive: true });
9308
+ fs11.writeFileSync(apichatsPath(), JSON.stringify(list, null, 2), "utf-8");
9186
9309
  try {
9187
- fs10.chmodSync(apichatsPath(), 384);
9310
+ fs11.chmodSync(apichatsPath(), 384);
9188
9311
  } catch {
9189
9312
  }
9190
9313
  }
@@ -9290,8 +9413,8 @@ async function openDirectProject(projectId, opts) {
9290
9413
  else p.consumerAuth = true;
9291
9414
  }
9292
9415
  }
9293
- console.log(` ${import_chalk46.default.dim("Proxy:")} ${import_chalk46.default.bold(p.proxyUrl)}`);
9294
- if (p.endUserId) console.log(` ${import_chalk46.default.dim("Acting as:")} ${import_chalk46.default.bold(p.endUserId)}`);
9416
+ console.log(` ${import_chalk47.default.dim("Proxy:")} ${import_chalk47.default.bold(p.proxyUrl)}`);
9417
+ if (p.endUserId) console.log(` ${import_chalk47.default.dim("Acting as:")} ${import_chalk47.default.bold(p.endUserId)}`);
9295
9418
  upsertApichat({
9296
9419
  name: projectId,
9297
9420
  target: p.proxyUrl,
@@ -9321,9 +9444,9 @@ async function openServerProxy(project) {
9321
9444
  let consumerAuth = false;
9322
9445
  if (acceptsApiKey) {
9323
9446
  if (!dpKey) {
9324
- console.log(import_chalk46.default.dim(` Minting an API key for tenant ${import_chalk46.default.bold(tenant2)} to query project ${import_chalk46.default.bold(project.projectName)}\u2026`));
9447
+ console.log(import_chalk47.default.dim(` Minting an API key for tenant ${import_chalk47.default.bold(tenant2)} to query project ${import_chalk47.default.bold(project.projectName)}\u2026`));
9325
9448
  dpKey = await mintDurableProxyKey(project.teamId, tenant2);
9326
- console.log(` ${import_chalk46.default.green("\u2714")} API key: ${import_chalk46.default.dim(maskKey(dpKey))}`);
9449
+ console.log(` ${import_chalk47.default.green("\u2714")} API key: ${import_chalk47.default.dim(maskKey(dpKey))}`);
9327
9450
  }
9328
9451
  } else {
9329
9452
  consumerAuth = true;
@@ -9352,9 +9475,9 @@ async function openServerProxy(project) {
9352
9475
  const spec2 = raw && (raw.spec ?? raw);
9353
9476
  spinner.stop();
9354
9477
  if (!spec2 || !(spec2.paths || spec2.openapi)) {
9355
- console.log(import_chalk46.default.yellow(" This proxy has no OpenAPI spec yet \u2014 chat will have no tools. Build one with `apiblaze agent openapi`."));
9478
+ console.log(import_chalk47.default.yellow(" This proxy has no OpenAPI spec yet \u2014 chat will have no tools. Build one with `apiblaze agent openapi`."));
9356
9479
  } else {
9357
- console.log(import_chalk46.default.dim(" Using the proxy's existing MCP catalogue (`apiblaze mcp` to rebuild it)."));
9480
+ console.log(import_chalk47.default.dim(" Using the proxy's existing MCP catalogue (`apiblaze mcp` to rebuild it)."));
9358
9481
  }
9359
9482
  } catch (err) {
9360
9483
  spinner.fail("Could not open the proxy.");
@@ -9386,15 +9509,15 @@ function discoverLocalSpecs() {
9386
9509
  const found = [];
9387
9510
  for (const n of known) {
9388
9511
  try {
9389
- if (fs10.statSync(path6.join(cwd, n)).isFile()) found.push(n);
9512
+ if (fs11.statSync(path7.join(cwd, n)).isFile()) found.push(n);
9390
9513
  } catch {
9391
9514
  }
9392
9515
  }
9393
9516
  try {
9394
- const files = fs10.readdirSync(cwd).filter((f) => /\.(ya?ml|json)$/i.test(f) && !found.includes(f));
9517
+ const files = fs11.readdirSync(cwd).filter((f) => /\.(ya?ml|json)$/i.test(f) && !found.includes(f));
9395
9518
  for (const f of files.slice(0, 60)) {
9396
9519
  try {
9397
- const head = fs10.readFileSync(path6.join(cwd, f), "utf-8").slice(0, 4e3);
9520
+ const head = fs11.readFileSync(path7.join(cwd, f), "utf-8").slice(0, 4e3);
9398
9521
  if (/["']?openapi["']?\s*:/i.test(head) || /["']?swagger["']?\s*:/i.test(head) || /^\s*paths\s*:/im.test(head) || /"paths"\s*:/.test(head)) {
9399
9522
  found.push(f);
9400
9523
  }
@@ -9410,7 +9533,7 @@ async function noArgsMenu(opts) {
9410
9533
  const me = loadCredentials()?.apiblazeUserId;
9411
9534
  const saved = loadApichats().filter((a) => a.anon ? true : a.ownerUserId !== void 0 && a.ownerUserId === me);
9412
9535
  const choices = saved.map((a) => ({
9413
- name: `Chat with ${import_chalk46.default.bold(a.name)} ${import_chalk46.default.dim(`(${a.target})${a.messages && a.messages.length ? ` \xB7 ${a.messages.length} msgs` : ""}`)}`,
9536
+ name: `Chat with ${import_chalk47.default.bold(a.name)} ${import_chalk47.default.dim(`(${a.target})${a.messages && a.messages.length ? ` \xB7 ${a.messages.length} msgs` : ""}`)}`,
9414
9537
  value: { type: "existing", a }
9415
9538
  }));
9416
9539
  const creds = loadCredentials();
@@ -9420,14 +9543,14 @@ async function noArgsMenu(opts) {
9420
9543
  const proxies = (await getProjects(creds.teamId)).filter((pr) => !savedIds.has(pr.projectId));
9421
9544
  for (const pr of proxies) {
9422
9545
  choices.push({
9423
- name: `Chat with ${import_chalk46.default.bold(pr.projectName)} ${import_chalk46.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
9546
+ name: `Chat with ${import_chalk47.default.bold(pr.projectName)} ${import_chalk47.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
9424
9547
  value: { type: "server", project: pr }
9425
9548
  });
9426
9549
  }
9427
9550
  } catch {
9428
9551
  }
9429
9552
  }
9430
- choices.push({ name: import_chalk46.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
9553
+ choices.push({ name: import_chalk47.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
9431
9554
  const { pick: pick2 } = await inquirer3.prompt([
9432
9555
  { type: "list", name: "pick", message: "What would you like to do?", choices }
9433
9556
  ]);
@@ -9530,36 +9653,36 @@ async function noArgsMenu(opts) {
9530
9653
  async function runRepl(p, initialMessages) {
9531
9654
  const { default: inquirer3 } = await import("inquirer");
9532
9655
  const messages = (initialMessages ?? []).filter((m) => Array.isArray(m.parts));
9533
- console.log("\n" + import_chalk46.default.cyan.bold("Chat with your API") + import_chalk46.default.dim(` \xB7 ${p.mcpHost}`));
9534
- if (messages.length) console.log(import_chalk46.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
9656
+ console.log("\n" + import_chalk47.default.cyan.bold("Chat with your API") + import_chalk47.default.dim(` \xB7 ${p.mcpHost}`));
9657
+ if (messages.length) console.log(import_chalk47.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
9535
9658
  const llm2 = loadLlmConfig();
9536
9659
  console.log(
9537
- import_chalk46.default.dim(
9660
+ import_chalk47.default.dim(
9538
9661
  llm2 ? `Using your local ${llm2.provider} key for the model. Type a question, or /exit. /login /claim manage your workspace.` : "Ask a question in plain English. /exit to quit \xB7 /login for more free chats \xB7 /claim to keep this workspace \xB7 `apiblaze llm set-key` for BYO models."
9539
9662
  )
9540
9663
  );
9541
9664
  for (; ; ) {
9542
- const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk46.default.green("you \u203A") }]);
9665
+ const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk47.default.green("you \u203A") }]);
9543
9666
  const text = (input ?? "").trim();
9544
9667
  if (!text) continue;
9545
9668
  if (["/exit", "/quit", "exit", "quit", ":q"].includes(text.toLowerCase())) break;
9546
9669
  if (text === "/login") {
9547
9670
  try {
9548
9671
  await runLogin();
9549
- console.log(import_chalk46.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
9672
+ console.log(import_chalk47.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
9550
9673
  } catch (err) {
9551
- console.log(import_chalk46.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9674
+ console.log(import_chalk47.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9552
9675
  }
9553
9676
  continue;
9554
9677
  }
9555
9678
  if (text === "/claim") {
9556
9679
  const justLoggedIn = !loadCredentials();
9557
9680
  if (justLoggedIn) {
9558
- console.log(import_chalk46.default.dim(" Logging in to claim your workspace\u2026"));
9681
+ console.log(import_chalk47.default.dim(" Logging in to claim your workspace\u2026"));
9559
9682
  try {
9560
9683
  await runLogin();
9561
9684
  } catch (err) {
9562
- console.log(import_chalk46.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9685
+ console.log(import_chalk47.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9563
9686
  continue;
9564
9687
  }
9565
9688
  if (!loadCredentials()) continue;
@@ -9570,57 +9693,123 @@ async function runRepl(p, initialMessages) {
9570
9693
  p.mcpHost = p.mcpHost.replace(".mcp.tryabz.run", ".mcp.abz.run");
9571
9694
  p.anon = false;
9572
9695
  claimApichat(p, loadCredentials()?.apiblazeUserId);
9573
- console.log(import_chalk46.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
9696
+ console.log(import_chalk47.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
9574
9697
  }
9575
9698
  } catch (err) {
9576
- console.log(import_chalk46.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
9699
+ console.log(import_chalk47.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
9577
9700
  }
9578
9701
  continue;
9579
9702
  }
9580
9703
  if (text === "/showauth") {
9581
9704
  revealAuth = !revealAuth;
9582
- console.log(import_chalk46.default.dim(revealAuth ? " The real API key will be shown in the next call's curl. /showauth again to re-mask." : " API key re-masked."));
9705
+ console.log(import_chalk47.default.dim(revealAuth ? " The real API key will be shown in the next call's curl. /showauth again to re-mask." : " API key re-masked."));
9583
9706
  continue;
9584
9707
  }
9585
9708
  if (text.startsWith("/")) {
9586
- console.log(import_chalk46.default.dim(" Commands: /login /claim /showauth /exit"));
9709
+ console.log(import_chalk47.default.dim(" Commands: /login /claim /showauth /exit"));
9587
9710
  continue;
9588
9711
  }
9589
9712
  await replTurn(p, messages, text);
9590
9713
  saveTranscript(p, messages);
9591
9714
  }
9592
- console.log(import_chalk46.default.dim("\nBye."));
9715
+ console.log(import_chalk47.default.dim("\nBye."));
9716
+ }
9717
+ function rememberCliOffer(projectId, cli, state) {
9718
+ const list = loadApichats();
9719
+ const i = list.findIndex((a) => a.projectId === projectId);
9720
+ if (i < 0) return;
9721
+ list[i].cliOffer = { ...list[i].cliOffer ?? {}, [cli]: state };
9722
+ list[i].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9723
+ writeApichats(list);
9724
+ }
9725
+ async function maybeInstallExternalCli(p, opts) {
9726
+ const spec2 = {
9727
+ name: p.projectId,
9728
+ url: `https://${p.mcpHost}/${p.version}/${p.environment}`,
9729
+ // consumerAuth means the door is a login — install bare, the CLI signs in.
9730
+ apiKey: p.consumerAuth ? void 0 : p.dpKey,
9731
+ projectLabel: p.projectId
9732
+ };
9733
+ const clis = detectExternalClis();
9734
+ if (opts.installMcp) {
9735
+ const want = opts.installMcp.toLowerCase();
9736
+ if (want !== "claude" && want !== "codex") fail4(`--install-mcp takes "claude" or "codex", not "${opts.installMcp}".`);
9737
+ const cli = clis.find((c) => c.kind === want);
9738
+ if (!cli) fail4(
9739
+ `${want === "claude" ? "Claude" : "Codex"} CLI not found on this machine.`,
9740
+ want === "claude" ? "Install it: npm install -g @anthropic-ai/claude-code" : "Install it: npm install -g @openai/codex"
9741
+ );
9742
+ const question2 = opts.prompt ?? (process.stdin.isTTY ? await askApiQuestion() : void 0);
9743
+ const ran2 = installAndDemo(cli, spec2, question2);
9744
+ if (ran2) rememberCliOffer(p.projectId, cli.kind, "installed");
9745
+ return ran2;
9746
+ }
9747
+ if (!process.stdin.isTTY || clis.length === 0) return false;
9748
+ const offer = loadApichats().find((a) => a.projectId === p.projectId)?.cliOffer ?? {};
9749
+ const fresh = clis.filter((c) => !offer[c.kind]);
9750
+ if (fresh.length === 0) return false;
9751
+ const { default: inquirer3 } = await import("inquirer");
9752
+ const names = fresh.map((c) => c.label).join(" and ");
9753
+ const { pick: pick2 } = await inquirer3.prompt([{
9754
+ type: "list",
9755
+ name: "pick",
9756
+ message: `I see ${names} ${fresh.length > 1 ? "are" : "is"} installed on this computer. Add the MCP for this proxy so you can chat with your API from there directly?`,
9757
+ choices: [
9758
+ ...fresh.map((c) => ({ name: `Yes \u2014 add it to ${c.label}`, value: c })),
9759
+ { name: "No \u2014 chat here instead", value: "no" }
9760
+ ]
9761
+ }]);
9762
+ if (pick2 === "no") {
9763
+ for (const c of fresh) rememberCliOffer(p.projectId, c.kind, "declined");
9764
+ return false;
9765
+ }
9766
+ const question = opts.prompt ?? await askApiQuestion();
9767
+ const ran = installAndDemo(pick2, spec2, question);
9768
+ if (ran) rememberCliOffer(p.projectId, pick2.kind, "installed");
9769
+ return ran;
9770
+ }
9771
+ async function askApiQuestion() {
9772
+ const { default: inquirer3 } = await import("inquirer");
9773
+ const { q } = await inquirer3.prompt([{
9774
+ type: "input",
9775
+ name: "q",
9776
+ message: "What question do you have for this API?"
9777
+ }]);
9778
+ const t = (q ?? "").trim();
9779
+ return t || void 0;
9593
9780
  }
9594
9781
  async function runApichat(opts) {
9595
9782
  setVerbose(opts.verbose !== false);
9596
- console.log(import_chalk46.default.bold("\napichat \u2014 turn any API into a chat\n"));
9783
+ console.log(import_chalk47.default.bold("\napichat \u2014 turn any API into a chat\n"));
9597
9784
  if (opts.target && !opts.openapispec) {
9598
9785
  const { classifyTargetInput: classifyTargetInput2 } = await Promise.resolve().then(() => (init_spec_or_target(), spec_or_target_exports));
9599
9786
  const c = await classifyTargetInput2(opts.target, fail4);
9600
9787
  if (c.kind === "spec") {
9601
- console.log(import_chalk46.default.dim(` --target is an OpenAPI document (${c.source}) \u2014 using it as the spec.`));
9788
+ console.log(import_chalk47.default.dim(` --target is an OpenAPI document (${c.source}) \u2014 using it as the spec.`));
9602
9789
  opts.openapispec = opts.target;
9603
9790
  opts.target = void 0;
9604
9791
  }
9605
9792
  }
9606
9793
  if (opts.project) {
9607
9794
  const opened = await openDirectProject(opts.project, opts);
9795
+ if (await maybeInstallExternalCli(opened.p, opts)) return;
9608
9796
  await runRepl(opened.p, opened.messages);
9609
9797
  return;
9610
9798
  }
9611
9799
  if (!opts.openapispec && !opts.target) {
9612
9800
  if (!process.stdin.isTTY) {
9613
- fail4("No spec source. Pass --openapispec <file|url> or --target <url>.", GENERATOR_HINT);
9801
+ fail4("No spec source. Pass --target <server-url | openapi-file | openapi-url>.", GENERATOR_HINT);
9614
9802
  }
9615
9803
  const resumed = await noArgsMenu(opts);
9616
9804
  if (resumed) {
9805
+ if (await maybeInstallExternalCli(resumed.p, opts)) return;
9617
9806
  await runRepl(resumed.p, resumed.messages);
9618
9807
  return;
9619
9808
  }
9620
9809
  }
9621
9810
  const { spec: spec2, sourceUrl } = await loadSpec(opts);
9622
9811
  const target = resolveTarget(spec2, opts, sourceUrl);
9623
- console.log(` ${import_chalk46.default.dim("Target:")} ${import_chalk46.default.bold(target)}`);
9812
+ console.log(` ${import_chalk47.default.dim("Target:")} ${import_chalk47.default.bold(target)}`);
9624
9813
  const auth = await resolveTargetAuth(spec2, opts);
9625
9814
  if (auth && !process.stdin.isTTY && !opts.targetAuthEnv) {
9626
9815
  fail4(
@@ -9629,7 +9818,7 @@ async function runApichat(opts) {
9629
9818
  );
9630
9819
  }
9631
9820
  const p = await provision(spec2, target, opts);
9632
- console.log(` ${import_chalk46.default.dim("Proxy: ")} ${import_chalk46.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
9821
+ console.log(` ${import_chalk47.default.dim("Proxy: ")} ${import_chalk47.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
9633
9822
  upsertApichat({
9634
9823
  name: p.projectId,
9635
9824
  target,
@@ -9649,30 +9838,31 @@ async function runApichat(opts) {
9649
9838
  const secret = await captureTargetSecret(auth, opts);
9650
9839
  if (secret) await writeTargetAuth(p, auth, secret);
9651
9840
  } else {
9652
- console.log(import_chalk46.default.dim(" Target auth: none required."));
9841
+ console.log(import_chalk47.default.dim(" Target auth: none required."));
9653
9842
  }
9654
9843
  const specText = JSON.stringify(spec2);
9655
9844
  await uploadSpec(p, specText, opts);
9656
9845
  const mcpUrl = await publishMcp(p, spec2);
9657
9846
  console.log();
9658
- if (p.proxyUrl) console.log(` ${import_chalk46.default.green("\u2713")} proxy ${import_chalk46.default.bold(p.proxyUrl)}`);
9847
+ if (p.proxyUrl) console.log(` ${import_chalk47.default.green("\u2713")} proxy ${import_chalk47.default.bold(p.proxyUrl)}`);
9659
9848
  if (mcpUrl) {
9660
- console.log(` ${import_chalk46.default.green("\u2713")} mcp ${import_chalk46.default.bold(mcpUrl)}`);
9849
+ console.log(` ${import_chalk47.default.green("\u2713")} mcp ${import_chalk47.default.bold(mcpUrl)}`);
9661
9850
  if (p.access === "invite") {
9662
- console.log(import_chalk46.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: invite \u2014 only you + emails you pre-approve"));
9663
- console.log(import_chalk46.default.dim(` Let others in: apiblaze preapprove someone@company.com${p.tenant ? ` --tenant ${p.tenant}` : ""} (or re-run with --access open)`));
9851
+ console.log(import_chalk47.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: invite \u2014 only you + emails you pre-approve"));
9852
+ console.log(import_chalk47.default.dim(` Let others in: apiblaze preapprove someone@company.com${p.tenant ? ` --tenant ${p.tenant}` : ""} (or re-run with --access open)`));
9664
9853
  } else {
9665
- console.log(import_chalk46.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: open \u2014 anyone who signs in can call this API"));
9854
+ console.log(import_chalk47.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: open \u2014 anyone who signs in can call this API"));
9666
9855
  }
9667
9856
  }
9668
9857
  if (p.anon) {
9669
- console.log(import_chalk46.default.dim("\n Anonymous workspace \u2014 /claim inside the chat to log in and keep it beyond 30 days."));
9858
+ console.log(import_chalk47.default.dim("\n Anonymous workspace \u2014 /claim inside the chat to log in and keep it beyond 30 days."));
9670
9859
  }
9860
+ if (await maybeInstallExternalCli(p, opts)) return;
9671
9861
  await runRepl(p);
9672
9862
  }
9673
9863
 
9674
9864
  // src/commands/consumer.ts
9675
- var import_chalk47 = __toESM(require("chalk"));
9865
+ var import_chalk48 = __toESM(require("chalk"));
9676
9866
  var import_ora24 = __toESM(require("ora"));
9677
9867
  init_admin();
9678
9868
  init_resolve();
@@ -9694,7 +9884,7 @@ async function consumerFetch(creds, suffix, init) {
9694
9884
  function requireConsumer2() {
9695
9885
  const c = loadConsumer();
9696
9886
  if (!c) {
9697
- console.error(import_chalk47.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
9887
+ console.error(import_chalk48.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
9698
9888
  process.exit(1);
9699
9889
  }
9700
9890
  return c;
@@ -9705,7 +9895,7 @@ async function runConsumerLogin(opts) {
9705
9895
  let clientId = opts.client;
9706
9896
  if (clientId) {
9707
9897
  if (!tenant2) {
9708
- console.error(import_chalk47.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
9898
+ console.error(import_chalk48.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
9709
9899
  process.exit(1);
9710
9900
  }
9711
9901
  } else {
@@ -9723,18 +9913,18 @@ async function runConsumerLogin(opts) {
9723
9913
  const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
9724
9914
  const pick2 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
9725
9915
  if (!pick2) {
9726
- console.error(import_chalk47.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
9916
+ console.error(import_chalk48.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
9727
9917
  process.exit(1);
9728
9918
  }
9729
9919
  clientId = pick2.client_id ?? pick2.clientId;
9730
9920
  }
9731
- console.log(`${import_chalk47.default.cyan("\u2192")} Logging in to ${import_chalk47.default.bold(tenant2)} as a consumer...`);
9921
+ console.log(`${import_chalk48.default.cyan("\u2192")} Logging in to ${import_chalk48.default.bold(tenant2)} as a consumer...`);
9732
9922
  const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
9733
9923
  console.log(`
9734
- Open: ${import_chalk47.default.underline(verificationUri)}`);
9735
- console.log(` Code: ${import_chalk47.default.bold(userCode)}
9924
+ Open: ${import_chalk48.default.underline(verificationUri)}`);
9925
+ console.log(` Code: ${import_chalk48.default.bold(userCode)}
9736
9926
  `);
9737
- console.log(import_chalk47.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
9927
+ console.log(import_chalk48.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
9738
9928
  });
9739
9929
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
9740
9930
  const creds = {
@@ -9749,7 +9939,7 @@ async function runConsumerLogin(opts) {
9749
9939
  obtainedAt: Date.now()
9750
9940
  };
9751
9941
  saveConsumer(creds);
9752
- console.log(import_chalk47.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
9942
+ console.log(import_chalk48.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
9753
9943
  }
9754
9944
  async function runConsumerTokens(opts) {
9755
9945
  const creds = requireConsumer2();
@@ -9762,18 +9952,18 @@ async function runConsumerTokens(opts) {
9762
9952
  console.log(JSON.stringify({ tenant: fresh.tenant, access_token: fresh.accessToken, refresh_token: fresh.refreshToken, id_token: fresh.idToken, expires_at: new Date(fresh.expiresAt).toISOString() }, null, 2));
9763
9953
  return;
9764
9954
  }
9765
- console.log(`${import_chalk47.default.cyan("Consumer")} ${import_chalk47.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk47.default.bold(fresh.tenant)}
9955
+ console.log(`${import_chalk48.default.cyan("Consumer")} ${import_chalk48.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk48.default.bold(fresh.tenant)}
9766
9956
  `);
9767
- console.log(`${import_chalk47.default.bold("access_token")} ${import_chalk47.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
9957
+ console.log(`${import_chalk48.default.bold("access_token")} ${import_chalk48.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
9768
9958
  ${fresh.accessToken}
9769
9959
  `);
9770
- if (fresh.idToken) console.log(`${import_chalk47.default.bold("id_token")} ${import_chalk47.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
9960
+ if (fresh.idToken) console.log(`${import_chalk48.default.bold("id_token")} ${import_chalk48.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
9771
9961
  ${fresh.idToken}
9772
9962
  `);
9773
- if (fresh.refreshToken) console.log(`${import_chalk47.default.bold("refresh_token")}
9963
+ if (fresh.refreshToken) console.log(`${import_chalk48.default.bold("refresh_token")}
9774
9964
  ${fresh.refreshToken}
9775
9965
  `);
9776
- console.log(import_chalk47.default.dim("These are your own tokens \u2014 keep them secret."));
9966
+ console.log(import_chalk48.default.dim("These are your own tokens \u2014 keep them secret."));
9777
9967
  }
9778
9968
  async function runConsumerApikeys(opts) {
9779
9969
  const creds = requireConsumer2();
@@ -9783,8 +9973,8 @@ async function runConsumerApikeys(opts) {
9783
9973
  const revealed = await consumerFetch(list.creds, "/apikeys/reveal").catch(() => ({ status: 0, data: null, creds: list.creds }));
9784
9974
  spinner.stop();
9785
9975
  if (list.status >= 400) {
9786
- console.error(import_chalk47.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
9787
- if (list.status === 401) console.error(import_chalk47.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
9976
+ console.error(import_chalk48.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
9977
+ if (list.status === 401) console.error(import_chalk48.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
9788
9978
  process.exit(1);
9789
9979
  }
9790
9980
  const keys = list.data?.keys ?? [];
@@ -9792,16 +9982,16 @@ async function runConsumerApikeys(opts) {
9792
9982
  if (opts.json) {
9793
9983
  console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
9794
9984
  } else if (!keys.length) {
9795
- console.log(import_chalk47.default.yellow("No API keys yet."));
9985
+ console.log(import_chalk48.default.yellow("No API keys yet."));
9796
9986
  } else {
9797
9987
  for (const k of keys) {
9798
9988
  const clear = revealMap[k.environment]?.key;
9799
- const shown = clear ? import_chalk47.default.green(clear) : import_chalk47.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
9800
- const exp = k.expires_at ? import_chalk47.default.dim(`exp ${k.expires_at}`) : import_chalk47.default.dim("no expiry");
9801
- console.log(` ${import_chalk47.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk47.default.dim(k.description ?? "")}`);
9989
+ const shown = clear ? import_chalk48.default.green(clear) : import_chalk48.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
9990
+ const exp = k.expires_at ? import_chalk48.default.dim(`exp ${k.expires_at}`) : import_chalk48.default.dim("no expiry");
9991
+ console.log(` ${import_chalk48.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk48.default.dim(k.description ?? "")}`);
9802
9992
  }
9803
9993
  if (Object.keys(revealMap).length === 0 && keys.some((k) => !k.expires_at)) {
9804
- console.log(import_chalk47.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
9994
+ console.log(import_chalk48.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
9805
9995
  }
9806
9996
  }
9807
9997
  if (opts.json) return;
@@ -9823,35 +10013,35 @@ async function runConsumerApikeys(opts) {
9823
10013
  }
9824
10014
  s2.succeed("Key created.");
9825
10015
  const key = created.data?.key ?? created.data?.fullKey;
9826
- if (key) console.log(` ${import_chalk47.default.green(key)} ${import_chalk47.default.dim("(shown once \u2014 store it now)")}`);
9827
- else console.log(import_chalk47.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
10016
+ if (key) console.log(` ${import_chalk48.default.green(key)} ${import_chalk48.default.dim("(shown once \u2014 store it now)")}`);
10017
+ else console.log(import_chalk48.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
9828
10018
  }
9829
10019
 
9830
10020
  // src/commands/sidecar.ts
9831
- var import_chalk48 = __toESM(require("chalk"));
10021
+ var import_chalk49 = __toESM(require("chalk"));
9832
10022
  var import_ora25 = __toESM(require("ora"));
9833
- var fs11 = __toESM(require("fs"));
9834
- var path7 = __toESM(require("path"));
10023
+ var fs12 = __toESM(require("fs"));
10024
+ var path8 = __toESM(require("path"));
9835
10025
  init_admin();
9836
10026
  init_resolve();
9837
10027
  init_auth();
9838
10028
  function detectNextProject(root) {
9839
- const hasConfig = ["next.config.js", "next.config.mjs", "next.config.ts"].some((f) => fs11.existsSync(path7.join(root, f)));
10029
+ const hasConfig = ["next.config.js", "next.config.mjs", "next.config.ts"].some((f) => fs12.existsSync(path8.join(root, f)));
9840
10030
  let hasDep = false;
9841
10031
  try {
9842
- const pkg = JSON.parse(fs11.readFileSync(path7.join(root, "package.json"), "utf8"));
10032
+ const pkg = JSON.parse(fs12.readFileSync(path8.join(root, "package.json"), "utf8"));
9843
10033
  hasDep = !!(pkg.dependencies?.next || pkg.devDependencies?.next);
9844
10034
  } catch {
9845
10035
  }
9846
- const appDir = fs11.existsSync(path7.join(root, "app")) || fs11.existsSync(path7.join(root, "src", "app"));
9847
- const pagesDir = fs11.existsSync(path7.join(root, "pages")) || fs11.existsSync(path7.join(root, "src", "pages"));
10036
+ const appDir = fs12.existsSync(path8.join(root, "app")) || fs12.existsSync(path8.join(root, "src", "app"));
10037
+ const pagesDir = fs12.existsSync(path8.join(root, "pages")) || fs12.existsSync(path8.join(root, "src", "pages"));
9848
10038
  return { found: hasConfig || hasDep || appDir || pagesDir, router: appDir ? "app" : pagesDir ? "pages" : null };
9849
10039
  }
9850
10040
  function upsertEnvLocal(root, token) {
9851
- const p = path7.join(root, ".env.local");
10041
+ const p = path8.join(root, ".env.local");
9852
10042
  let existing = "";
9853
10043
  try {
9854
- existing = fs11.readFileSync(p, "utf8");
10044
+ existing = fs12.readFileSync(p, "utf8");
9855
10045
  } catch {
9856
10046
  }
9857
10047
  const had = /^APIBLAZE_API_KEY=/m.test(existing) || /^APIBLAZE_TOKEN=/m.test(existing);
@@ -9866,15 +10056,15 @@ function upsertEnvLocal(root, token) {
9866
10056
  next = (next.endsWith("\n") ? next : next + "\n") + `APIBLAZE_SIDECAR_VERBOSE=true
9867
10057
  `;
9868
10058
  }
9869
- fs11.writeFileSync(p, next);
10059
+ fs12.writeFileSync(p, next);
9870
10060
  return had ? "rotated" : "created";
9871
10061
  }
9872
10062
  function installSidecarPackage(root) {
9873
- if (fs11.existsSync(path7.join(root, "node_modules", "apiblaze", "package.json"))) {
9874
- console.log(` ${import_chalk48.default.green("\u2713")} apiblaze package already installed`);
10063
+ if (fs12.existsSync(path8.join(root, "node_modules", "apiblaze", "package.json"))) {
10064
+ console.log(` ${import_chalk49.default.green("\u2713")} apiblaze package already installed`);
9875
10065
  return;
9876
10066
  }
9877
- const has = (f) => fs11.existsSync(path7.join(root, f));
10067
+ const has = (f) => fs12.existsSync(path8.join(root, f));
9878
10068
  const pm = has("bun.lockb") || has("bun.lock") ? { cmd: "bun", add: "add" } : has("pnpm-lock.yaml") ? { cmd: "pnpm", add: "add" } : has("yarn.lock") ? { cmd: "yarn", add: "add" } : { cmd: "npm", add: "install" };
9879
10069
  const spinner = (0, import_ora25.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
9880
10070
  try {
@@ -9882,12 +10072,12 @@ function installSidecarPackage(root) {
9882
10072
  execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
9883
10073
  spinner.succeed("Installed apiblaze (the sidecar runtime).");
9884
10074
  } catch {
9885
- spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk48.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk48.default.cyan("npm run dev")}.`);
10075
+ spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk49.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk49.default.cyan("npm run dev")}.`);
9886
10076
  }
9887
10077
  }
9888
10078
  function readEnvKey(root) {
9889
10079
  try {
9890
- const s = fs11.readFileSync(path7.join(root, ".env.local"), "utf8");
10080
+ const s = fs12.readFileSync(path8.join(root, ".env.local"), "utf8");
9891
10081
  const m = s.match(/^APIBLAZE_API_KEY=(.+)$/m) ?? s.match(/^APIBLAZE_TOKEN=(.+)$/m);
9892
10082
  return m ? m[1].trim() : null;
9893
10083
  } catch {
@@ -9895,16 +10085,16 @@ function readEnvKey(root) {
9895
10085
  }
9896
10086
  }
9897
10087
  function ensureGitignored(root) {
9898
- const p = path7.join(root, ".gitignore");
10088
+ const p = path8.join(root, ".gitignore");
9899
10089
  let c = "";
9900
10090
  try {
9901
- c = fs11.readFileSync(p, "utf8");
10091
+ c = fs12.readFileSync(p, "utf8");
9902
10092
  } catch {
9903
10093
  }
9904
- if (!/^\.env\.local$/m.test(c) && !/^\.env\*/m.test(c)) fs11.writeFileSync(p, (c && !c.endsWith("\n") ? c + "\n" : c) + ".env.local\n");
10094
+ if (!/^\.env\.local$/m.test(c) && !/^\.env\*/m.test(c)) fs12.writeFileSync(p, (c && !c.endsWith("\n") ? c + "\n" : c) + ".env.local\n");
9905
10095
  }
9906
10096
  function wireInstrumentation(root) {
9907
- const existing = ["instrumentation.ts", "instrumentation.js", path7.join("src", "instrumentation.ts")].map((c) => path7.join(root, c)).find((f) => fs11.existsSync(f));
10097
+ const existing = ["instrumentation.ts", "instrumentation.js", path8.join("src", "instrumentation.ts")].map((c) => path8.join(root, c)).find((f) => fs12.existsSync(f));
9908
10098
  const body = `import { register as apiblaze } from "apiblaze/sidecar";
9909
10099
 
9910
10100
  export function register() {
@@ -9912,18 +10102,18 @@ export function register() {
9912
10102
  }
9913
10103
  `;
9914
10104
  if (!existing) {
9915
- fs11.writeFileSync(path7.join(root, "instrumentation.ts"), body);
10105
+ fs12.writeFileSync(path8.join(root, "instrumentation.ts"), body);
9916
10106
  return "created";
9917
10107
  }
9918
- const cur = fs11.readFileSync(existing, "utf8");
10108
+ const cur = fs12.readFileSync(existing, "utf8");
9919
10109
  if (cur.includes("apiblaze/sidecar")) return "present";
9920
10110
  if (/export\s+function\s+register\s*\(/.test(cur)) {
9921
- fs11.writeFileSync(existing, `import { register as apiblaze } from "apiblaze/sidecar";
10111
+ fs12.writeFileSync(existing, `import { register as apiblaze } from "apiblaze/sidecar";
9922
10112
  ` + cur.replace(/export\s+function\s+register\s*\(\s*\)\s*\{/, (m) => `${m}
9923
10113
  apiblaze();`));
9924
10114
  return "patched";
9925
10115
  }
9926
- fs11.writeFileSync(existing, `import { register as apiblaze } from "apiblaze/sidecar";
10116
+ fs12.writeFileSync(existing, `import { register as apiblaze } from "apiblaze/sidecar";
9927
10117
  ${cur}
9928
10118
  // call apiblaze() inside your register() export.
9929
10119
  `);
@@ -10002,17 +10192,17 @@ export default async function Page() {
10002
10192
  function generateInspector(root, router) {
10003
10193
  try {
10004
10194
  if (router === "pages") {
10005
- const dir2 = fs11.existsSync(path7.join(root, "src", "pages")) ? path7.join(root, "src", "pages") : path7.join(root, "pages");
10006
- const f2 = path7.join(dir2, "abz-inspector.tsx");
10007
- fs11.writeFileSync(f2, INSPECTOR_PAGE);
10008
- return path7.relative(root, f2);
10009
- }
10010
- const base2 = fs11.existsSync(path7.join(root, "src", "app")) ? path7.join(root, "src", "app") : path7.join(root, "app");
10011
- const dir = path7.join(base2, "abz-inspector");
10012
- fs11.mkdirSync(dir, { recursive: true });
10013
- const f = path7.join(dir, "page.tsx");
10014
- fs11.writeFileSync(f, INSPECTOR_PAGE);
10015
- return path7.relative(root, f);
10195
+ const dir2 = fs12.existsSync(path8.join(root, "src", "pages")) ? path8.join(root, "src", "pages") : path8.join(root, "pages");
10196
+ const f2 = path8.join(dir2, "abz-inspector.tsx");
10197
+ fs12.writeFileSync(f2, INSPECTOR_PAGE);
10198
+ return path8.relative(root, f2);
10199
+ }
10200
+ const base2 = fs12.existsSync(path8.join(root, "src", "app")) ? path8.join(root, "src", "app") : path8.join(root, "app");
10201
+ const dir = path8.join(base2, "abz-inspector");
10202
+ fs12.mkdirSync(dir, { recursive: true });
10203
+ const f = path8.join(dir, "page.tsx");
10204
+ fs12.writeFileSync(f, INSPECTOR_PAGE);
10205
+ return path8.relative(root, f);
10016
10206
  } catch {
10017
10207
  return null;
10018
10208
  }
@@ -10033,29 +10223,29 @@ async function runAnonymousInit(root, router, opts) {
10033
10223
  if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
10034
10224
  const envState = upsertEnvLocal(root, out.token);
10035
10225
  ensureGitignored(root);
10036
- console.log(` ${import_chalk48.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
10037
- console.log(` ${import_chalk48.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
10226
+ console.log(` ${import_chalk49.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
10227
+ console.log(` ${import_chalk49.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
10038
10228
  installSidecarPackage(root);
10039
10229
  let inspectorPath = null;
10040
10230
  if (!opts.noInspector) {
10041
10231
  inspectorPath = generateInspector(root, router);
10042
- if (inspectorPath) console.log(` ${import_chalk48.default.green("\u2713")} inspector at ${inspectorPath}`);
10232
+ if (inspectorPath) console.log(` ${import_chalk49.default.green("\u2713")} inspector at ${inspectorPath}`);
10043
10233
  }
10044
10234
  console.log("");
10045
- console.log(import_chalk48.default.bold("Done (no account needed). What happens next:"));
10046
- console.log(` 1. ${import_chalk48.default.cyan("npm run dev")} and use your app.`);
10235
+ console.log(import_chalk49.default.bold("Done (no account needed). What happens next:"));
10236
+ console.log(` 1. ${import_chalk49.default.cyan("npm run dev")} and use your app.`);
10047
10237
  console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
10048
- console.log(` ${import_chalk48.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
10238
+ console.log(` ${import_chalk49.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
10049
10239
  console.log("");
10050
- console.log(import_chalk48.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
10051
- console.log(` ${import_chalk48.default.cyan("apiblaze login")} then ${import_chalk48.default.cyan("apiblaze claim")} ${import_chalk48.default.dim("(no code needed here)")}`);
10052
- console.log(import_chalk48.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
10240
+ console.log(import_chalk49.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
10241
+ console.log(` ${import_chalk49.default.cyan("apiblaze login")} then ${import_chalk49.default.cyan("apiblaze claim")} ${import_chalk49.default.dim("(no code needed here)")}`);
10242
+ console.log(import_chalk49.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
10053
10243
  }
10054
10244
  async function runSidecar(opts) {
10055
- const root = path7.resolve(opts.dir ?? process.cwd());
10245
+ const root = path8.resolve(opts.dir ?? process.cwd());
10056
10246
  const detected = detectNextProject(root);
10057
10247
  if (!detected.found) {
10058
- console.log(import_chalk48.default.yellow(`No Next.js project detected in ${root}.`));
10248
+ console.log(import_chalk49.default.yellow(`No Next.js project detected in ${root}.`));
10059
10249
  console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
10060
10250
  return;
10061
10251
  }
@@ -10066,10 +10256,10 @@ async function runSidecar(opts) {
10066
10256
  if (!loadCredentials()) {
10067
10257
  upsertEnvLocal(root, readEnvKey(root));
10068
10258
  ensureGitignored(root);
10069
- console.log(` ${import_chalk48.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
10070
- console.log(` ${import_chalk48.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
10259
+ console.log(` ${import_chalk49.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
10260
+ console.log(` ${import_chalk49.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
10071
10261
  installSidecarPackage(root);
10072
- console.log(import_chalk48.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
10262
+ console.log(import_chalk49.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
10073
10263
  return;
10074
10264
  }
10075
10265
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -10092,38 +10282,38 @@ async function runSidecar(opts) {
10092
10282
  throw err;
10093
10283
  }
10094
10284
  } else {
10095
- console.log(import_chalk48.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
10285
+ console.log(import_chalk49.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
10096
10286
  }
10097
10287
  const envState = upsertEnvLocal(root, token);
10098
10288
  ensureGitignored(root);
10099
- console.log(` ${import_chalk48.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
10289
+ console.log(` ${import_chalk49.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
10100
10290
  const wireState = wireInstrumentation(root);
10101
- console.log(` ${import_chalk48.default.green("\u2713")} instrumentation.ts ${wireState}`);
10291
+ console.log(` ${import_chalk49.default.green("\u2713")} instrumentation.ts ${wireState}`);
10102
10292
  installSidecarPackage(root);
10103
10293
  let inspectorPath = null;
10104
10294
  if (!opts.noInspector) {
10105
10295
  inspectorPath = generateInspector(root, detected.router);
10106
- if (inspectorPath) console.log(` ${import_chalk48.default.green("\u2713")} inspector at ${inspectorPath}`);
10296
+ if (inspectorPath) console.log(` ${import_chalk49.default.green("\u2713")} inspector at ${inspectorPath}`);
10107
10297
  }
10108
10298
  console.log("");
10109
- console.log(import_chalk48.default.bold("Done. What happens next:"));
10110
- console.log(` 1. ${import_chalk48.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
10111
- console.log(` 2. The origins your app calls appear as ${import_chalk48.default.bold("candidates")} \u2014 list them: ${import_chalk48.default.cyan("apiblaze sidecar")}`);
10112
- console.log(` 3. Approve the ones to route: ${import_chalk48.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
10299
+ console.log(import_chalk49.default.bold("Done. What happens next:"));
10300
+ console.log(` 1. ${import_chalk49.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
10301
+ console.log(` 2. The origins your app calls appear as ${import_chalk49.default.bold("candidates")} \u2014 list them: ${import_chalk49.default.cyan("apiblaze sidecar")}`);
10302
+ console.log(` 3. Approve the ones to route: ${import_chalk49.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
10113
10303
  console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
10114
- if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk48.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path7.dirname(inspectorPath)} before shipping)`);
10115
- if (switchingTeam) console.log(import_chalk48.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
10304
+ if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk49.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path8.dirname(inspectorPath)} before shipping)`);
10305
+ if (switchingTeam) console.log(import_chalk49.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
10116
10306
  console.log("");
10117
- console.log(import_chalk48.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
10118
- console.log(import_chalk48.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
10119
- console.log(import_chalk48.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
10307
+ console.log(import_chalk49.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
10308
+ console.log(import_chalk49.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
10309
+ console.log(import_chalk49.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
10120
10310
  console.log("");
10121
- console.log(import_chalk48.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
10122
- console.log(import_chalk48.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
10311
+ console.log(import_chalk49.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
10312
+ console.log(import_chalk49.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
10123
10313
  }
10124
10314
 
10125
10315
  // src/commands/origins.ts
10126
- var import_chalk49 = __toESM(require("chalk"));
10316
+ var import_chalk50 = __toESM(require("chalk"));
10127
10317
  var import_ora26 = __toESM(require("ora"));
10128
10318
  init_admin();
10129
10319
  init_resolve();
@@ -10134,7 +10324,7 @@ async function runOriginsList(opts) {
10134
10324
  if (!loadCredentials()) {
10135
10325
  const cred = loadAnonCred();
10136
10326
  if (!cred) {
10137
- console.log(import_chalk49.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
10327
+ console.log(import_chalk50.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
10138
10328
  return;
10139
10329
  }
10140
10330
  out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
@@ -10152,27 +10342,27 @@ async function runOriginsList(opts) {
10152
10342
  }
10153
10343
  const routed = out.routed ?? [];
10154
10344
  const candidates = out.candidates ?? [];
10155
- console.log(import_chalk49.default.bold(`
10345
+ console.log(import_chalk50.default.bold(`
10156
10346
  Routed through APIblaze (${routed.length})`));
10157
- if (!routed.length) console.log(import_chalk49.default.dim(" none yet"));
10158
- for (const r of routed) console.log(` ${import_chalk49.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk49.default.dim(`\u2192 ${r.project_id}`)}`);
10159
- console.log(import_chalk49.default.bold(`
10347
+ if (!routed.length) console.log(import_chalk50.default.dim(" none yet"));
10348
+ for (const r of routed) console.log(` ${import_chalk50.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk50.default.dim(`\u2192 ${r.project_id}`)}`);
10349
+ console.log(import_chalk50.default.bold(`
10160
10350
  Candidates \u2014 going direct, not yet approved (${candidates.length})`));
10161
- if (!candidates.length) console.log(import_chalk49.default.dim(" none \u2014 run your app to discover the origins it calls"));
10351
+ if (!candidates.length) console.log(import_chalk50.default.dim(" none \u2014 run your app to discover the origins it calls"));
10162
10352
  for (const c of candidates) {
10163
- console.log(` ${import_chalk49.default.yellow("\u25CB")} ${c.origin} ${import_chalk49.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
10353
+ console.log(` ${import_chalk50.default.yellow("\u25CB")} ${c.origin} ${import_chalk50.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
10164
10354
  }
10165
10355
  if (candidates.length) {
10166
- console.log(import_chalk49.default.dim(`
10356
+ console.log(import_chalk50.default.dim(`
10167
10357
  Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
10168
- console.log(import_chalk49.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
10358
+ console.log(import_chalk50.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
10169
10359
  }
10170
10360
  }
10171
10361
  async function runOriginsApprove(origin, opts) {
10172
10362
  if (!loadCredentials()) {
10173
10363
  const cred = loadAnonCred();
10174
10364
  if (!cred) {
10175
- console.error(import_chalk49.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
10365
+ console.error(import_chalk50.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
10176
10366
  process.exit(1);
10177
10367
  }
10178
10368
  const spinner2 = (0, import_ora26.default)(`Approving ${origin} (anonymous)...`).start();
@@ -10225,13 +10415,13 @@ async function runOriginsRemove(origin, opts) {
10225
10415
  }
10226
10416
 
10227
10417
  // src/commands/op.ts
10228
- var import_chalk51 = __toESM(require("chalk"));
10418
+ var import_chalk52 = __toESM(require("chalk"));
10229
10419
  init_auth();
10230
10420
  init_trace();
10231
10421
  init_types();
10232
10422
 
10233
10423
  // src/commands/op-billing.ts
10234
- var import_chalk50 = __toESM(require("chalk"));
10424
+ var import_chalk51 = __toESM(require("chalk"));
10235
10425
  init_admin();
10236
10426
  var SANDBOX = {
10237
10427
  teamId: "team_1782844865835_zujrf",
@@ -10290,7 +10480,7 @@ async function rowsForRays(project, version2, tenant2, rays) {
10290
10480
  }
10291
10481
  function printDoors(data) {
10292
10482
  const checks = [];
10293
- console.log(import_chalk50.default.bold("\n Doors \u2014 is every way in metered?\n"));
10483
+ console.log(import_chalk51.default.bold("\n Doors \u2014 is every way in metered?\n"));
10294
10484
  const doors = data?.doors ?? [];
10295
10485
  const metered = doors.filter((d) => d.verdict === "metered");
10296
10486
  const allowed = doors.filter((d) => d.verdict === "allowed-free");
@@ -10299,29 +10489,29 @@ function printDoors(data) {
10299
10489
  const errs = data?.errors ?? [];
10300
10490
  const routeAuditBroke = errs.some((e) => e.startsWith("zone "));
10301
10491
  const devAuditBroke = errs.some((e) => e.startsWith("workers.dev audit"));
10302
- console.log(import_chalk50.default.dim(` ${metered.length} route(s) behind main-proxy (metered)`));
10303
- for (const d of metered) console.log(import_chalk50.default.green(` \u2713 ${d.pattern}`));
10304
- console.log(import_chalk50.default.dim(`
10492
+ console.log(import_chalk51.default.dim(` ${metered.length} route(s) behind main-proxy (metered)`));
10493
+ for (const d of metered) console.log(import_chalk51.default.green(` \u2713 ${d.pattern}`));
10494
+ console.log(import_chalk51.default.dim(`
10305
10495
  ${allowed.length} route(s) free ON PURPOSE`));
10306
10496
  for (const d of allowed) {
10307
- console.log(import_chalk50.default.cyan(` \u2022 ${d.pattern}`) + import_chalk50.default.dim(` \u2192 ${d.script}`));
10308
- console.log(import_chalk50.default.dim(` ${d.why}`));
10497
+ console.log(import_chalk51.default.cyan(` \u2022 ${d.pattern}`) + import_chalk51.default.dim(` \u2192 ${d.script}`));
10498
+ console.log(import_chalk51.default.dim(` ${d.why}`));
10309
10499
  }
10310
10500
  if (known.length) {
10311
- console.log(import_chalk50.default.yellow(`
10501
+ console.log(import_chalk51.default.yellow(`
10312
10502
  ${known.length} route(s) KNOWN OPEN \u2014 unmetered, not yet closed`));
10313
10503
  for (const d of known) {
10314
- console.log(import_chalk50.default.yellow(` ! ${d.pattern}`) + import_chalk50.default.dim(` \u2192 ${d.script}`));
10315
- console.log(import_chalk50.default.dim(` ${d.why}`));
10504
+ console.log(import_chalk51.default.yellow(` ! ${d.pattern}`) + import_chalk51.default.dim(` \u2192 ${d.script}`));
10505
+ console.log(import_chalk51.default.dim(` ${d.why}`));
10316
10506
  }
10317
10507
  checks.push({ name: "no known-open doors", status: "KNOWN", detail: `${known.length} unmetered route(s) still open \u2014 see above` });
10318
10508
  }
10319
10509
  if (stray.length) {
10320
- console.log(import_chalk50.default.red(`
10510
+ console.log(import_chalk51.default.red(`
10321
10511
  ${stray.length} STRAY route(s) \u2014 not main-proxy, not on the allowlist`));
10322
10512
  for (const d of stray) {
10323
- console.log(import_chalk50.default.red(` \u2717 ${d.pattern}`) + import_chalk50.default.dim(` \u2192 ${d.script}`));
10324
- console.log(import_chalk50.default.dim(` ${d.why}`));
10513
+ console.log(import_chalk51.default.red(` \u2717 ${d.pattern}`) + import_chalk51.default.dim(` \u2192 ${d.script}`));
10514
+ console.log(import_chalk51.default.dim(` ${d.why}`));
10325
10515
  }
10326
10516
  checks.push({ name: "no stray routes", status: "FAIL", detail: `${stray.length}: ${stray.map((s) => s.pattern).join(", ")}` });
10327
10517
  } else if (routeAuditBroke) {
@@ -10332,22 +10522,22 @@ function printDoors(data) {
10332
10522
  const wd = data?.workers_dev ?? {};
10333
10523
  const open = wd.enabled ?? [];
10334
10524
  if (open.length) {
10335
- console.log(import_chalk50.default.red(`
10525
+ console.log(import_chalk51.default.red(`
10336
10526
  ${open.length} of ${wd.total} worker(s) reachable on *.workers.dev`));
10337
- for (const s of open) console.log(import_chalk50.default.red(` \u2717 ${s.script}.workers.dev`) + import_chalk50.default.dim(` (enabled=${s.enabled} previews=${s.previews})`));
10338
- console.log(import_chalk50.default.dim(" A workers.dev hostname bypasses every CF route, WAF rule and the credit gate."));
10527
+ for (const s of open) console.log(import_chalk51.default.red(` \u2717 ${s.script}.workers.dev`) + import_chalk51.default.dim(` (enabled=${s.enabled} previews=${s.previews})`));
10528
+ console.log(import_chalk51.default.dim(" A workers.dev hostname bypasses every CF route, WAF rule and the credit gate."));
10339
10529
  checks.push({ name: "no workers.dev doors", status: "FAIL", detail: `${open.length} script(s) publicly reachable: ${open.map((s) => s.script).join(", ")}` });
10340
10530
  } else if (devAuditBroke || !wd.total) {
10341
10531
  checks.push({ name: "no workers.dev doors", status: "SKIP", detail: "script enumeration failed \u2014 NOT a pass, no subdomain was ever read. Needs a CF token with Workers Scripts:Read." });
10342
10532
  } else {
10343
- console.log(import_chalk50.default.green(`
10533
+ console.log(import_chalk51.default.green(`
10344
10534
  \u2713 0 of ${wd.total} workers reachable on *.workers.dev`));
10345
10535
  checks.push({ name: "no workers.dev doors", status: "PASS", detail: `all ${wd.total} scripts have workers.dev + previews disabled` });
10346
10536
  }
10347
- if (data?.how_to_fix) console.log(import_chalk50.default.yellow(`
10348
- ${data.reason}`) + import_chalk50.default.dim(`
10537
+ if (data?.how_to_fix) console.log(import_chalk51.default.yellow(`
10538
+ ${data.reason}`) + import_chalk51.default.dim(`
10349
10539
  ${data.how_to_fix}`));
10350
- else for (const e of errs) console.log(import_chalk50.default.red(`
10540
+ else for (const e of errs) console.log(import_chalk51.default.red(`
10351
10541
  audit error: ${e}`));
10352
10542
  if (errs.length) {
10353
10543
  checks.push({ name: "audit completeness", status: "FAIL", detail: `${errs.length} part(s) of the audit could not run \u2014 coverage is INCOMPLETE, and the checks they would have covered are SKIP above` });
@@ -10357,9 +10547,9 @@ function printDoors(data) {
10357
10547
  async function runMeter(readLedger, opts) {
10358
10548
  const checks = [];
10359
10549
  const N = Math.max(1, Math.min(10, opts.count ?? 3));
10360
- console.log(import_chalk50.default.bold("\n Meter \u2014 is 1 request charged exactly 1 request?\n"));
10550
+ console.log(import_chalk51.default.bold("\n Meter \u2014 is 1 request charged exactly 1 request?\n"));
10361
10551
  const snap = await readLedger();
10362
- console.log(import_chalk50.default.dim(` wallet ${snap.billing_account_id} \xB7 band count ${snap.band_count} \xB7 next request ${snap.next_request_cents}\xA2
10552
+ console.log(import_chalk51.default.dim(` wallet ${snap.billing_account_id} \xB7 band count ${snap.band_count} \xB7 next request ${snap.next_request_cents}\xA2
10363
10553
  `));
10364
10554
  const url = `https://${dpHost}/${SANDBOX.version}/${SANDBOX.environment}/`;
10365
10555
  const headers = opts.key ? { "X-API-Key": opts.key } : {};
@@ -10441,22 +10631,22 @@ async function runMeter(readLedger, opts) {
10441
10631
  return checks;
10442
10632
  }
10443
10633
  function printChecks(checks) {
10444
- console.log(import_chalk50.default.bold("\n Results\n"));
10445
- const mark = { PASS: import_chalk50.default.green(" PASS"), FAIL: import_chalk50.default.red(" FAIL"), SKIP: import_chalk50.default.dim(" SKIP"), KNOWN: import_chalk50.default.yellow(" KNOWN") };
10634
+ console.log(import_chalk51.default.bold("\n Results\n"));
10635
+ const mark = { PASS: import_chalk51.default.green(" PASS"), FAIL: import_chalk51.default.red(" FAIL"), SKIP: import_chalk51.default.dim(" SKIP"), KNOWN: import_chalk51.default.yellow(" KNOWN") };
10446
10636
  for (const ch of checks) {
10447
- console.log(` ${mark[ch.status]} ${import_chalk50.default.bold(ch.name)}`);
10448
- console.log(import_chalk50.default.dim(` ${ch.detail}`));
10637
+ console.log(` ${mark[ch.status]} ${import_chalk51.default.bold(ch.name)}`);
10638
+ console.log(import_chalk51.default.dim(` ${ch.detail}`));
10449
10639
  }
10450
10640
  const fails = checks.filter((c) => c.status === "FAIL").length;
10451
10641
  const skips = checks.filter((c) => c.status === "SKIP").length;
10452
10642
  const known = checks.filter((c) => c.status === "KNOWN").length;
10453
10643
  console.log("");
10454
10644
  const passes = checks.filter((c) => c.status === "PASS").length;
10455
- if (fails) console.log(import_chalk50.default.red(` ${fails} check(s) FAILED.`));
10456
- else if (passes) console.log(import_chalk50.default.green(` ${passes} check(s) passed, 0 failed.`));
10457
- else console.log(import_chalk50.default.yellow(" NOTHING WAS VERIFIED \u2014 every check was skipped."));
10458
- if (known) console.log(import_chalk50.default.yellow(` ${known} known-open issue(s) still outstanding.`));
10459
- if (skips) console.log(import_chalk50.default.dim(` ${skips} check(s) NOT RUN (see SKIP above) \u2014 those invariants are unverified.`));
10645
+ if (fails) console.log(import_chalk51.default.red(` ${fails} check(s) FAILED.`));
10646
+ else if (passes) console.log(import_chalk51.default.green(` ${passes} check(s) passed, 0 failed.`));
10647
+ else console.log(import_chalk51.default.yellow(" NOTHING WAS VERIFIED \u2014 every check was skipped."));
10648
+ if (known) console.log(import_chalk51.default.yellow(` ${known} known-open issue(s) still outstanding.`));
10649
+ if (skips) console.log(import_chalk51.default.dim(` ${skips} check(s) NOT RUN (see SKIP above) \u2014 those invariants are unverified.`));
10460
10650
  console.log("");
10461
10651
  }
10462
10652
 
@@ -10503,93 +10693,93 @@ var OP_COMMANDS = [
10503
10693
  function renderOpCommands() {
10504
10694
  const width = Math.max(...OP_COMMANDS.map((c) => c.cmd.length)) + 10;
10505
10695
  const lines = OP_COMMANDS.map((c) => {
10506
- const left = ` ${import_chalk51.default.cyan(`apiblaze ${c.cmd}`)}`;
10696
+ const left = ` ${import_chalk52.default.cyan(`apiblaze ${c.cmd}`)}`;
10507
10697
  const pad = " ".repeat(Math.max(1, width - c.cmd.length));
10508
- return `${left}${pad}${c.blurb}${c.extra ? " " + import_chalk51.default.dim(`(${c.extra})`) : ""}`;
10698
+ return `${left}${pad}${c.blurb}${c.extra ? " " + import_chalk52.default.dim(`(${c.extra})`) : ""}`;
10509
10699
  });
10510
10700
  return [
10511
- import_chalk51.default.bold("Operator commands"),
10701
+ import_chalk52.default.bold("Operator commands"),
10512
10702
  ...lines,
10513
10703
  "",
10514
- import_chalk51.default.dim(" Operators only. The gate is server-side (dashboard /api/cli/op checks the"),
10515
- import_chalk51.default.dim(" signed-in email, admin-api re-checks with operatorGate) \u2014 a patched CLI just"),
10516
- import_chalk51.default.dim(" gets 403s. Every op call is read-only except `op sweep`."),
10704
+ import_chalk52.default.dim(" Operators only. The gate is server-side (dashboard /api/cli/op checks the"),
10705
+ import_chalk52.default.dim(" signed-in email, admin-api re-checks with operatorGate) \u2014 a patched CLI just"),
10706
+ import_chalk52.default.dim(" gets 403s. Every op call is read-only except `op sweep`."),
10517
10707
  "",
10518
- import_chalk51.default.dim(" Not a CLI command: to prune all non-CP data run scripts/nuke-but-cp.sh --apply --sweep"),
10519
- import_chalk51.default.dim(" in the repo. Operator dashboards (dlq, thresholds, throttling, pricing, billing,"),
10520
- import_chalk51.default.dim(" agent-spend, teams, tests, leak-detection, lifecycle) live at /operator/* in the app.")
10708
+ import_chalk52.default.dim(" Not a CLI command: to prune all non-CP data run scripts/nuke-but-cp.sh --apply --sweep"),
10709
+ import_chalk52.default.dim(" in the repo. Operator dashboards (dlq, thresholds, throttling, pricing, billing,"),
10710
+ import_chalk52.default.dim(" agent-spend, teams, tests, leak-detection, lifecycle) live at /operator/* in the app.")
10521
10711
  ].join("\n");
10522
10712
  }
10523
10713
  function printResidue(report, applied) {
10524
10714
  const up = report?.upstash ?? {};
10525
10715
  const fga = report?.fga ?? {};
10526
10716
  const ghosts = report?.ghosts ?? {};
10527
- console.log(import_chalk51.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
10528
- console.log(import_chalk51.default.bold("\n Upstash"));
10717
+ console.log(import_chalk52.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
10718
+ console.log(import_chalk52.default.bold("\n Upstash"));
10529
10719
  const orphans = up.orphans ?? [];
10530
- if (orphans.length === 0) console.log(import_chalk51.default.green(" no orphaned keys"));
10531
- for (const o of orphans) console.log(` ${import_chalk51.default.yellow(o.key)} ${import_chalk51.default.dim(`\u2014 ${o.reason}`)}`);
10532
- console.log(import_chalk51.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
10720
+ if (orphans.length === 0) console.log(import_chalk52.default.green(" no orphaned keys"));
10721
+ for (const o of orphans) console.log(` ${import_chalk52.default.yellow(o.key)} ${import_chalk52.default.dim(`\u2014 ${o.reason}`)}`);
10722
+ console.log(import_chalk52.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
10533
10723
  if (up.anon_wallet_detail) {
10534
10724
  const d = up.anon_wallet_detail;
10535
- console.log(import_chalk51.default.dim(` anon wallets: ${d.count} ($${(d.total_cents / 100).toFixed(2)}), ${d.no_ttl} with NO TTL${d.no_ttl ? " \u26A0" : " (all self-expire)"}`));
10725
+ console.log(import_chalk52.default.dim(` anon wallets: ${d.count} ($${(d.total_cents / 100).toFixed(2)}), ${d.no_ttl} with NO TTL${d.no_ttl ? " \u26A0" : " (all self-expire)"}`));
10536
10726
  }
10537
10727
  if (up.keyspace_census) {
10538
10728
  const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
10539
- console.log(import_chalk51.default.dim(` keyspace: ${census}`));
10729
+ console.log(import_chalk52.default.dim(` keyspace: ${census}`));
10540
10730
  }
10541
- if (up.unknown?.length) console.log(import_chalk51.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
10542
- if (applied) console.log(` ${import_chalk51.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
10543
- for (const e of up.errors ?? []) console.log(import_chalk51.default.red(` error: ${e}`));
10544
- console.log(import_chalk51.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
10731
+ if (up.unknown?.length) console.log(import_chalk52.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
10732
+ if (applied) console.log(` ${import_chalk52.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
10733
+ for (const e of up.errors ?? []) console.log(import_chalk52.default.red(` error: ${e}`));
10734
+ console.log(import_chalk52.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
10545
10735
  if (applied) {
10546
10736
  const swept = fga?.swept ?? [];
10547
- if (swept.length === 0) console.log(import_chalk51.default.green(" no orphaned stores"));
10737
+ if (swept.length === 0) console.log(import_chalk52.default.green(" no orphaned stores"));
10548
10738
  for (const s of swept) {
10549
10739
  console.log(
10550
- ` ${import_chalk51.default.yellow(s.store_id)} ${import_chalk51.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
10740
+ ` ${import_chalk52.default.yellow(s.store_id)} ${import_chalk52.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
10551
10741
  );
10552
10742
  }
10553
- if (fga?.remaining) console.log(import_chalk51.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
10743
+ if (fga?.remaining) console.log(import_chalk52.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
10554
10744
  const st = fga?.side_tables;
10555
- if (st) console.log(import_chalk51.default.dim(` Neon side-tables purged: ${st.soft_deleted_stores} store records, ${st.orphan_models} models, ${st.orphan_changelog} changelog rows${st.error ? ` (${st.error})` : ""}`));
10745
+ if (st) console.log(import_chalk52.default.dim(` Neon side-tables purged: ${st.soft_deleted_stores} store records, ${st.orphan_models} models, ${st.orphan_changelog} changelog rows${st.error ? ` (${st.error})` : ""}`));
10556
10746
  } else {
10557
10747
  const fgaOrphans = fga?.orphans ?? [];
10558
- if (fgaOrphans.length === 0) console.log(import_chalk51.default.green(" no orphaned stores"));
10748
+ if (fgaOrphans.length === 0) console.log(import_chalk52.default.green(" no orphaned stores"));
10559
10749
  for (const s of fgaOrphans) {
10560
10750
  const src = s.in_openfga ? "live in OpenFGA" : "Neon tuples only";
10561
- console.log(` ${import_chalk51.default.yellow(s.store_id)} ${import_chalk51.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
10751
+ console.log(` ${import_chalk52.default.yellow(s.store_id)} ${import_chalk52.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
10562
10752
  }
10563
- console.log(import_chalk51.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
10753
+ console.log(import_chalk52.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
10564
10754
  const st = fga?.side_tables;
10565
- if (st) console.log(import_chalk51.default.dim(` Neon side-table residue: ${st.soft_deleted_stores} soft-deleted store records, ${st.orphan_models} orphan models, ${st.orphan_changelog} orphan changelog rows`));
10755
+ if (st) console.log(import_chalk52.default.dim(` Neon side-table residue: ${st.soft_deleted_stores} soft-deleted store records, ${st.orphan_models} orphan models, ${st.orphan_changelog} orphan changelog rows`));
10566
10756
  }
10567
- for (const e of fga?.errors ?? []) console.log(import_chalk51.default.red(` error: ${e}`));
10568
- console.log(import_chalk51.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
10757
+ for (const e of fga?.errors ?? []) console.log(import_chalk52.default.red(` error: ${e}`));
10758
+ console.log(import_chalk52.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
10569
10759
  if (applied) {
10570
- if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk51.default.green(" no ghost tuples"));
10571
- else console.log(` ${import_chalk51.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk51.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
10760
+ if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk52.default.green(" no ghost tuples"));
10761
+ else console.log(` ${import_chalk52.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk52.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
10572
10762
  } else {
10573
10763
  const n = ghosts?.ghost_count ?? 0;
10574
- if (n === 0) console.log(import_chalk51.default.green(` no ghost tuples ${import_chalk51.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
10764
+ if (n === 0) console.log(import_chalk52.default.green(` no ghost tuples ${import_chalk52.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
10575
10765
  else {
10576
- console.log(import_chalk51.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
10766
+ console.log(import_chalk52.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
10577
10767
  for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
10578
- console.log(import_chalk51.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
10768
+ console.log(import_chalk52.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
10579
10769
  }
10580
- if (n > 20) console.log(import_chalk51.default.dim(` \u2026 and ${n - 20} more`));
10770
+ if (n > 20) console.log(import_chalk52.default.dim(` \u2026 and ${n - 20} more`));
10581
10771
  }
10582
10772
  }
10583
- for (const e of ghosts?.errors ?? []) console.log(import_chalk51.default.red(` error: ${e}`));
10773
+ for (const e of ghosts?.errors ?? []) console.log(import_chalk52.default.red(` error: ${e}`));
10584
10774
  console.log();
10585
10775
  }
10586
10776
  async function runOp(sub, opts = {}, view) {
10587
10777
  if (!loadCredentials()) {
10588
- console.log(import_chalk51.default.dim("Not logged in. Run `apiblaze login`."));
10778
+ console.log(import_chalk52.default.dim("Not logged in. Run `apiblaze login`."));
10589
10779
  return;
10590
10780
  }
10591
10781
  if (!isOperatorLogin()) {
10592
- console.log(import_chalk51.default.dim("`apiblaze op` is only available to platform operators."));
10782
+ console.log(import_chalk52.default.dim("`apiblaze op` is only available to platform operators."));
10593
10783
  return;
10594
10784
  }
10595
10785
  switch (sub) {
@@ -10615,17 +10805,17 @@ async function runOp(sub, opts = {}, view) {
10615
10805
  const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
10616
10806
  printResidue(report, false);
10617
10807
  if (nUp + nFga + nGhost + nSide === 0) {
10618
- console.log(import_chalk51.default.green("Nothing to sweep."));
10808
+ console.log(import_chalk52.default.green("Nothing to sweep."));
10619
10809
  return;
10620
10810
  }
10621
10811
  if (!opts.yes) {
10622
10812
  const readline3 = await import("readline/promises");
10623
10813
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
10624
10814
  const answer = await rl.question(
10625
- import_chalk51.default.red(`Delete ${nUp} Upstash key(s) + ${nFga} OpenFGA store(s) + ${nGhost} ghost tuple(s) + ${nSide} Neon side-table row(s)? Type 'sweep' to confirm: `)
10815
+ import_chalk52.default.red(`Delete ${nUp} Upstash key(s) + ${nFga} OpenFGA store(s) + ${nGhost} ghost tuple(s) + ${nSide} Neon side-table row(s)? Type 'sweep' to confirm: `)
10626
10816
  );
10627
10817
  rl.close();
10628
- if (answer.trim() !== "sweep") return void console.log(import_chalk51.default.dim("Aborted."));
10818
+ if (answer.trim() !== "sweep") return void console.log(import_chalk52.default.dim("Aborted."));
10629
10819
  }
10630
10820
  const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
10631
10821
  if (opts.json) return void console.log(JSON.stringify(result, null, 2));
@@ -10635,25 +10825,25 @@ async function runOp(sub, opts = {}, view) {
10635
10825
  case "mark": {
10636
10826
  const label3 = (view ?? "").trim();
10637
10827
  if (!label3) {
10638
- console.log(import_chalk51.default.red("Give the change a name:") + import_chalk51.default.cyan(' apiblaze op mark "cached tenant count"'));
10828
+ console.log(import_chalk52.default.red("Give the change a name:") + import_chalk52.default.cyan(' apiblaze op mark "cached tenant count"'));
10639
10829
  return;
10640
10830
  }
10641
10831
  const res = await opCall({ method: "POST", path: "/operator/latency/mark", body: { label: label3 }, summary: "record change marker" });
10642
10832
  const ts = new Date(res?.marker?.ts ?? Date.now()).toISOString();
10643
- console.log(import_chalk51.default.green(`
10644
- Marked: `) + import_chalk51.default.bold(label3));
10645
- console.log(import_chalk51.default.dim(` ${ts}`));
10646
- console.log(import_chalk51.default.dim(` Once traffic has run on both sides, compare with: `) + import_chalk51.default.cyan("apiblaze op latency compare") + "\n");
10833
+ console.log(import_chalk52.default.green(`
10834
+ Marked: `) + import_chalk52.default.bold(label3));
10835
+ console.log(import_chalk52.default.dim(` ${ts}`));
10836
+ console.log(import_chalk52.default.dim(` Once traffic has run on both sides, compare with: `) + import_chalk52.default.cyan("apiblaze op latency compare") + "\n");
10647
10837
  return;
10648
10838
  }
10649
10839
  case "credits": {
10650
10840
  const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list credit wallets" });
10651
10841
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10652
10842
  const accounts = data?.accounts ?? [];
10653
- if (accounts.length === 0) return void console.log(import_chalk51.default.dim("No credit wallets."));
10843
+ if (accounts.length === 0) return void console.log(import_chalk52.default.dim("No credit wallets."));
10654
10844
  for (const a of accounts) {
10655
10845
  const bal = typeof a.balance_cents === "number" ? `$${(a.balance_cents / 100).toFixed(2)}` : "?";
10656
- console.log(` ${import_chalk51.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk51.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk51.default.dim(" \u2014 anon") : ""}`);
10846
+ console.log(` ${import_chalk52.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk52.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk52.default.dim(" \u2014 anon") : ""}`);
10657
10847
  }
10658
10848
  return;
10659
10849
  }
@@ -10664,7 +10854,7 @@ async function runOp(sub, opts = {}, view) {
10664
10854
  case "billing": {
10665
10855
  const which = (view ?? "").trim().toLowerCase();
10666
10856
  if (which && which !== "doors" && which !== "meter") {
10667
- return void console.log(import_chalk51.default.red(`Unknown: apiblaze op billing ${which}. Use 'doors', 'meter', or neither for both.`));
10857
+ return void console.log(import_chalk52.default.red(`Unknown: apiblaze op billing ${which}. Use 'doors', 'meter', or neither for both.`));
10668
10858
  }
10669
10859
  const checks = [];
10670
10860
  let doorsData = null;
@@ -10725,29 +10915,29 @@ async function runOp(sub, opts = {}, view) {
10725
10915
  const data = await opCall({ method: "GET", path: `/operator/latency/grades${q}`, summary: "latency grades" });
10726
10916
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10727
10917
  const t = data.thresholds_ms;
10728
- console.log(import_chalk51.default.bold("\nHow good was apiblaze itself?") + import_chalk51.default.dim(" (our overhead only \u2014 a slow customer API never counts against us)"));
10729
- console.log(import_chalk51.default.dim(` excellent <${t.excellent.replace("<", "")}ms \xB7 okay ${t.okay}ms \xB7 bad ${t.bad}ms \xB7 terrible ${t.terrible.replace(">=", "")}ms+
10918
+ console.log(import_chalk52.default.bold("\nHow good was apiblaze itself?") + import_chalk52.default.dim(" (our overhead only \u2014 a slow customer API never counts against us)"));
10919
+ console.log(import_chalk52.default.dim(` excellent <${t.excellent.replace("<", "")}ms \xB7 okay ${t.okay}ms \xB7 bad ${t.bad}ms \xB7 terrible ${t.terrible.replace(">=", "")}ms+
10730
10920
  `));
10731
- console.log(import_chalk51.default.dim(" date reqs excellent okay bad terrible"));
10921
+ console.log(import_chalk52.default.dim(" date reqs excellent okay bad terrible"));
10732
10922
  for (const d of data.days ?? []) {
10733
10923
  const p = d.pct;
10734
- const cell = (v, colour) => v > 0 ? colour(`${String(v).padStart(5)}%`) : import_chalk51.default.dim(`${String(v).padStart(5)}%`);
10924
+ const cell = (v, colour) => v > 0 ? colour(`${String(v).padStart(5)}%`) : import_chalk52.default.dim(`${String(v).padStart(5)}%`);
10735
10925
  console.log(
10736
- ` ${d.date} ${String(d.total).padStart(5)} ${cell(p.excellent, import_chalk51.default.green)} ${cell(p.okay, import_chalk51.default.cyan)} ${cell(p.bad, import_chalk51.default.yellow)} ${cell(p.terrible, import_chalk51.default.red)}`
10926
+ ` ${d.date} ${String(d.total).padStart(5)} ${cell(p.excellent, import_chalk52.default.green)} ${cell(p.okay, import_chalk52.default.cyan)} ${cell(p.bad, import_chalk52.default.yellow)} ${cell(p.terrible, import_chalk52.default.red)}`
10737
10927
  );
10738
10928
  }
10739
10929
  const cul = data.culprits ?? [];
10740
10930
  if (cul.length) {
10741
- console.log(import_chalk51.default.bold("\n Who caused the bad and terrible ones\n"));
10742
- console.log(import_chalk51.default.dim(" bad terrible feature \u2192 dependency"));
10931
+ console.log(import_chalk52.default.bold("\n Who caused the bad and terrible ones\n"));
10932
+ console.log(import_chalk52.default.dim(" bad terrible feature \u2192 dependency"));
10743
10933
  for (const r of cul.slice(0, 12)) {
10744
10934
  if (!r.bad && !r.terrible) continue;
10745
10935
  console.log(
10746
- ` ${String(r.bad).padStart(6)} ${import_chalk51.default.red(String(r.terrible).padStart(8))} ${import_chalk51.default.yellow(r.feature)} ${import_chalk51.default.dim("\u2192")} ${import_chalk51.default.cyan(r.dep)}`
10936
+ ` ${String(r.bad).padStart(6)} ${import_chalk52.default.red(String(r.terrible).padStart(8))} ${import_chalk52.default.yellow(r.feature)} ${import_chalk52.default.dim("\u2192")} ${import_chalk52.default.cyan(r.dep)}`
10747
10937
  );
10748
10938
  }
10749
10939
  }
10750
- if (data.caveat) console.log(import_chalk51.default.dim(`
10940
+ if (data.caveat) console.log(import_chalk52.default.dim(`
10751
10941
  \u26A0 ${data.caveat}
10752
10942
  `));
10753
10943
  return;
@@ -10756,24 +10946,24 @@ async function runOp(sub, opts = {}, view) {
10756
10946
  const data = await opCall({ method: "GET", path: `/operator/latency/compare${q}`, summary: "latency before/after" });
10757
10947
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10758
10948
  const b = data.before, a = data.after, d = data.delta;
10759
- console.log(import_chalk51.default.bold(`
10760
- Before vs after: `) + import_chalk51.default.cyan(data.marker.label));
10761
- console.log(import_chalk51.default.dim(` marked ${new Date(data.marker.ts).toISOString()} \xB7 ${data.window_hours}h either side
10949
+ console.log(import_chalk52.default.bold(`
10950
+ Before vs after: `) + import_chalk52.default.cyan(data.marker.label));
10951
+ console.log(import_chalk52.default.dim(` marked ${new Date(data.marker.ts).toISOString()} \xB7 ${data.window_hours}h either side
10762
10952
  `));
10763
10953
  const row = (name, before, after, delta) => {
10764
10954
  const arrow = delta === 0 ? "=" : delta < 0 ? "\u2193" : "\u2191";
10765
10955
  const txt = `${String(before).padStart(6)}ms \u2192${String(after).padStart(7)}ms ${arrow}${Math.abs(delta)}ms`;
10766
- console.log(` ${name.padEnd(22)}${data.trustworthy ? delta <= 0 ? import_chalk51.default.green(txt) : import_chalk51.default.red(txt) : import_chalk51.default.dim(txt)}`);
10956
+ console.log(` ${name.padEnd(22)}${data.trustworthy ? delta <= 0 ? import_chalk52.default.green(txt) : import_chalk52.default.red(txt) : import_chalk52.default.dim(txt)}`);
10767
10957
  };
10768
- console.log(import_chalk51.default.dim(" metric before after change"));
10958
+ console.log(import_chalk52.default.dim(" metric before after change"));
10769
10959
  row("total p50", b.total_p50, a.total_p50, d.total_p50);
10770
10960
  row("total p95", b.total_p95, a.total_p95, d.total_p95);
10771
10961
  row("apiblaze overhead p50", b.gw_p50, a.gw_p50, d.gw_p50);
10772
10962
  row("apiblaze overhead p95", b.gw_p95, a.gw_p95, d.gw_p95);
10773
- console.log(import_chalk51.default.dim(`
10963
+ console.log(import_chalk52.default.dim(`
10774
10964
  requests: ${b.requests} before \xB7 ${a.requests} after`));
10775
10965
  for (const w of data.warnings ?? []) {
10776
- console.log((data.trustworthy ? import_chalk51.default.dim : import_chalk51.default.yellow)(` ${data.trustworthy ? "\xB7" : "\u26A0"} ${w}`));
10966
+ console.log((data.trustworthy ? import_chalk52.default.dim : import_chalk52.default.yellow)(` ${data.trustworthy ? "\xB7" : "\u26A0"} ${w}`));
10777
10967
  }
10778
10968
  console.log("");
10779
10969
  return;
@@ -10782,19 +10972,19 @@ Before vs after: `) + import_chalk51.default.cyan(data.marker.label));
10782
10972
  const data = await opCall({ method: "GET", path: `/operator/latency/slow${q}`, summary: "slowest requests" });
10783
10973
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10784
10974
  const rows2 = data?.rows ?? [];
10785
- if (!rows2.length) return void console.log(import_chalk51.default.dim("No requests over the threshold in that window."));
10786
- console.log(import_chalk51.default.bold(`
10975
+ if (!rows2.length) return void console.log(import_chalk52.default.dim("No requests over the threshold in that window."));
10976
+ console.log(import_chalk52.default.bold(`
10787
10977
  Slowest requests \u2014 last ${data.window_hours}h, over ${data.min_ms}ms
10788
10978
  `));
10789
- console.log(import_chalk51.default.dim(" total ours theirs blame request id"));
10979
+ console.log(import_chalk52.default.dim(" total ours theirs blame request id"));
10790
10980
  for (const r of rows2.slice(0, 30)) {
10791
10981
  console.log(
10792
- ` ${String(Math.round(r.duration_ms)).padStart(6)} ${String(Math.round(r.gateway_ms)).padStart(5)} ${String(Math.round(r.upstream_ttfb_ms)).padStart(6)} ${import_chalk51.default.yellow(`${r.slow_gw_feature || "-"}\u2192${r.slow_dep || "-"}`.padEnd(20))} ${import_chalk51.default.dim(r.request_id || "")}`
10982
+ ` ${String(Math.round(r.duration_ms)).padStart(6)} ${String(Math.round(r.gateway_ms)).padStart(5)} ${String(Math.round(r.upstream_ttfb_ms)).padStart(6)} ${import_chalk52.default.yellow(`${r.slow_gw_feature || "-"}\u2192${r.slow_dep || "-"}`.padEnd(20))} ${import_chalk52.default.dim(r.request_id || "")}`
10793
10983
  );
10794
10984
  }
10795
- console.log(import_chalk51.default.dim(`
10985
+ console.log(import_chalk52.default.dim(`
10796
10986
  The last column is the request id (Cloudflare calls it a "cf-ray"). Look one up with`));
10797
- console.log(import_chalk51.default.dim(` \`apiblaze logs\` for that request's exact per-feature breakdown \u2014 unsampled, unlike the table above.
10987
+ console.log(import_chalk52.default.dim(` \`apiblaze logs\` for that request's exact per-feature breakdown \u2014 unsampled, unlike the table above.
10798
10988
  `));
10799
10989
  return;
10800
10990
  }
@@ -10802,18 +10992,18 @@ Slowest requests \u2014 last ${data.window_hours}h, over ${data.min_ms}ms
10802
10992
  const data = await opCall({ method: "GET", path: `/operator/latency/llm${q}`, summary: "llm latency" });
10803
10993
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10804
10994
  const rows2 = data?.rows ?? [];
10805
- if (!rows2.length) return void console.log(import_chalk51.default.dim("No LLM traffic in that window."));
10806
- console.log(import_chalk51.default.bold(`
10995
+ if (!rows2.length) return void console.log(import_chalk52.default.dim("No LLM traffic in that window."));
10996
+ console.log(import_chalk52.default.bold(`
10807
10997
  LLM timing \u2014 last ${data.window_hours}h
10808
10998
  `));
10809
- console.log(import_chalk51.default.dim(" turns turn p95 ttfc p95 gen p95 reserve p95 in/out tokens p95 model"));
10999
+ console.log(import_chalk52.default.dim(" turns turn p95 ttfc p95 gen p95 reserve p95 in/out tokens p95 model"));
10810
11000
  for (const r of rows2) {
10811
11001
  const n = r.turns ?? r.requests ?? 0;
10812
11002
  console.log(
10813
11003
  ` ${String(Math.round(n)).padStart(8)} ${String(Math.round(r.turn_p95_ms ?? 0)).padStart(6)}ms ${String(Math.round(r.ttfc_p95_ms ?? 0)).padStart(6)}ms ${String(Math.round(r.gen_p95_ms ?? 0)).padStart(6)}ms ${String(Math.round(r.reserve_p95_ms ?? 0)).padStart(9)}ms ${String(Math.round(r.input_tokens_p95 ?? 0)).padStart(6)}/${String(Math.round(r.output_tokens_p95 ?? 0)).padEnd(6)} ${r.model || "-"}`
10814
11004
  );
10815
11005
  }
10816
- console.log(import_chalk51.default.dim(`
11006
+ console.log(import_chalk52.default.dim(`
10817
11007
  ${data.note}
10818
11008
  `));
10819
11009
  return;
@@ -10824,26 +11014,26 @@ LLM timing \u2014 last ${data.window_hours}h
10824
11014
  ]);
10825
11015
  if (opts.json) return void console.log(JSON.stringify({ blame, summary }, null, 2));
10826
11016
  const ov = summary?.apiblaze_overhead_ms ?? {};
10827
- console.log(import_chalk51.default.bold(`
11017
+ console.log(import_chalk52.default.bold(`
10828
11018
  Latency \u2014 last ${summary?.window_hours ?? "?"}h, ${Number(summary?.requests ?? 0).toLocaleString()} requests
10829
11019
  `));
10830
- console.log(` ${import_chalk51.default.bold("apiblaze overhead")} p50 ${String(ov.p50 ?? 0).padStart(5)}ms p95 ${String(ov.p95 ?? 0).padStart(6)}ms p99 ${String(ov.p99 ?? 0).padStart(6)}ms ${import_chalk51.default.dim("\u2190 ours")}`);
10831
- console.log(` ${import_chalk51.default.bold("upstream ttfb ")} ${" ".repeat(24)}p95 ${String(summary?.upstream_ttfb_p95_ms ?? 0).padStart(6)}ms ${import_chalk51.default.dim("\u2190 theirs")}`);
10832
- console.log(import_chalk51.default.dim(` (per-request percentiles \u2014 never subtract one from the other)
11020
+ console.log(` ${import_chalk52.default.bold("apiblaze overhead")} p50 ${String(ov.p50 ?? 0).padStart(5)}ms p95 ${String(ov.p95 ?? 0).padStart(6)}ms p99 ${String(ov.p99 ?? 0).padStart(6)}ms ${import_chalk52.default.dim("\u2190 ours")}`);
11021
+ console.log(` ${import_chalk52.default.bold("upstream ttfb ")} ${" ".repeat(24)}p95 ${String(summary?.upstream_ttfb_p95_ms ?? 0).padStart(6)}ms ${import_chalk52.default.dim("\u2190 theirs")}`);
11022
+ console.log(import_chalk52.default.dim(` (per-request percentiles \u2014 never subtract one from the other)
10833
11023
  `));
10834
11024
  const rows = blame?.blame ?? [];
10835
- if (!rows.length) return void console.log(import_chalk51.default.dim("No latency rows in that window."));
10836
- console.log(import_chalk51.default.bold(" Which feature ate the time, and what inside it\n"));
10837
- console.log(import_chalk51.default.dim(" share p95 feature \u2192 dependency"));
11025
+ if (!rows.length) return void console.log(import_chalk52.default.dim("No latency rows in that window."));
11026
+ console.log(import_chalk52.default.bold(" Which feature ate the time, and what inside it\n"));
11027
+ console.log(import_chalk52.default.dim(" share p95 feature \u2192 dependency"));
10838
11028
  for (const r of rows.slice(0, 15)) {
10839
11029
  const share = `${(r.share * 100).toFixed(1)}%`;
10840
- console.log(` ${share.padStart(6)} ${String(r.p95_ms).padStart(6)}ms ${import_chalk51.default.yellow(r.feature)} ${import_chalk51.default.dim("\u2192")} ${import_chalk51.default.cyan(r.dep)}`);
11030
+ console.log(` ${share.padStart(6)} ${String(r.p95_ms).padStart(6)}ms ${import_chalk52.default.yellow(r.feature)} ${import_chalk52.default.dim("\u2192")} ${import_chalk52.default.cyan(r.dep)}`);
10841
11031
  }
10842
11032
  console.log("");
10843
11033
  return;
10844
11034
  }
10845
11035
  default:
10846
- console.log(import_chalk51.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
11036
+ console.log(import_chalk52.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
10847
11037
  }
10848
11038
  }
10849
11039
 
@@ -10876,7 +11066,7 @@ program.command("login").description("Authenticate with APIblaze").option("--tea
10876
11066
  process.exit(1);
10877
11067
  }
10878
11068
  });
10879
- program.command("create").description("Create a new API proxy (no login needed \u2014 without auth it creates an anonymous proxy and prints a claim URL)").option("--name <name>", "Proxy name (becomes <name>.abz.run)").option("--target <url>", "Target URL to forward requests to").option("--openapi <file|url>", "Create FROM an OpenAPI spec instead of --target \u2014 a local file or a URL (e.g. https://pokeapi.co/openapi.yaml). Routes, API version and environments (one per `servers` entry) all come from the spec").option("--openapispec <file|url>", "Alias for --openapi").option("--team <id|name>", "Team to create under (defaults to your active team)").option("--auth <type>", "Auth type: api_key | none | oauth", "api_key").option("--apikey", "Protect with API keys and print the bootstrap keys (the default, made explicit). Consumers send X-API-Key.").option("--oauth [config]", `Login door. Bare = APIblaze-hosted GitHub sign-in. '{"iss","aud","jwks"}' = trust YOUR hosted login's JWTs. '{"provider","clientId","clientSecret"}' = APIblaze-hosted login page with YOUR OAuth app (github \xB7 google \xB7 microsoft \xB7 facebook \xB7 auth0).`).option("--identified", "Require every call to identify its end user (X-End-User-Id or a login token); unattributed calls are rejected").option("--iam", "Turn IAM on for the proxy's tenant so users & groups apply to identified calls").option("--apiversion <version>", "API version to create (e.g. 2.0.0). Creating a new version of a proxy you own adds a version to the existing project.").option("--tenant <slug>", "Tenant to attach the proxy to (created if new). Omitted \u2192 your team's most-recently-used tenant.").option("--product <slug>", "Product tag to group this project under in the portal (team-scoped; anonymous create). Defaults to your team's existing/placeholder tag.").option("--display-name <name>", "Human-friendly display name").option("--subdomain <slug>", "Explicit subdomain (defaults to --name)").option("--config <file>", "JSON file with the full request body (anonymous create): requests_auth, login providers + client/server token types, scopes, callback URLs, etc. See apiblaze_anonymous.yaml. Flags override its fields.").option("-y, --yes", "Skip the confirmation prompt").option("--new-session", "Start a fresh anonymous session (do not group with prior anonymous creates)").option("--json", "Output machine-readable JSON (non-interactive)").action(async (opts) => {
11069
+ program.command("create").description("Create a new API proxy (no login needed \u2014 without auth it creates an anonymous proxy and prints a claim URL)").option("--name <name>", "Proxy name (becomes <name>.abz.run)").option("--target <url|file>", "What to proxy \u2014 pass ANY of: a target server base URL (https://httpbin.org), a local OpenAPI file (./openapi.yaml), or a remote OpenAPI URL (https://acme.com/openapi.yaml). Spec inputs are detected automatically; routes, API version and environments then come from the spec").addOption(new import_commander.Option("--openapi <file|url>", "Deprecated alias \u2014 --target now detects spec files/URLs itself").hideHelp()).addOption(new import_commander.Option("--openapispec <file|url>", "Deprecated alias for --openapi").hideHelp()).option("--team <id|name>", "Team to create under (defaults to your active team)").option("--auth <type>", "Auth type: api_key | none | oauth", "api_key").option("--apikey", "Protect with API keys and print the bootstrap keys (the default, made explicit). Consumers send X-API-Key.").option("--oauth [config]", `Login door. Bare = APIblaze-hosted GitHub sign-in. '{"iss","aud","jwks"}' = trust YOUR hosted login's JWTs. '{"provider","clientId","clientSecret"}' = APIblaze-hosted login page with YOUR OAuth app (github \xB7 google \xB7 microsoft \xB7 facebook \xB7 auth0).`).option("--identified", "Require every call to identify its end user (X-End-User-Id or a login token); unattributed calls are rejected").option("--iam", "Turn IAM on for the proxy's tenant so users & groups apply to identified calls").option("--apiversion <version>", "API version to create (e.g. 2.0.0). Creating a new version of a proxy you own adds a version to the existing project.").option("--tenant <slug>", "Tenant to attach the proxy to (created if new). Omitted \u2192 your team's most-recently-used tenant.").option("--product <slug>", "Product tag to group this project under in the portal (team-scoped; anonymous create). Defaults to your team's existing/placeholder tag.").option("--display-name <name>", "Human-friendly display name").option("--subdomain <slug>", "Explicit subdomain (defaults to --name)").option("--config <file>", "JSON file with the full request body (anonymous create): requests_auth, login providers + client/server token types, scopes, callback URLs, etc. See apiblaze_anonymous.yaml. Flags override its fields.").option("-y, --yes", "Skip the confirmation prompt").option("--new-session", "Start a fresh anonymous session (do not group with prior anonymous creates)").option("--json", "Output machine-readable JSON (non-interactive)").action(async (opts) => {
10880
11070
  try {
10881
11071
  await runCreate({ ...opts, openapi: opts.openapi ?? opts.openapispec });
10882
11072
  } catch (err) {
@@ -10889,7 +11079,7 @@ agent.command("authz").description("Chat to design and turn on access rules for
10889
11079
  program.command("rule").description("Author an object-level access rule in plain English, in one shot (billed per turn)").argument("<rule>", 'The rule in plain English, e.g. "users see only their own rows"').argument("<project>", "Project name or id").option("--enforce", "Turn enforcement on immediately (default: shadow-publish only)").option("--apiversion <version>", "API version (defaults to the project's)").action(action((rule, project, opts) => runRule(rule, project, opts)));
10890
11080
  agent.command("openapi").description("Chat to build your API spec from real traffic").argument("<project>", "Project name or id").argument("[apiVersion]", "API version (defaults to the project's)").action(action((project, apiVersion) => runOpenapi(project, apiVersion)));
10891
11081
  agent.command("mcp").description("Chat to build an MCP server for an API").argument("<project>", "Project name or id").argument("[apiVersion]", "API version (defaults to the project's)").option("--environment <env>", "Environment to publish (default: prod)").action(action((project, apiVersion, opts) => runMcp(project, apiVersion, opts)));
10892
- program.command("apichat [project]").description("Turn any API into a chat: point at an OpenAPI spec \u2014 or chat an EXISTING proxy by name (no login needed)").option("--openapi <file|url>", "OpenAPI/Swagger spec to build from (JSON or YAML; file path or URL)").option("--openapispec <file|url>", "Alias for --openapi").option("--target <url>", "Upstream base URL (overrides servers[0].url; enables spec discovery when --openapi is omitted)").option("--name <name>", "Proxy name (defaults to the target host)").option("--apiversion <version>", "API version to create (e.g. 1.0.0)").option("--environment <env>", "Environment to chat against (default: prod anonymous / dev logged-in)").option("--access <mode>", 'Who can call this API once connected (e.g. via Claude): "open" = anyone who signs in, "invite" = only you + emails you pre-approve. Default: invite when logged in, open when anonymous.').option("--target-auth-env <ENV_VAR>", "Read the upstream credential from this env var (CI-safe; required when there is no TTY and the API needs auth)").option("--force", "Proceed even if the API uses oauth2/openIdConnect target auth (you configure target auth yourself later)").option("-y, --yes", "Skip confirmation prompts").option("--tenant <slug>", "Tenant (consumer namespace: portal, login, users) for the new proxy; omit to be asked").option("--apikey <key>", "Use this API key for the proxy's door (api_key proxies). Without it, apichat detects the door and asks \u2014 or runs the consumer login for OAuth doors.").option("--xenduserid <id>", "Assert this end-user id (X-End-User-Id) \u2014 required by proxies with identified/pre-approved enforcement; you are asked for one when the proxy demands it.").option("--no-verbose", "Hide the per-turn proxy curl trace (shown by default for apichat)").action(action((project, opts) => runApichat({ ...opts, project, openapispec: opts.openapispec ?? opts.openapi })));
11082
+ program.command("apichat [project]").description("Turn any API into a chat: point at an OpenAPI spec \u2014 or chat an EXISTING proxy by name (no login needed)").option("--target <url|file>", "What to chat with \u2014 pass ANY of: a target server base URL (spec auto-discovered at /openapi.json etc.), a local OpenAPI file (./openapi.yaml), or a remote OpenAPI URL (https://acme.com/openapi.yaml)").addOption(new import_commander.Option("--openapi <file|url>", "Deprecated alias \u2014 --target now detects spec files/URLs itself").hideHelp()).addOption(new import_commander.Option("--openapispec <file|url>", "Deprecated alias for --openapi").hideHelp()).option("--name <name>", "Proxy name (defaults to the target host)").option("--apiversion <version>", "API version to create (e.g. 1.0.0)").option("--environment <env>", "Environment to chat against (default: prod anonymous / dev logged-in)").option("--access <mode>", 'Who can call this API once connected (e.g. via Claude): "open" = anyone who signs in, "invite" = only you + emails you pre-approve. Default: invite when logged in, open when anonymous.').option("--target-auth-env <ENV_VAR>", "Read the upstream credential from this env var (CI-safe; required when there is no TTY and the API needs auth)").option("--force", "Proceed even if the API uses oauth2/openIdConnect target auth (you configure target auth yourself later)").option("-y, --yes", "Skip confirmation prompts").option("--tenant <slug>", "Tenant (consumer namespace: portal, login, users) for the new proxy; omit to be asked").option("--apikey <key>", "Use this API key for the proxy's door (api_key proxies). Without it, apichat detects the door and asks \u2014 or runs the consumer login for OAuth doors.").option("--xenduserid <id>", "Assert this end-user id (X-End-User-Id) \u2014 required by proxies with identified/pre-approved enforcement; you are asked for one when the proxy demands it.").option("--no-verbose", "Hide the per-turn proxy curl trace (shown by default for apichat)").option("-p, --prompt <question>", "One-shot question piped through the external agent CLI after the MCP install (used with --install-mcp or the install offer)").option("--install-mcp <cli>", "Install this proxy's MCP into an external agent CLI without asking: claude | codex. Also re-offers after an earlier decline.").action(action((project, opts) => runApichat({ ...opts, project, openapispec: opts.openapispec ?? opts.openapi })));
10893
11083
  var llm = program.command("llm").description("Manage a local LLM provider key for chat (optional \u2014 lifts model quality, bills your key)");
10894
11084
  llm.command("set-key").description("Store an LLM provider key locally (OpenRouter/Anthropic/DeepSeek/OpenAI)").argument("[key]", "The API key (omit to enter it hidden at a prompt)").option("--model <id>", "Model id to use with this key (e.g. anthropic/claude-haiku-4.5)").action(action((key, opts) => runLlmSetKey(key, opts)));
10895
11085
  llm.command("show").description("Show the locally stored LLM key (masked)").action(action(() => runLlmShow()));
@@ -10906,7 +11096,7 @@ program.command("dev").description("Put your localhost behind a public URL (dev
10906
11096
  try {
10907
11097
  const resolved = parseInt(port ?? opts.port, 10);
10908
11098
  if (Number.isNaN(resolved)) {
10909
- console.error(import_chalk52.default.red(`Invalid port: ${port ?? opts.port}`));
11099
+ console.error(import_chalk53.default.red(`Invalid port: ${port ?? opts.port}`));
10910
11100
  process.exit(1);
10911
11101
  }
10912
11102
  await runDev({ port: resolved, project: opts.project, yes: opts.yes, captureFile: opts.captureFile, newSession: opts.newSession });
@@ -11038,7 +11228,7 @@ function groupedCommandHelp() {
11038
11228
  const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
11039
11229
  return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
11040
11230
  }).filter(Boolean).join("\n");
11041
- return `${import_chalk52.default.bold(g.title)}
11231
+ return `${import_chalk53.default.bold(g.title)}
11042
11232
  ${rows}`;
11043
11233
  }).join("\n\n");
11044
11234
  }
@@ -11076,14 +11266,14 @@ async function recoverStaleTeam() {
11076
11266
  const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
11077
11267
  const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
11078
11268
  if (!linked) {
11079
- console.error(import_chalk52.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
11269
+ console.error(import_chalk53.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
11080
11270
  return;
11081
11271
  }
11082
11272
  if (linked.teamId === creds.teamId) return;
11083
11273
  const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
11084
11274
  delete next.activeTenant;
11085
11275
  saveCredentials(next);
11086
- console.error(import_chalk52.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk52.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
11276
+ console.error(import_chalk53.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk53.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
11087
11277
  } catch {
11088
11278
  }
11089
11279
  }
@@ -11091,16 +11281,16 @@ async function printError(err) {
11091
11281
  if (err instanceof ApiError) {
11092
11282
  const data = err.body;
11093
11283
  const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
11094
- console.error(import_chalk52.default.red(`
11284
+ console.error(import_chalk53.default.red(`
11095
11285
  API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
11096
11286
  if (err.status === 403 || err.status === 404) {
11097
11287
  await recoverStaleTeam();
11098
11288
  }
11099
11289
  } else if (err instanceof Error) {
11100
- console.error(import_chalk52.default.red(`
11290
+ console.error(import_chalk53.default.red(`
11101
11291
  Error: ${err.message}`));
11102
11292
  } else {
11103
- console.error(import_chalk52.default.red("\nUnknown error"));
11293
+ console.error(import_chalk53.default.red("\nUnknown error"));
11104
11294
  }
11105
11295
  }
11106
11296
  program.parse(process.argv);