apiblaze 0.20.10 → 0.20.13

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 +753 -365
  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.13";
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,238 @@ 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 useShell = process.platform === "win32";
8364
+ var winQuote = (a) => /^[A-Za-z0-9_\-.:/\\=]+$/.test(a) ? a : `"${a.replace(/"/g, '""')}"`;
8365
+ var run = (cmd, args, opts = {}) => (0, import_child_process2.spawnSync)(cmd, useShell ? args.map(winQuote) : args, {
8366
+ encoding: "utf-8",
8367
+ stdio: opts.interactive ? ["inherit", "inherit", "inherit"] : opts.inherit ? ["ignore", "inherit", "inherit"] : ["ignore", "pipe", "pipe"],
8368
+ timeout: opts.inherit || opts.interactive ? void 0 : 15e3,
8369
+ shell: useShell
8370
+ });
8371
+ var detected = null;
8372
+ function detectExternalClis() {
8373
+ if (detected) return detected;
8374
+ const found = [];
8375
+ for (const [kind, label3] of [["claude", "Claude CLI"], ["codex", "Codex CLI"]]) {
8376
+ try {
8377
+ const r = run(kind, ["--version"]);
8378
+ if (r.status === 0) found.push({ kind, label: label3, version: (r.stdout || "").trim().split("\n")[0] || void 0 });
8379
+ } catch {
8380
+ }
8381
+ }
8382
+ detected = found;
8383
+ return found;
8384
+ }
8385
+ var OURS = /\.mcp\.(abz\.run|tryabz\.run|apiblaze\.com)\b/;
8386
+ var mask = (k) => k.length > 14 ? `${k.slice(0, 10)}\u2026${k.slice(-4)}` : "\u2022\u2022\u2022";
8387
+ async function verifyMcpEndpoint(spec2) {
8388
+ try {
8389
+ const headers = { "Content-Type": "application/json" };
8390
+ if (spec2.apiKey) headers["X-API-Key"] = spec2.apiKey;
8391
+ if (spec2.endUserId) headers["X-End-User-Id"] = spec2.endUserId;
8392
+ const res = await fetch(spec2.url, {
8393
+ method: "POST",
8394
+ headers,
8395
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list" }),
8396
+ signal: AbortSignal.timeout(1e4)
8397
+ });
8398
+ if (!res.ok) return { ok: false, status: res.status, tools: 0 };
8399
+ const body = await res.json().catch(() => null);
8400
+ if (!spec2.apiKey) return { ok: true, status: res.status, tools: body?.result?.tools?.length ?? 0 };
8401
+ if (body?.error) return { ok: false, status: res.status, tools: 0 };
8402
+ return { ok: true, status: res.status, tools: body?.result?.tools?.length ?? 0 };
8403
+ } catch {
8404
+ return { ok: false, status: 0, tools: 0 };
8405
+ }
8406
+ }
8407
+ function claudeInstallArgs(spec2, masked = false) {
8408
+ const args = ["mcp", "add", "--transport", "http", spec2.name, spec2.url];
8409
+ if (spec2.apiKey) args.push("--header", `X-API-Key: ${masked ? mask(spec2.apiKey) : spec2.apiKey}`);
8410
+ if (spec2.endUserId) args.push("--header", `X-End-User-Id: ${spec2.endUserId}`);
8411
+ return args;
8412
+ }
8413
+ function installIntoClaude(spec2) {
8414
+ const existing = run("claude", ["mcp", "get", spec2.name]);
8415
+ if (existing.status === 0) {
8416
+ const desc = existing.stdout || "";
8417
+ if (!OURS.test(desc)) {
8418
+ return {
8419
+ ok: false,
8420
+ conflict: true,
8421
+ error: `Claude CLI already has an MCP server named "${spec2.name}" that is not an APIblaze proxy \u2014 not touching it. Remove or rename it (claude mcp remove ${spec2.name}) and re-run.`
8422
+ };
8423
+ }
8424
+ run("claude", ["mcp", "remove", spec2.name]);
8425
+ }
8426
+ const r = run("claude", claudeInstallArgs(spec2));
8427
+ if (r.status === 0) return { ok: true };
8428
+ return { ok: false, error: (r.stderr || r.stdout || `exit ${r.status}`).trim().slice(0, 400) };
8429
+ }
8430
+ function claudeOneShot(spec2, prompt) {
8431
+ const argv = ["claude", "-p", prompt, "--allowedTools", `mcp__${spec2.name}__*`];
8432
+ const r = run(argv[0], argv.slice(1), { inherit: true });
8433
+ return { argv, status: r.status };
8434
+ }
8435
+ function codexConfigPath() {
8436
+ return path6.join(process.env.CODEX_HOME || path6.join(os4.homedir(), ".codex"), "config.toml");
8437
+ }
8438
+ var tomlStr = (s) => `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
8439
+ function codexServerBlock(spec2) {
8440
+ const lines = [`[mcp_servers.${tomlStr(spec2.name)}]`, `url = ${tomlStr(spec2.url)}`];
8441
+ const headers = [];
8442
+ if (spec2.apiKey) headers.push(`"X-API-Key" = ${tomlStr(spec2.apiKey)}`);
8443
+ if (spec2.endUserId) headers.push(`"X-End-User-Id" = ${tomlStr(spec2.endUserId)}`);
8444
+ if (headers.length) lines.push(`http_headers = { ${headers.join(", ")} }`);
8445
+ return lines.join("\n") + "\n";
8446
+ }
8447
+ function codexSectionRanges(lines, name) {
8448
+ const esc = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8449
+ const header = new RegExp(`^\\[mcp_servers\\.(?:"${esc}"|${esc})\\]\\s*(#.*)?$`);
8450
+ const anyHeader = /^\s*\[[^\]]+\]\s*(#.*)?$/;
8451
+ const ranges = [];
8452
+ for (let i = 0; i < lines.length; i++) {
8453
+ if (!header.test(lines[i])) continue;
8454
+ let end = lines.length;
8455
+ for (let j = i + 1; j < lines.length; j++) {
8456
+ if (anyHeader.test(lines[j])) {
8457
+ end = j;
8458
+ break;
8459
+ }
8460
+ }
8461
+ ranges.push({ start: i, end });
8462
+ i = end - 1;
8463
+ }
8464
+ return ranges;
8465
+ }
8466
+ function installIntoCodex(spec2) {
8467
+ const file = codexConfigPath();
8468
+ try {
8469
+ fs10.mkdirSync(path6.dirname(file), { recursive: true });
8470
+ let text = "";
8471
+ let existed = true;
8472
+ try {
8473
+ text = fs10.readFileSync(file, "utf-8");
8474
+ } catch {
8475
+ existed = false;
8476
+ }
8477
+ const lines = text.split("\n");
8478
+ const ranges = codexSectionRanges(lines, spec2.name);
8479
+ for (const r of ranges) {
8480
+ const body = lines.slice(r.start, r.end).join("\n");
8481
+ const url = body.match(/^\s*url\s*=\s*"([^"]*)"/m)?.[1];
8482
+ if (url && !OURS.test(url) || !url && /^\s*command\s*=/m.test(body)) {
8483
+ return {
8484
+ ok: false,
8485
+ conflict: true,
8486
+ path: file,
8487
+ error: `~/.codex/config.toml already has an MCP server named "${spec2.name}" that is not an APIblaze proxy \u2014 not touching it. Rename or remove that block and re-run.`
8488
+ };
8489
+ }
8490
+ }
8491
+ for (const r of [...ranges].reverse()) lines.splice(r.start, r.end - r.start);
8492
+ let cleaned = lines.join("\n");
8493
+ if (cleaned.length && !cleaned.endsWith("\n")) cleaned += "\n";
8494
+ if (cleaned.length && !cleaned.endsWith("\n\n")) cleaned += "\n";
8495
+ const tmp = `${file}.tmp-${process.pid}`;
8496
+ fs10.writeFileSync(tmp, cleaned + codexServerBlock(spec2), { encoding: "utf-8", mode: 384 });
8497
+ fs10.renameSync(tmp, file);
8498
+ if (!existed) {
8499
+ try {
8500
+ fs10.chmodSync(file, 384);
8501
+ } catch {
8502
+ }
8503
+ }
8504
+ return { ok: true, path: file };
8505
+ } catch (err) {
8506
+ return { ok: false, error: err instanceof Error ? err.message : String(err), path: file };
8507
+ }
8508
+ }
8509
+ function codexOneShot(_spec, prompt) {
8510
+ const argv = ["codex", "exec", prompt];
8511
+ const r = run(argv[0], argv.slice(1), { inherit: true });
8512
+ return { argv, status: r.status };
8513
+ }
8514
+ var shellQuote = (s) => `"${s.replace(/(["\\$`])/g, "\\$1")}"`;
8515
+ function renderCommand(argv) {
8516
+ return argv.map((a, i) => i === 0 || /^[A-Za-z0-9_@%+=:,./-]+$/.test(a) ? a : shellQuote(a)).join(" ");
8517
+ }
8518
+ function refreshInstall(cli, spec2) {
8519
+ const r = cli === "claude" ? installIntoClaude(spec2) : installIntoCodex(spec2);
8520
+ return r.ok;
8521
+ }
8522
+ async function installAndDemo(cli, spec2, getQuestion, log = console.log) {
8523
+ if (cli.kind === "claude") {
8524
+ log(`
8525
+ ${import_chalk46.default.dim("$")} ${renderCommand(["claude", ...claudeInstallArgs(spec2, true)])}`);
8526
+ const r = installIntoClaude(spec2);
8527
+ if (!r.ok) {
8528
+ log(import_chalk46.default.red(` ${r.conflict ? "" : "Install failed: "}${r.error}`));
8529
+ return false;
8530
+ }
8531
+ log(` ${import_chalk46.default.green("\u2714")} MCP ${import_chalk46.default.bold(spec2.name)} added to Claude CLI (local scope \u2014 this directory).`);
8532
+ if (spec2.apiKey) log(import_chalk46.default.dim(" The API key is stored in Claude's local MCP config for this directory."));
8533
+ } else {
8534
+ const r = installIntoCodex(spec2);
8535
+ if (!r.ok) {
8536
+ log(import_chalk46.default.red(` ${r.conflict ? "" : `Could not write ${r.path}: `}${r.error}`));
8537
+ return false;
8538
+ }
8539
+ log(` ${import_chalk46.default.green("\u2714")} MCP ${import_chalk46.default.bold(spec2.name)} added to ${r.path}.`);
8540
+ }
8541
+ if (!spec2.apiKey) {
8542
+ const loginArgv = cli.kind === "claude" ? ["claude", "mcp", "login", spec2.name] : ["codex", "mcp", "login", spec2.name];
8543
+ log(`
8544
+ ${import_chalk46.default.dim("This proxy authenticates by login \u2014 signing you in:")}`);
8545
+ log(` ${import_chalk46.default.dim("$")} ${renderCommand(loginArgv)}`);
8546
+ const r = run(loginArgv[0], loginArgv.slice(1), { interactive: true });
8547
+ if (r.status !== 0) {
8548
+ log(import_chalk46.default.yellow(` Sign-in didn't complete (exit ${r.status ?? "?"}). Run \`${renderCommand(loginArgv)}\` yourself, then chat away.`));
8549
+ return true;
8550
+ }
8551
+ log(` ${import_chalk46.default.green("\u2714")} Signed in.`);
8552
+ }
8553
+ const oneShot = cli.kind === "claude" ? claudeOneShot : codexOneShot;
8554
+ const abilities = `What are the tool abilities of the MCP server "${spec2.name}"? List them briefly.`;
8555
+ log(`
8556
+ ${import_chalk46.default.dim("Checking what the API can do\u2026")}`);
8557
+ log(` ${import_chalk46.default.dim("$")} ${renderCommand(cli.kind === "claude" ? ["claude", "-p", abilities, "--allowedTools", `mcp__${spec2.name}__*`] : ["codex", "exec", abilities])}
8558
+ `);
8559
+ const check = oneShot(spec2, abilities);
8560
+ if (check.status !== 0) {
8561
+ log(import_chalk46.default.yellow(`
8562
+ ${cli.label} exited with ${check.status ?? "no status"} \u2014 the MCP is installed, but the demo call failed.`));
8563
+ log(import_chalk46.default.yellow(` Open ${cli.label} and try it there${cli.kind === "claude" ? " (use /mcp to inspect the connection)" : ""}.`));
8564
+ return true;
8565
+ }
8566
+ const question = await getQuestion();
8567
+ if (question) {
8568
+ log(`
8569
+ ${import_chalk46.default.dim("Your question, through " + cli.label + ":")}`);
8570
+ const shown = cli.kind === "claude" ? ["claude", "-p", question, "--allowedTools", `mcp__${spec2.name}__*`] : ["codex", "exec", question];
8571
+ log(` ${import_chalk46.default.dim("$")} ${renderCommand(shown)}
8572
+ `);
8573
+ const ans = oneShot(spec2, question);
8574
+ if (ans.status !== 0) log(import_chalk46.default.yellow(`
8575
+ ${cli.label} exited with ${ans.status ?? "no status"} on that one \u2014 the MCP stays installed.`));
8576
+ }
8577
+ log(`
8578
+ ${import_chalk46.default.bold(`Your ${cli.label} is now able to talk to the ${spec2.projectLabel} API.`)}`);
8579
+ return true;
8580
+ }
8581
+
8582
+ // src/commands/apichat.ts
8356
8583
  init_types();
8357
8584
  function fail4(message, hint) {
8358
- console.error(import_chalk46.default.red(`
8585
+ console.error(import_chalk47.default.red(`
8359
8586
  Error: ${message}`));
8360
- if (hint) console.error(import_chalk46.default.dim(hint));
8587
+ if (hint) console.error(import_chalk47.default.dim(hint));
8361
8588
  process.exit(1);
8362
8589
  }
8363
8590
  function normalizeName3(raw) {
@@ -8388,7 +8615,7 @@ function parseSpec(text) {
8388
8615
  }
8389
8616
  return parsed;
8390
8617
  }
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>";
8618
+ 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
8619
  async function fetchText(url) {
8393
8620
  try {
8394
8621
  const res = await fetch(url, { headers: { accept: "application/json, application/yaml, text/yaml, */*" } });
@@ -8421,7 +8648,7 @@ async function loadSpec(opts) {
8421
8648
  }
8422
8649
  let text;
8423
8650
  try {
8424
- text = fs10.readFileSync(opts.openapispec, "utf-8");
8651
+ text = fs11.readFileSync(opts.openapispec, "utf-8");
8425
8652
  } catch {
8426
8653
  fail4(`Cannot read spec file: ${opts.openapispec}`);
8427
8654
  }
@@ -8435,7 +8662,7 @@ async function loadSpec(opts) {
8435
8662
  }
8436
8663
  return { spec: found.spec, sourceUrl: found.sourceUrl };
8437
8664
  }
8438
- fail4("No spec source. Pass --openapispec <file|url> or --target <url>.", GENERATOR_HINT);
8665
+ fail4("No spec source. Pass --target <server-url | openapi-file | openapi-url>.", GENERATOR_HINT);
8439
8666
  }
8440
8667
  function resolveTarget(spec2, opts, sourceUrl) {
8441
8668
  if (opts.target) {
@@ -8505,7 +8732,7 @@ async function resolveTargetAuth(spec2, opts) {
8505
8732
  "Re-run with --force to provision anyway (configure target auth later with `apiblaze config`),\nor use an api_key / bearer / basic scheme."
8506
8733
  );
8507
8734
  }
8508
- if (sawOAuth) console.log(import_chalk46.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
8735
+ if (sawOAuth) console.log(import_chalk47.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
8509
8736
  return null;
8510
8737
  }
8511
8738
  if (candidates.length === 1 && !noneAllowed) return candidates[0];
@@ -8579,7 +8806,7 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
8579
8806
  const fresh = await validConsumerToken(existing);
8580
8807
  if (fresh) {
8581
8808
  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})` : ""}.`));
8809
+ console.log(import_chalk47.default.dim(` Using your consumer session on ${import_chalk47.default.bold(tenant2)}${fresh.email ? ` (${fresh.email})` : ""}.`));
8583
8810
  return fresh;
8584
8811
  }
8585
8812
  }
@@ -8598,13 +8825,13 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
8598
8825
  );
8599
8826
  }
8600
8827
  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)}...`);
8828
+ 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
8829
  const result = await deviceLogin(clientId, "openid email profile offline_access", ({ verificationUri, userCode }) => {
8603
8830
  console.log(`
8604
- Open: ${import_chalk46.default.underline(verificationUri)}`);
8605
- console.log(` Code: ${import_chalk46.default.bold(userCode)}
8831
+ Open: ${import_chalk47.default.underline(verificationUri)}`);
8832
+ console.log(` Code: ${import_chalk47.default.bold(userCode)}
8606
8833
  `);
8607
- console.log(import_chalk46.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
8834
+ console.log(import_chalk47.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
8608
8835
  }, resource);
8609
8836
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
8610
8837
  const creds = {
@@ -8620,16 +8847,16 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
8620
8847
  resource
8621
8848
  };
8622
8849
  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}.`);
8850
+ console.log(` ${import_chalk47.default.green("\u2714")} Signed in as${creds.email ? ` ${import_chalk47.default.bold(creds.email)}` : " a consumer"} on ${tenant2}.`);
8624
8851
  return creds;
8625
8852
  }
8626
- async function cpPost(anon, path8, body, summary) {
8853
+ async function cpPost(anon, path9, body, summary) {
8627
8854
  if (anon) {
8628
8855
  const cred = loadAnonCred();
8629
8856
  if (!cred) throw new Error("Anonymous workspace credential missing.");
8630
- return cpFetch(cred.cp_key, path8, { method: "POST", body: JSON.stringify(body) });
8857
+ return cpFetch(cred.cp_key, path9, { method: "POST", body: JSON.stringify(body) });
8631
8858
  }
8632
- return admin({ method: "POST", path: path8, body, summary });
8859
+ return admin({ method: "POST", path: path9, body, summary });
8633
8860
  }
8634
8861
  async function provision(spec2, target, opts) {
8635
8862
  const loggedIn = !!loadCredentials();
@@ -8649,7 +8876,7 @@ async function provision(spec2, target, opts) {
8649
8876
  let name = opts.name ? base2 : `${base2}${salt()}`;
8650
8877
  const access = anon ? "open" : opts.access === "open" ? "open" : "invite";
8651
8878
  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`."));
8879
+ 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
8880
  }
8654
8881
  const DUAL_AUTH = {
8655
8882
  mode: "authenticate",
@@ -8748,7 +8975,7 @@ async function provision(spec2, target, opts) {
8748
8975
  try {
8749
8976
  await addPreapprovalRule(tenant2, email);
8750
8977
  } catch {
8751
- console.log(import_chalk46.default.dim(` (Could not auto-approve your email for sign-in \u2014 add it later: apiblaze preapprove ${email})`));
8978
+ console.log(import_chalk47.default.dim(` (Could not auto-approve your email for sign-in \u2014 add it later: apiblaze preapprove ${email})`));
8752
8979
  }
8753
8980
  }
8754
8981
  }
@@ -8792,7 +9019,7 @@ async function uploadSpec(p, specText, opts) {
8792
9019
  throw err;
8793
9020
  }
8794
9021
  if (out && out.reused === true) {
8795
- console.log(import_chalk46.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
9022
+ console.log(import_chalk47.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
8796
9023
  } else if (out && out.changed === true && out.previous_spec_hash) {
8797
9024
  const interactive = !!process.stdin.isTTY && !opts.yes;
8798
9025
  if (interactive) {
@@ -8800,7 +9027,7 @@ async function uploadSpec(p, specText, opts) {
8800
9027
  const { go } = await inquirer3.prompt([
8801
9028
  { type: "confirm", name: "go", message: "The spec changed since the last provision \u2014 re-publish the MCP catalogue?", default: true }
8802
9029
  ]);
8803
- if (!go) console.log(import_chalk46.default.dim(" Keeping the existing MCP catalogue."));
9030
+ if (!go) console.log(import_chalk47.default.dim(" Keeping the existing MCP catalogue."));
8804
9031
  }
8805
9032
  }
8806
9033
  }
@@ -8842,9 +9069,9 @@ function billingLine(info) {
8842
9069
  if (typeof info.free_turns_remaining === "number") return null;
8843
9070
  const cents = info.charged_cents;
8844
9071
  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}`);
9072
+ let line = import_chalk47.default.magenta(` \u{1F4B3} $${usd}`);
8846
9073
  if (typeof info.credits_remaining === "number") {
8847
- line += import_chalk46.default.dim(` \xB7 balance $${(info.credits_remaining / 100).toFixed(2)}`);
9074
+ line += import_chalk47.default.dim(` \xB7 balance $${(info.credits_remaining / 100).toFixed(2)}`);
8848
9075
  }
8849
9076
  return line;
8850
9077
  }
@@ -8852,15 +9079,15 @@ function freeBudgetWarning(info, anon) {
8852
9079
  if (!anon || !info) return null;
8853
9080
  if (typeof info.free_turns_remaining === "number") {
8854
9081
  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`);
9082
+ if (left2 <= 0) return import_chalk47.default.yellow(" Free chats used up \u2014 `npx apiblaze login` (free) to keep going.");
9083
+ return import_chalk47.default.dim(` ${left2} free chat${left2 === 1 ? "" : "s"} left \xB7 /login to get more`);
8857
9084
  }
8858
9085
  if (typeof info.free_remaining_cents !== "number") return null;
8859
9086
  const perTurn = Math.max(info.charged_cents || 0, 0.02);
8860
9087
  const left = Math.floor(info.free_remaining_cents / perTurn);
8861
9088
  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.`);
9089
+ if (left <= 0) return import_chalk47.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
9090
+ return import_chalk47.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
8864
9091
  }
8865
9092
  async function readSse(body, onEvent) {
8866
9093
  const reader = body.getReader();
@@ -8905,7 +9132,7 @@ async function replTurn(p, messages, userText) {
8905
9132
  });
8906
9133
  } catch (err) {
8907
9134
  spinner.fail("Network error.");
8908
- console.log(import_chalk46.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
9135
+ console.log(import_chalk47.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
8909
9136
  return;
8910
9137
  }
8911
9138
  if ((res.headers.get("content-type") ?? "").includes("text/event-stream") && res.ok && res.body) break;
@@ -8928,12 +9155,12 @@ async function replTurn(p, messages, userText) {
8928
9155
  spinner.start("retrying on the " + (p.anon ? "trial" : "claimed") + " plane\u2026");
8929
9156
  continue;
8930
9157
  }
8931
- console.log(import_chalk46.default.red(` No proxy named ${p.projectId} was found (tried both abz.run and tryabz.run).`));
9158
+ console.log(import_chalk47.default.red(` No proxy named ${p.projectId} was found (tried both abz.run and tryabz.run).`));
8932
9159
  return;
8933
9160
  }
8934
9161
  if (code === "identity_required" || /identif/i.test(msg) && !code) {
8935
9162
  if (!p.endUserId && tty) {
8936
- console.log(import_chalk46.default.yellow(" This API requires every call to say WHO is calling."));
9163
+ console.log(import_chalk47.default.yellow(" This API requires every call to say WHO is calling."));
8937
9164
  const { default: inquirer3 } = await import("inquirer");
8938
9165
  const { id } = await inquirer3.prompt([{ type: "input", name: "id", message: "Your end-user id (usually your email):" }]);
8939
9166
  if (typeof id === "string" && id.trim()) {
@@ -8943,27 +9170,27 @@ async function replTurn(p, messages, userText) {
8943
9170
  continue;
8944
9171
  }
8945
9172
  }
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)."));
9173
+ console.log(import_chalk47.default.red(" This API requires an identified caller."));
9174
+ console.log(import_chalk47.default.dim(" Re-run with --xenduserid <your id> (usually your email)."));
8948
9175
  return;
8949
9176
  }
8950
9177
  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}`));
9178
+ console.log(import_chalk47.default.yellow(` ${msg || "You are not pre-approved on this API."}`));
9179
+ if (p.endUserId) console.log(import_chalk47.default.dim(` Identity sent: ${p.endUserId}`));
8953
9180
  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>`."));
9181
+ if (accessUrl) console.log(` Request access: ${import_chalk47.default.bold(String(accessUrl))}`);
9182
+ console.log(import_chalk47.default.dim(" Or ask the producer to pre-approve you: `apiblaze preapprove <your-email> --tenant <tenant>`."));
8956
9183
  return;
8957
9184
  }
8958
9185
  if (code === "user_frozen") {
8959
- console.log(import_chalk46.default.red(` ${msg || "Your access to this API has been frozen by the producer."}`));
9186
+ console.log(import_chalk47.default.red(` ${msg || "Your access to this API has been frozen by the producer."}`));
8960
9187
  return;
8961
9188
  }
8962
9189
  const oauthWanted = /oauth token required|authorization: bearer/i.test(msg);
8963
9190
  const keyWanted = /api key required|x-api-key/i.test(msg);
8964
9191
  if (oauthWanted && !p.consumerAuth) {
8965
9192
  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"));
9193
+ console.log(import_chalk47.default.dim(" This proxy signs consumers in with OAuth \u2014 starting the login\u2026"));
8967
9194
  try {
8968
9195
  await ensureConsumerLogin(p.teamId, p.tenant, p.version);
8969
9196
  p.consumerAuth = true;
@@ -8972,17 +9199,17 @@ async function replTurn(p, messages, userText) {
8972
9199
  spinner.start("retrying\u2026");
8973
9200
  continue;
8974
9201
  } catch (err) {
8975
- console.log(import_chalk46.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9202
+ console.log(import_chalk47.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
8976
9203
  return;
8977
9204
  }
8978
9205
  }
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."));
9206
+ console.log(import_chalk47.default.red(" This proxy signs consumers in with OAuth (a login), not an API key."));
9207
+ console.log(import_chalk47.default.dim(" Sign in with: `apiblaze consumer login --tenant <tenant> --client <app-client-id>`, then re-run apichat."));
8981
9208
  return;
8982
9209
  }
8983
9210
  if (keyWanted) {
8984
9211
  if (tty) {
8985
- console.log(import_chalk46.default.yellow(` ${msg || "This API requires an API key."}`));
9212
+ console.log(import_chalk47.default.yellow(` ${msg || "This API requires an API key."}`));
8986
9213
  const { default: inquirer3 } = await import("inquirer");
8987
9214
  const { key } = await inquirer3.prompt([{ type: "password", name: "key", mask: "*", message: "API key for this proxy:" }]);
8988
9215
  if (typeof key === "string" && key.trim()) {
@@ -8993,8 +9220,8 @@ async function replTurn(p, messages, userText) {
8993
9220
  continue;
8994
9221
  }
8995
9222
  }
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)."));
9223
+ console.log(import_chalk47.default.red(` ${msg || "This API requires an API key."}`));
9224
+ console.log(import_chalk47.default.dim(" Re-run with --apikey <key> (mint one from the producer's site or dev portal)."));
8998
9225
  return;
8999
9226
  }
9000
9227
  if (res && (res.status === 402 || res.status === 403)) {
@@ -9002,16 +9229,16 @@ async function replTurn(p, messages, userText) {
9002
9229
  return;
9003
9230
  }
9004
9231
  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>."));
9232
+ console.log(import_chalk47.default.red(` The proxy rejected the request (401)${msg ? `: ${msg}` : "."}`));
9233
+ 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
9234
  return;
9008
9235
  }
9009
- console.log(import_chalk46.default.red(` Chat error: ${msg || (res ? `HTTP ${res.status}` : "request failed")}`));
9236
+ console.log(import_chalk47.default.red(` Chat error: ${msg || (res ? `HTTP ${res.status}` : "request failed")}`));
9010
9237
  return;
9011
9238
  }
9012
9239
  if (!res || !res.body || !(res.headers.get("content-type") ?? "").includes("text/event-stream")) {
9013
9240
  spinner.stop();
9014
- console.log(import_chalk46.default.red(" Chat error: could not authenticate to this proxy after several attempts."));
9241
+ console.log(import_chalk47.default.red(" Chat error: could not authenticate to this proxy after several attempts."));
9015
9242
  return;
9016
9243
  }
9017
9244
  let spinnerLive = true;
@@ -9052,7 +9279,7 @@ async function replTurn(p, messages, userText) {
9052
9279
  const name = String(ev.toolName ?? "tool");
9053
9280
  parts.push({ type: `tool-${name}`, toolCallId: String(ev.toolCallId ?? ""), state: "input-streaming" });
9054
9281
  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")}`);
9282
+ console.log(` ${import_chalk47.default.cyan("\u2699")} ${import_chalk47.default.cyan(name)}${import_chalk47.default.dim("\u2026")}`);
9056
9283
  break;
9057
9284
  }
9058
9285
  case "tool-input-available": {
@@ -9064,9 +9291,9 @@ async function replTurn(p, messages, userText) {
9064
9291
  Object.assign(parts[meta.partIdx], { state: "input-available", input });
9065
9292
  }
9066
9293
  if (isVerbose()) {
9067
- console.log(import_chalk46.default.dim(` args ${JSON.stringify(input)}`));
9294
+ console.log(import_chalk47.default.dim(` args ${JSON.stringify(input)}`));
9068
9295
  const hint = credHint();
9069
- if (hint) console.log(import_chalk46.default.dim(` auth ${hint}`) + (revealAuth ? "" : import_chalk46.default.yellow(" \u2190 /showauth reveals")));
9296
+ if (hint) console.log(import_chalk47.default.dim(` auth ${hint}`) + (revealAuth ? "" : import_chalk47.default.yellow(" \u2190 /showauth reveals")));
9070
9297
  }
9071
9298
  break;
9072
9299
  }
@@ -9077,8 +9304,8 @@ async function replTurn(p, messages, userText) {
9077
9304
  const meta = toolMeta.get(id);
9078
9305
  const ok = ev.type === "tool-output-available";
9079
9306
  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` : ""})`)}`);
9307
+ const mark = ok ? import_chalk47.default.green("\u2713") : import_chalk47.default.red("\u2717");
9308
+ console.log(` ${mark} ${import_chalk47.default.cyan(meta?.name ?? "tool")} ${import_chalk47.default.dim(`(${ok ? "ok" : "error"}${ms != null ? `, ${ms}ms` : ""})`)}`);
9082
9309
  const detail = ok ? String(ev.output ?? "") : String(ev.errorText ?? "Tool call failed.");
9083
9310
  if (meta) {
9084
9311
  Object.assign(parts[meta.partIdx], ok ? { state: "output-available", output: detail } : { state: "output-error", errorText: detail });
@@ -9093,9 +9320,9 @@ async function replTurn(p, messages, userText) {
9093
9320
  })();
9094
9321
  const lines = pretty.split("\n");
9095
9322
  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`));
9323
+ console.log(import_chalk47.default.dim(" response:"));
9324
+ for (const line of lines.slice(0, cap)) console.log(import_chalk47.default.dim(` ${line}`));
9325
+ if (lines.length > cap) console.log(import_chalk47.default.dim(` \u2026${lines.length - cap} more lines`));
9099
9326
  }
9100
9327
  break;
9101
9328
  }
@@ -9104,7 +9331,7 @@ async function replTurn(p, messages, userText) {
9104
9331
  parts.push({ type: "text", text: "" });
9105
9332
  openTextIdx = parts.length - 1;
9106
9333
  if (!assistantOpen) {
9107
- process.stdout.write("\n" + import_chalk46.default.green("assistant \u203A "));
9334
+ process.stdout.write("\n" + import_chalk47.default.green("assistant \u203A "));
9108
9335
  assistantOpen = true;
9109
9336
  }
9110
9337
  break;
@@ -9135,12 +9362,12 @@ async function replTurn(p, messages, userText) {
9135
9362
  });
9136
9363
  } catch (err) {
9137
9364
  stopSpinner();
9138
- console.log(import_chalk46.default.red(` Stream error: ${err instanceof Error ? err.message : String(err)}`));
9365
+ console.log(import_chalk47.default.red(` Stream error: ${err instanceof Error ? err.message : String(err)}`));
9139
9366
  }
9140
9367
  stopSpinner();
9141
9368
  if (assistantOpen) process.stdout.write("\n\n");
9142
9369
  if (parts.length) messages.push({ id: messageId, role: "assistant", parts });
9143
- if (errorText) console.log(import_chalk46.default.red(` ${errorText}`));
9370
+ if (errorText) console.log(import_chalk47.default.red(` ${errorText}`));
9144
9371
  if (upsell) {
9145
9372
  renderUpsell(p, upsell, { messageAlreadyShown: true });
9146
9373
  }
@@ -9152,39 +9379,39 @@ async function replTurn(p, messages, userText) {
9152
9379
  function renderUpsell(p, upsell, opts = {}) {
9153
9380
  const loggedIn = !!loadCredentials();
9154
9381
  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.)"));
9382
+ console.log("\n" + import_chalk47.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
9383
+ 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
9384
  console.log();
9158
9385
  return;
9159
9386
  }
9160
9387
  if (!opts.messageAlreadyShown) {
9161
- console.log("\n" + import_chalk46.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
9388
+ console.log("\n" + import_chalk47.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
9162
9389
  }
9163
9390
  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
9391
  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."));
9392
+ 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
9393
  } 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)."));
9394
+ 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
9395
  }
9169
9396
  } 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."));
9397
+ console.log(import_chalk47.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
9171
9398
  }
9172
9399
  console.log();
9173
9400
  }
9174
- var apichatsPath = () => path6.join(getApiblazeDir(), "apichats.json");
9401
+ var apichatsPath = () => path7.join(getApiblazeDir(), "apichats.json");
9175
9402
  function loadApichats() {
9176
9403
  try {
9177
- const list = JSON.parse(fs10.readFileSync(apichatsPath(), "utf-8"));
9404
+ const list = JSON.parse(fs11.readFileSync(apichatsPath(), "utf-8"));
9178
9405
  return Array.isArray(list) ? list : [];
9179
9406
  } catch {
9180
9407
  return [];
9181
9408
  }
9182
9409
  }
9183
9410
  function writeApichats(list) {
9184
- fs10.mkdirSync(getApiblazeDir(), { recursive: true });
9185
- fs10.writeFileSync(apichatsPath(), JSON.stringify(list, null, 2), "utf-8");
9411
+ fs11.mkdirSync(getApiblazeDir(), { recursive: true });
9412
+ fs11.writeFileSync(apichatsPath(), JSON.stringify(list, null, 2), "utf-8");
9186
9413
  try {
9187
- fs10.chmodSync(apichatsPath(), 384);
9414
+ fs11.chmodSync(apichatsPath(), 384);
9188
9415
  } catch {
9189
9416
  }
9190
9417
  }
@@ -9290,8 +9517,8 @@ async function openDirectProject(projectId, opts) {
9290
9517
  else p.consumerAuth = true;
9291
9518
  }
9292
9519
  }
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)}`);
9520
+ console.log(` ${import_chalk47.default.dim("Proxy:")} ${import_chalk47.default.bold(p.proxyUrl)}`);
9521
+ if (p.endUserId) console.log(` ${import_chalk47.default.dim("Acting as:")} ${import_chalk47.default.bold(p.endUserId)}`);
9295
9522
  upsertApichat({
9296
9523
  name: projectId,
9297
9524
  target: p.proxyUrl,
@@ -9321,9 +9548,9 @@ async function openServerProxy(project) {
9321
9548
  let consumerAuth = false;
9322
9549
  if (acceptsApiKey) {
9323
9550
  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`));
9551
+ 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
9552
  dpKey = await mintDurableProxyKey(project.teamId, tenant2);
9326
- console.log(` ${import_chalk46.default.green("\u2714")} API key: ${import_chalk46.default.dim(maskKey(dpKey))}`);
9553
+ console.log(` ${import_chalk47.default.green("\u2714")} API key: ${import_chalk47.default.dim(maskKey(dpKey))}`);
9327
9554
  }
9328
9555
  } else {
9329
9556
  consumerAuth = true;
@@ -9352,9 +9579,9 @@ async function openServerProxy(project) {
9352
9579
  const spec2 = raw && (raw.spec ?? raw);
9353
9580
  spinner.stop();
9354
9581
  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`."));
9582
+ 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
9583
  } else {
9357
- console.log(import_chalk46.default.dim(" Using the proxy's existing MCP catalogue (`apiblaze mcp` to rebuild it)."));
9584
+ console.log(import_chalk47.default.dim(" Using the proxy's existing MCP catalogue (`apiblaze mcp` to rebuild it)."));
9358
9585
  }
9359
9586
  } catch (err) {
9360
9587
  spinner.fail("Could not open the proxy.");
@@ -9386,15 +9613,15 @@ function discoverLocalSpecs() {
9386
9613
  const found = [];
9387
9614
  for (const n of known) {
9388
9615
  try {
9389
- if (fs10.statSync(path6.join(cwd, n)).isFile()) found.push(n);
9616
+ if (fs11.statSync(path7.join(cwd, n)).isFile()) found.push(n);
9390
9617
  } catch {
9391
9618
  }
9392
9619
  }
9393
9620
  try {
9394
- const files = fs10.readdirSync(cwd).filter((f) => /\.(ya?ml|json)$/i.test(f) && !found.includes(f));
9621
+ const files = fs11.readdirSync(cwd).filter((f) => /\.(ya?ml|json)$/i.test(f) && !found.includes(f));
9395
9622
  for (const f of files.slice(0, 60)) {
9396
9623
  try {
9397
- const head = fs10.readFileSync(path6.join(cwd, f), "utf-8").slice(0, 4e3);
9624
+ const head = fs11.readFileSync(path7.join(cwd, f), "utf-8").slice(0, 4e3);
9398
9625
  if (/["']?openapi["']?\s*:/i.test(head) || /["']?swagger["']?\s*:/i.test(head) || /^\s*paths\s*:/im.test(head) || /"paths"\s*:/.test(head)) {
9399
9626
  found.push(f);
9400
9627
  }
@@ -9410,7 +9637,7 @@ async function noArgsMenu(opts) {
9410
9637
  const me = loadCredentials()?.apiblazeUserId;
9411
9638
  const saved = loadApichats().filter((a) => a.anon ? true : a.ownerUserId !== void 0 && a.ownerUserId === me);
9412
9639
  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` : ""}`)}`,
9640
+ 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
9641
  value: { type: "existing", a }
9415
9642
  }));
9416
9643
  const creds = loadCredentials();
@@ -9420,14 +9647,14 @@ async function noArgsMenu(opts) {
9420
9647
  const proxies = (await getProjects(creds.teamId)).filter((pr) => !savedIds.has(pr.projectId));
9421
9648
  for (const pr of proxies) {
9422
9649
  choices.push({
9423
- name: `Chat with ${import_chalk46.default.bold(pr.projectName)} ${import_chalk46.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
9650
+ name: `Chat with ${import_chalk47.default.bold(pr.projectName)} ${import_chalk47.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
9424
9651
  value: { type: "server", project: pr }
9425
9652
  });
9426
9653
  }
9427
9654
  } catch {
9428
9655
  }
9429
9656
  }
9430
- choices.push({ name: import_chalk46.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
9657
+ choices.push({ name: import_chalk47.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
9431
9658
  const { pick: pick2 } = await inquirer3.prompt([
9432
9659
  { type: "list", name: "pick", message: "What would you like to do?", choices }
9433
9660
  ]);
@@ -9530,36 +9757,36 @@ async function noArgsMenu(opts) {
9530
9757
  async function runRepl(p, initialMessages) {
9531
9758
  const { default: inquirer3 } = await import("inquirer");
9532
9759
  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.`));
9760
+ console.log("\n" + import_chalk47.default.cyan.bold("Chat with your API") + import_chalk47.default.dim(` \xB7 ${p.mcpHost}`));
9761
+ if (messages.length) console.log(import_chalk47.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
9535
9762
  const llm2 = loadLlmConfig();
9536
9763
  console.log(
9537
- import_chalk46.default.dim(
9764
+ import_chalk47.default.dim(
9538
9765
  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
9766
  )
9540
9767
  );
9541
9768
  for (; ; ) {
9542
- const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk46.default.green("you \u203A") }]);
9769
+ const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk47.default.green("you \u203A") }]);
9543
9770
  const text = (input ?? "").trim();
9544
9771
  if (!text) continue;
9545
9772
  if (["/exit", "/quit", "exit", "quit", ":q"].includes(text.toLowerCase())) break;
9546
9773
  if (text === "/login") {
9547
9774
  try {
9548
9775
  await runLogin();
9549
- console.log(import_chalk46.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
9776
+ console.log(import_chalk47.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
9550
9777
  } catch (err) {
9551
- console.log(import_chalk46.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9778
+ console.log(import_chalk47.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9552
9779
  }
9553
9780
  continue;
9554
9781
  }
9555
9782
  if (text === "/claim") {
9556
9783
  const justLoggedIn = !loadCredentials();
9557
9784
  if (justLoggedIn) {
9558
- console.log(import_chalk46.default.dim(" Logging in to claim your workspace\u2026"));
9785
+ console.log(import_chalk47.default.dim(" Logging in to claim your workspace\u2026"));
9559
9786
  try {
9560
9787
  await runLogin();
9561
9788
  } catch (err) {
9562
- console.log(import_chalk46.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9789
+ console.log(import_chalk47.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
9563
9790
  continue;
9564
9791
  }
9565
9792
  if (!loadCredentials()) continue;
@@ -9570,57 +9797,217 @@ async function runRepl(p, initialMessages) {
9570
9797
  p.mcpHost = p.mcpHost.replace(".mcp.tryabz.run", ".mcp.abz.run");
9571
9798
  p.anon = false;
9572
9799
  claimApichat(p, loadCredentials()?.apiblazeUserId);
9573
- console.log(import_chalk46.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
9800
+ console.log(import_chalk47.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
9801
+ const entry = loadApichats().find((a) => apichatKey(a) === apichatKey(p));
9802
+ for (const [cli, state] of Object.entries(entry?.cliOffer ?? {})) {
9803
+ if (state === "installed" && (cli === "claude" || cli === "codex")) {
9804
+ if (refreshInstall(cli, buildInstallSpec(p))) {
9805
+ console.log(import_chalk47.default.dim(` ${cli === "claude" ? "Claude" : "Codex"} CLI's MCP entry updated to the new host.`));
9806
+ }
9807
+ }
9808
+ }
9574
9809
  }
9575
9810
  } catch (err) {
9576
- console.log(import_chalk46.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
9811
+ console.log(import_chalk47.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
9577
9812
  }
9578
9813
  continue;
9579
9814
  }
9580
9815
  if (text === "/showauth") {
9581
9816
  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."));
9817
+ 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
9818
  continue;
9584
9819
  }
9585
9820
  if (text.startsWith("/")) {
9586
- console.log(import_chalk46.default.dim(" Commands: /login /claim /showauth /exit"));
9821
+ console.log(import_chalk47.default.dim(" Commands: /login /claim /showauth /exit"));
9587
9822
  continue;
9588
9823
  }
9589
9824
  await replTurn(p, messages, text);
9590
9825
  saveTranscript(p, messages);
9591
9826
  }
9592
- console.log(import_chalk46.default.dim("\nBye."));
9827
+ console.log(import_chalk47.default.dim("\nBye."));
9828
+ }
9829
+ function offerKey(p) {
9830
+ return apichatKey(p);
9831
+ }
9832
+ function rememberCliOffer(p, cli, state) {
9833
+ const list = loadApichats();
9834
+ const i = list.findIndex((a) => apichatKey(a) === offerKey(p));
9835
+ if (i < 0) return;
9836
+ list[i].cliOffer = { ...list[i].cliOffer ?? {}, [cli]: state };
9837
+ list[i].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9838
+ writeApichats(list);
9839
+ }
9840
+ function buildInstallSpec(p) {
9841
+ return {
9842
+ name: p.projectId,
9843
+ url: `https://${p.mcpHost}/${p.version}/${p.environment}`,
9844
+ // consumerAuth means the door is a login — install bare, the CLI signs in.
9845
+ apiKey: p.consumerAuth ? void 0 : p.dpKey,
9846
+ endUserId: p.endUserId,
9847
+ projectLabel: p.projectId
9848
+ };
9849
+ }
9850
+ async function verifyAndHealMcpHost(p) {
9851
+ const ok = (await verifyMcpEndpoint(buildInstallSpec(p))).ok;
9852
+ if (ok) return true;
9853
+ const flipped = p.mcpHost.includes(".mcp.tryabz.run") ? p.mcpHost.replace(".mcp.tryabz.run", ".mcp.abz.run") : p.mcpHost.replace(".mcp.abz.run", ".mcp.tryabz.run");
9854
+ if (flipped === p.mcpHost) return false;
9855
+ const prev = p.mcpHost;
9856
+ p.mcpHost = flipped;
9857
+ if ((await verifyMcpEndpoint(buildInstallSpec(p))).ok) {
9858
+ const list = loadApichats();
9859
+ const i = list.findIndex((a) => apichatKey(a) === offerKey(p));
9860
+ if (i >= 0) {
9861
+ list[i].mcpHost = flipped;
9862
+ list[i].updatedAt = (/* @__PURE__ */ new Date()).toISOString();
9863
+ writeApichats(list);
9864
+ }
9865
+ return true;
9866
+ }
9867
+ p.mcpHost = prev;
9868
+ return false;
9869
+ }
9870
+ async function maybeInstallExternalCli(p, opts) {
9871
+ const forced = (opts.installMcp ?? "").toLowerCase();
9872
+ if (forced && forced !== "claude" && forced !== "codex") {
9873
+ fail4(`--install-mcp takes "claude" or "codex", not "${opts.installMcp}".`);
9874
+ }
9875
+ if (!forced && !process.stdin.isTTY) return false;
9876
+ const offer = loadApichats().find((a) => apichatKey(a) === offerKey(p))?.cliOffer ?? {};
9877
+ if (forced) {
9878
+ const cli = detectExternalClis().find((c) => c.kind === forced);
9879
+ if (!cli) fail4(
9880
+ `${forced === "claude" ? "Claude" : "Codex"} CLI not found on this machine.`,
9881
+ forced === "claude" ? "Install it: npm install -g @anthropic-ai/claude-code" : "Install it: npm install -g @openai/codex"
9882
+ );
9883
+ if (!await ensureInstallableDoor(p, opts)) return false;
9884
+ if (!await verifyAndHealMcpHost(p)) {
9885
+ fail4(`The MCP endpoint https://${p.mcpHost}/${p.version}/${p.environment} is not answering \u2014 not installing it into ${cli.label}.`);
9886
+ }
9887
+ const ran2 = await installAndDemo(cli, buildInstallSpec(p), () => resolveQuestion(opts));
9888
+ if (ran2) rememberCliOffer(p, cli.kind, "installed");
9889
+ return ran2;
9890
+ }
9891
+ const clis = detectExternalClis();
9892
+ if (clis.length === 0) return false;
9893
+ for (const c of clis) {
9894
+ if (offer[c.kind] === "installed" && await verifyAndHealMcpHost(p)) {
9895
+ refreshInstall(c.kind, buildInstallSpec(p));
9896
+ }
9897
+ }
9898
+ const fresh = clis.filter((c) => !offer[c.kind]);
9899
+ if (fresh.length === 0) return false;
9900
+ const { default: inquirer3 } = await import("inquirer");
9901
+ const names = fresh.map((c) => c.label).join(" and ");
9902
+ const targetName = fresh.length > 1 ? "one of them" : fresh[0].label;
9903
+ const { pick: pick2 } = await inquirer3.prompt([{
9904
+ type: "list",
9905
+ name: "pick",
9906
+ message: `I see ${names} ${fresh.length > 1 ? "are" : "is"} installed on this computer. Do you want to add the MCP for this proxy to ${targetName} so you can chat with your API from there directly, or chat here directly?`,
9907
+ choices: [
9908
+ ...fresh.map((c) => ({ name: c.label, value: c })),
9909
+ { name: "Chat here directly", value: "here" }
9910
+ ]
9911
+ }]);
9912
+ if (pick2 === "here") {
9913
+ for (const c of fresh) rememberCliOffer(p, c.kind, "declined");
9914
+ if (p.consumerAuth && p.teamId && p.tenant) {
9915
+ try {
9916
+ await ensureConsumerLogin(p.teamId, p.tenant, p.version);
9917
+ } catch (err) {
9918
+ console.log(import_chalk47.default.yellow(` Sign-in didn't complete (${err instanceof Error ? err.message : String(err)}) \u2014 the first chat turn will retry it.`));
9919
+ }
9920
+ }
9921
+ return false;
9922
+ }
9923
+ if (!await ensureInstallableDoor(p, opts)) return false;
9924
+ if (!await verifyAndHealMcpHost(p)) {
9925
+ console.log(import_chalk47.default.red(` The MCP endpoint https://${p.mcpHost}/${p.version}/${p.environment} is not answering \u2014 not installing it into ${pick2.label}. Chat here instead.`));
9926
+ return false;
9927
+ }
9928
+ const ran = await installAndDemo(pick2, buildInstallSpec(p), () => resolveQuestion(opts));
9929
+ if (ran) {
9930
+ rememberCliOffer(p, pick2.kind, "installed");
9931
+ if (p.anon) {
9932
+ console.log(import_chalk47.default.dim(` Anonymous workspace \u2014 run \`apiblaze apichat ${p.projectId}\` and /claim to keep it (and this MCP) beyond 30 days.`));
9933
+ }
9934
+ }
9935
+ return ran;
9936
+ }
9937
+ async function ensureInstallableDoor(p, opts) {
9938
+ if (p.dpKey || p.consumerAuth) return true;
9939
+ if (!process.stdin.isTTY) {
9940
+ fail4(
9941
+ `Can't tell how "${p.projectId}" authenticates (no key on file).`,
9942
+ "Pass --apikey <key> for a key-door proxy, or open it interactively once first."
9943
+ );
9944
+ }
9945
+ const { default: inquirer3 } = await import("inquirer");
9946
+ const { key } = await inquirer3.prompt([{
9947
+ type: "password",
9948
+ name: "key",
9949
+ mask: "*",
9950
+ message: `API key for ${p.projectId} (leave empty if it uses a login):`
9951
+ }]);
9952
+ if (typeof key === "string" && key.trim()) p.dpKey = key.trim();
9953
+ else p.consumerAuth = true;
9954
+ void opts;
9955
+ return true;
9956
+ }
9957
+ async function resolveQuestion(opts) {
9958
+ if (opts.prompt) return opts.prompt;
9959
+ if (!process.stdin.isTTY) return void 0;
9960
+ const { default: inquirer3 } = await import("inquirer");
9961
+ const { q } = await inquirer3.prompt([{
9962
+ type: "input",
9963
+ name: "q",
9964
+ message: "What question do you have for this API?"
9965
+ }]);
9966
+ const t = (q ?? "").trim();
9967
+ return t || void 0;
9968
+ }
9969
+ async function startChat(p, messages, opts) {
9970
+ if (opts.prompt) {
9971
+ await replTurn(p, messages, opts.prompt);
9972
+ saveTranscript(p, messages);
9973
+ if (!process.stdin.isTTY) return;
9974
+ } else if (!process.stdin.isTTY) {
9975
+ fail4('Interactive chat needs a terminal. Pass -p "<question>" for a one-shot answer.');
9976
+ }
9977
+ await runRepl(p, messages);
9593
9978
  }
9594
9979
  async function runApichat(opts) {
9595
- setVerbose(opts.verbose !== false);
9596
- console.log(import_chalk46.default.bold("\napichat \u2014 turn any API into a chat\n"));
9980
+ setVerbose(opts.verbose === true);
9981
+ console.log(import_chalk47.default.bold("\napichat \u2014 turn any API into a chat\n"));
9597
9982
  if (opts.target && !opts.openapispec) {
9598
9983
  const { classifyTargetInput: classifyTargetInput2 } = await Promise.resolve().then(() => (init_spec_or_target(), spec_or_target_exports));
9599
9984
  const c = await classifyTargetInput2(opts.target, fail4);
9600
9985
  if (c.kind === "spec") {
9601
- console.log(import_chalk46.default.dim(` --target is an OpenAPI document (${c.source}) \u2014 using it as the spec.`));
9986
+ console.log(import_chalk47.default.dim(` --target is an OpenAPI document (${c.source}) \u2014 using it as the spec.`));
9602
9987
  opts.openapispec = opts.target;
9603
9988
  opts.target = void 0;
9604
9989
  }
9605
9990
  }
9606
9991
  if (opts.project) {
9607
9992
  const opened = await openDirectProject(opts.project, opts);
9608
- await runRepl(opened.p, opened.messages);
9993
+ if (await maybeInstallExternalCli(opened.p, opts)) return;
9994
+ await startChat(opened.p, opened.messages, opts);
9609
9995
  return;
9610
9996
  }
9611
9997
  if (!opts.openapispec && !opts.target) {
9612
9998
  if (!process.stdin.isTTY) {
9613
- fail4("No spec source. Pass --openapispec <file|url> or --target <url>.", GENERATOR_HINT);
9999
+ fail4("No spec source. Pass --target <server-url | openapi-file | openapi-url>.", GENERATOR_HINT);
9614
10000
  }
9615
10001
  const resumed = await noArgsMenu(opts);
9616
10002
  if (resumed) {
9617
- await runRepl(resumed.p, resumed.messages);
10003
+ if (await maybeInstallExternalCli(resumed.p, opts)) return;
10004
+ await startChat(resumed.p, resumed.messages, opts);
9618
10005
  return;
9619
10006
  }
9620
10007
  }
9621
10008
  const { spec: spec2, sourceUrl } = await loadSpec(opts);
9622
10009
  const target = resolveTarget(spec2, opts, sourceUrl);
9623
- console.log(` ${import_chalk46.default.dim("Target:")} ${import_chalk46.default.bold(target)}`);
10010
+ console.log(` ${import_chalk47.default.dim("Target:")} ${import_chalk47.default.bold(target)}`);
9624
10011
  const auth = await resolveTargetAuth(spec2, opts);
9625
10012
  if (auth && !process.stdin.isTTY && !opts.targetAuthEnv) {
9626
10013
  fail4(
@@ -9629,7 +10016,7 @@ async function runApichat(opts) {
9629
10016
  );
9630
10017
  }
9631
10018
  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}`)}`);
10019
+ console.log(` ${import_chalk47.default.dim("Proxy: ")} ${import_chalk47.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
9633
10020
  upsertApichat({
9634
10021
  name: p.projectId,
9635
10022
  target,
@@ -9649,30 +10036,31 @@ async function runApichat(opts) {
9649
10036
  const secret = await captureTargetSecret(auth, opts);
9650
10037
  if (secret) await writeTargetAuth(p, auth, secret);
9651
10038
  } else {
9652
- console.log(import_chalk46.default.dim(" Target auth: none required."));
10039
+ console.log(import_chalk47.default.dim(" Target auth: none required."));
9653
10040
  }
9654
10041
  const specText = JSON.stringify(spec2);
9655
10042
  await uploadSpec(p, specText, opts);
9656
10043
  const mcpUrl = await publishMcp(p, spec2);
9657
10044
  console.log();
9658
- if (p.proxyUrl) console.log(` ${import_chalk46.default.green("\u2713")} proxy ${import_chalk46.default.bold(p.proxyUrl)}`);
10045
+ if (p.proxyUrl) console.log(` ${import_chalk47.default.green("\u2713")} proxy ${import_chalk47.default.bold(p.proxyUrl)}`);
9659
10046
  if (mcpUrl) {
9660
- console.log(` ${import_chalk46.default.green("\u2713")} mcp ${import_chalk46.default.bold(mcpUrl)}`);
10047
+ console.log(` ${import_chalk47.default.green("\u2713")} mcp ${import_chalk47.default.bold(mcpUrl)}`);
9661
10048
  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)`));
10049
+ console.log(import_chalk47.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: invite \u2014 only you + emails you pre-approve"));
10050
+ 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
10051
  } 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"));
10052
+ 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
10053
  }
9667
10054
  }
9668
10055
  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."));
10056
+ console.log(import_chalk47.default.dim("\n Anonymous workspace \u2014 /claim inside the chat to log in and keep it beyond 30 days."));
9670
10057
  }
9671
- await runRepl(p);
10058
+ if (mcpUrl && await maybeInstallExternalCli(p, opts)) return;
10059
+ await startChat(p, [], opts);
9672
10060
  }
9673
10061
 
9674
10062
  // src/commands/consumer.ts
9675
- var import_chalk47 = __toESM(require("chalk"));
10063
+ var import_chalk48 = __toESM(require("chalk"));
9676
10064
  var import_ora24 = __toESM(require("ora"));
9677
10065
  init_admin();
9678
10066
  init_resolve();
@@ -9694,7 +10082,7 @@ async function consumerFetch(creds, suffix, init) {
9694
10082
  function requireConsumer2() {
9695
10083
  const c = loadConsumer();
9696
10084
  if (!c) {
9697
- console.error(import_chalk47.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
10085
+ console.error(import_chalk48.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
9698
10086
  process.exit(1);
9699
10087
  }
9700
10088
  return c;
@@ -9705,7 +10093,7 @@ async function runConsumerLogin(opts) {
9705
10093
  let clientId = opts.client;
9706
10094
  if (clientId) {
9707
10095
  if (!tenant2) {
9708
- console.error(import_chalk47.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
10096
+ console.error(import_chalk48.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
9709
10097
  process.exit(1);
9710
10098
  }
9711
10099
  } else {
@@ -9723,18 +10111,18 @@ async function runConsumerLogin(opts) {
9723
10111
  const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
9724
10112
  const pick2 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
9725
10113
  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).`));
10114
+ 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
10115
  process.exit(1);
9728
10116
  }
9729
10117
  clientId = pick2.client_id ?? pick2.clientId;
9730
10118
  }
9731
- console.log(`${import_chalk47.default.cyan("\u2192")} Logging in to ${import_chalk47.default.bold(tenant2)} as a consumer...`);
10119
+ console.log(`${import_chalk48.default.cyan("\u2192")} Logging in to ${import_chalk48.default.bold(tenant2)} as a consumer...`);
9732
10120
  const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
9733
10121
  console.log(`
9734
- Open: ${import_chalk47.default.underline(verificationUri)}`);
9735
- console.log(` Code: ${import_chalk47.default.bold(userCode)}
10122
+ Open: ${import_chalk48.default.underline(verificationUri)}`);
10123
+ console.log(` Code: ${import_chalk48.default.bold(userCode)}
9736
10124
  `);
9737
- console.log(import_chalk47.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
10125
+ console.log(import_chalk48.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
9738
10126
  });
9739
10127
  const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
9740
10128
  const creds = {
@@ -9749,7 +10137,7 @@ async function runConsumerLogin(opts) {
9749
10137
  obtainedAt: Date.now()
9750
10138
  };
9751
10139
  saveConsumer(creds);
9752
- console.log(import_chalk47.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
10140
+ console.log(import_chalk48.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
9753
10141
  }
9754
10142
  async function runConsumerTokens(opts) {
9755
10143
  const creds = requireConsumer2();
@@ -9762,18 +10150,18 @@ async function runConsumerTokens(opts) {
9762
10150
  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
10151
  return;
9764
10152
  }
9765
- console.log(`${import_chalk47.default.cyan("Consumer")} ${import_chalk47.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk47.default.bold(fresh.tenant)}
10153
+ console.log(`${import_chalk48.default.cyan("Consumer")} ${import_chalk48.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk48.default.bold(fresh.tenant)}
9766
10154
  `);
9767
- console.log(`${import_chalk47.default.bold("access_token")} ${import_chalk47.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
10155
+ console.log(`${import_chalk48.default.bold("access_token")} ${import_chalk48.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
9768
10156
  ${fresh.accessToken}
9769
10157
  `);
9770
- if (fresh.idToken) console.log(`${import_chalk47.default.bold("id_token")} ${import_chalk47.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
10158
+ if (fresh.idToken) console.log(`${import_chalk48.default.bold("id_token")} ${import_chalk48.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
9771
10159
  ${fresh.idToken}
9772
10160
  `);
9773
- if (fresh.refreshToken) console.log(`${import_chalk47.default.bold("refresh_token")}
10161
+ if (fresh.refreshToken) console.log(`${import_chalk48.default.bold("refresh_token")}
9774
10162
  ${fresh.refreshToken}
9775
10163
  `);
9776
- console.log(import_chalk47.default.dim("These are your own tokens \u2014 keep them secret."));
10164
+ console.log(import_chalk48.default.dim("These are your own tokens \u2014 keep them secret."));
9777
10165
  }
9778
10166
  async function runConsumerApikeys(opts) {
9779
10167
  const creds = requireConsumer2();
@@ -9783,8 +10171,8 @@ async function runConsumerApikeys(opts) {
9783
10171
  const revealed = await consumerFetch(list.creds, "/apikeys/reveal").catch(() => ({ status: 0, data: null, creds: list.creds }));
9784
10172
  spinner.stop();
9785
10173
  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."));
10174
+ console.error(import_chalk48.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
10175
+ if (list.status === 401) console.error(import_chalk48.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
9788
10176
  process.exit(1);
9789
10177
  }
9790
10178
  const keys = list.data?.keys ?? [];
@@ -9792,16 +10180,16 @@ async function runConsumerApikeys(opts) {
9792
10180
  if (opts.json) {
9793
10181
  console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
9794
10182
  } else if (!keys.length) {
9795
- console.log(import_chalk47.default.yellow("No API keys yet."));
10183
+ console.log(import_chalk48.default.yellow("No API keys yet."));
9796
10184
  } else {
9797
10185
  for (const k of keys) {
9798
10186
  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 ?? "")}`);
10187
+ const shown = clear ? import_chalk48.default.green(clear) : import_chalk48.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
10188
+ const exp = k.expires_at ? import_chalk48.default.dim(`exp ${k.expires_at}`) : import_chalk48.default.dim("no expiry");
10189
+ console.log(` ${import_chalk48.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk48.default.dim(k.description ?? "")}`);
9802
10190
  }
9803
10191
  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.)"));
10192
+ console.log(import_chalk48.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
9805
10193
  }
9806
10194
  }
9807
10195
  if (opts.json) return;
@@ -9823,35 +10211,35 @@ async function runConsumerApikeys(opts) {
9823
10211
  }
9824
10212
  s2.succeed("Key created.");
9825
10213
  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."));
10214
+ if (key) console.log(` ${import_chalk48.default.green(key)} ${import_chalk48.default.dim("(shown once \u2014 store it now)")}`);
10215
+ else console.log(import_chalk48.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
9828
10216
  }
9829
10217
 
9830
10218
  // src/commands/sidecar.ts
9831
- var import_chalk48 = __toESM(require("chalk"));
10219
+ var import_chalk49 = __toESM(require("chalk"));
9832
10220
  var import_ora25 = __toESM(require("ora"));
9833
- var fs11 = __toESM(require("fs"));
9834
- var path7 = __toESM(require("path"));
10221
+ var fs12 = __toESM(require("fs"));
10222
+ var path8 = __toESM(require("path"));
9835
10223
  init_admin();
9836
10224
  init_resolve();
9837
10225
  init_auth();
9838
10226
  function detectNextProject(root) {
9839
- const hasConfig = ["next.config.js", "next.config.mjs", "next.config.ts"].some((f) => fs11.existsSync(path7.join(root, f)));
10227
+ const hasConfig = ["next.config.js", "next.config.mjs", "next.config.ts"].some((f) => fs12.existsSync(path8.join(root, f)));
9840
10228
  let hasDep = false;
9841
10229
  try {
9842
- const pkg = JSON.parse(fs11.readFileSync(path7.join(root, "package.json"), "utf8"));
10230
+ const pkg = JSON.parse(fs12.readFileSync(path8.join(root, "package.json"), "utf8"));
9843
10231
  hasDep = !!(pkg.dependencies?.next || pkg.devDependencies?.next);
9844
10232
  } catch {
9845
10233
  }
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"));
10234
+ const appDir = fs12.existsSync(path8.join(root, "app")) || fs12.existsSync(path8.join(root, "src", "app"));
10235
+ const pagesDir = fs12.existsSync(path8.join(root, "pages")) || fs12.existsSync(path8.join(root, "src", "pages"));
9848
10236
  return { found: hasConfig || hasDep || appDir || pagesDir, router: appDir ? "app" : pagesDir ? "pages" : null };
9849
10237
  }
9850
10238
  function upsertEnvLocal(root, token) {
9851
- const p = path7.join(root, ".env.local");
10239
+ const p = path8.join(root, ".env.local");
9852
10240
  let existing = "";
9853
10241
  try {
9854
- existing = fs11.readFileSync(p, "utf8");
10242
+ existing = fs12.readFileSync(p, "utf8");
9855
10243
  } catch {
9856
10244
  }
9857
10245
  const had = /^APIBLAZE_API_KEY=/m.test(existing) || /^APIBLAZE_TOKEN=/m.test(existing);
@@ -9866,15 +10254,15 @@ function upsertEnvLocal(root, token) {
9866
10254
  next = (next.endsWith("\n") ? next : next + "\n") + `APIBLAZE_SIDECAR_VERBOSE=true
9867
10255
  `;
9868
10256
  }
9869
- fs11.writeFileSync(p, next);
10257
+ fs12.writeFileSync(p, next);
9870
10258
  return had ? "rotated" : "created";
9871
10259
  }
9872
10260
  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`);
10261
+ if (fs12.existsSync(path8.join(root, "node_modules", "apiblaze", "package.json"))) {
10262
+ console.log(` ${import_chalk49.default.green("\u2713")} apiblaze package already installed`);
9875
10263
  return;
9876
10264
  }
9877
- const has = (f) => fs11.existsSync(path7.join(root, f));
10265
+ const has = (f) => fs12.existsSync(path8.join(root, f));
9878
10266
  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
10267
  const spinner = (0, import_ora25.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
9880
10268
  try {
@@ -9882,12 +10270,12 @@ function installSidecarPackage(root) {
9882
10270
  execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
9883
10271
  spinner.succeed("Installed apiblaze (the sidecar runtime).");
9884
10272
  } 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")}.`);
10273
+ 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
10274
  }
9887
10275
  }
9888
10276
  function readEnvKey(root) {
9889
10277
  try {
9890
- const s = fs11.readFileSync(path7.join(root, ".env.local"), "utf8");
10278
+ const s = fs12.readFileSync(path8.join(root, ".env.local"), "utf8");
9891
10279
  const m = s.match(/^APIBLAZE_API_KEY=(.+)$/m) ?? s.match(/^APIBLAZE_TOKEN=(.+)$/m);
9892
10280
  return m ? m[1].trim() : null;
9893
10281
  } catch {
@@ -9895,16 +10283,16 @@ function readEnvKey(root) {
9895
10283
  }
9896
10284
  }
9897
10285
  function ensureGitignored(root) {
9898
- const p = path7.join(root, ".gitignore");
10286
+ const p = path8.join(root, ".gitignore");
9899
10287
  let c = "";
9900
10288
  try {
9901
- c = fs11.readFileSync(p, "utf8");
10289
+ c = fs12.readFileSync(p, "utf8");
9902
10290
  } catch {
9903
10291
  }
9904
- if (!/^\.env\.local$/m.test(c) && !/^\.env\*/m.test(c)) fs11.writeFileSync(p, (c && !c.endsWith("\n") ? c + "\n" : c) + ".env.local\n");
10292
+ if (!/^\.env\.local$/m.test(c) && !/^\.env\*/m.test(c)) fs12.writeFileSync(p, (c && !c.endsWith("\n") ? c + "\n" : c) + ".env.local\n");
9905
10293
  }
9906
10294
  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));
10295
+ const existing = ["instrumentation.ts", "instrumentation.js", path8.join("src", "instrumentation.ts")].map((c) => path8.join(root, c)).find((f) => fs12.existsSync(f));
9908
10296
  const body = `import { register as apiblaze } from "apiblaze/sidecar";
9909
10297
 
9910
10298
  export function register() {
@@ -9912,18 +10300,18 @@ export function register() {
9912
10300
  }
9913
10301
  `;
9914
10302
  if (!existing) {
9915
- fs11.writeFileSync(path7.join(root, "instrumentation.ts"), body);
10303
+ fs12.writeFileSync(path8.join(root, "instrumentation.ts"), body);
9916
10304
  return "created";
9917
10305
  }
9918
- const cur = fs11.readFileSync(existing, "utf8");
10306
+ const cur = fs12.readFileSync(existing, "utf8");
9919
10307
  if (cur.includes("apiblaze/sidecar")) return "present";
9920
10308
  if (/export\s+function\s+register\s*\(/.test(cur)) {
9921
- fs11.writeFileSync(existing, `import { register as apiblaze } from "apiblaze/sidecar";
10309
+ fs12.writeFileSync(existing, `import { register as apiblaze } from "apiblaze/sidecar";
9922
10310
  ` + cur.replace(/export\s+function\s+register\s*\(\s*\)\s*\{/, (m) => `${m}
9923
10311
  apiblaze();`));
9924
10312
  return "patched";
9925
10313
  }
9926
- fs11.writeFileSync(existing, `import { register as apiblaze } from "apiblaze/sidecar";
10314
+ fs12.writeFileSync(existing, `import { register as apiblaze } from "apiblaze/sidecar";
9927
10315
  ${cur}
9928
10316
  // call apiblaze() inside your register() export.
9929
10317
  `);
@@ -10002,17 +10390,17 @@ export default async function Page() {
10002
10390
  function generateInspector(root, router) {
10003
10391
  try {
10004
10392
  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);
10393
+ const dir2 = fs12.existsSync(path8.join(root, "src", "pages")) ? path8.join(root, "src", "pages") : path8.join(root, "pages");
10394
+ const f2 = path8.join(dir2, "abz-inspector.tsx");
10395
+ fs12.writeFileSync(f2, INSPECTOR_PAGE);
10396
+ return path8.relative(root, f2);
10397
+ }
10398
+ const base2 = fs12.existsSync(path8.join(root, "src", "app")) ? path8.join(root, "src", "app") : path8.join(root, "app");
10399
+ const dir = path8.join(base2, "abz-inspector");
10400
+ fs12.mkdirSync(dir, { recursive: true });
10401
+ const f = path8.join(dir, "page.tsx");
10402
+ fs12.writeFileSync(f, INSPECTOR_PAGE);
10403
+ return path8.relative(root, f);
10016
10404
  } catch {
10017
10405
  return null;
10018
10406
  }
@@ -10033,43 +10421,43 @@ async function runAnonymousInit(root, router, opts) {
10033
10421
  if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
10034
10422
  const envState = upsertEnvLocal(root, out.token);
10035
10423
  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)}`);
10424
+ console.log(` ${import_chalk49.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
10425
+ console.log(` ${import_chalk49.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
10038
10426
  installSidecarPackage(root);
10039
10427
  let inspectorPath = null;
10040
10428
  if (!opts.noInspector) {
10041
10429
  inspectorPath = generateInspector(root, router);
10042
- if (inspectorPath) console.log(` ${import_chalk48.default.green("\u2713")} inspector at ${inspectorPath}`);
10430
+ if (inspectorPath) console.log(` ${import_chalk49.default.green("\u2713")} inspector at ${inspectorPath}`);
10043
10431
  }
10044
10432
  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.`);
10433
+ console.log(import_chalk49.default.bold("Done (no account needed). What happens next:"));
10434
+ console.log(` 1. ${import_chalk49.default.cyan("npm run dev")} and use your app.`);
10047
10435
  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)`);
10436
+ console.log(` ${import_chalk49.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
10049
10437
  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`));
10438
+ console.log(import_chalk49.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
10439
+ console.log(` ${import_chalk49.default.cyan("apiblaze login")} then ${import_chalk49.default.cyan("apiblaze claim")} ${import_chalk49.default.dim("(no code needed here)")}`);
10440
+ console.log(import_chalk49.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
10053
10441
  }
10054
10442
  async function runSidecar(opts) {
10055
- const root = path7.resolve(opts.dir ?? process.cwd());
10056
- const detected = detectNextProject(root);
10057
- if (!detected.found) {
10058
- console.log(import_chalk48.default.yellow(`No Next.js project detected in ${root}.`));
10443
+ const root = path8.resolve(opts.dir ?? process.cwd());
10444
+ const detected2 = detectNextProject(root);
10445
+ if (!detected2.found) {
10446
+ console.log(import_chalk49.default.yellow(`No Next.js project detected in ${root}.`));
10059
10447
  console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
10060
10448
  return;
10061
10449
  }
10062
10450
  if (!loadCredentials() && !readEnvKey(root)) {
10063
- await runAnonymousInit(root, detected.router, opts);
10451
+ await runAnonymousInit(root, detected2.router, opts);
10064
10452
  return;
10065
10453
  }
10066
10454
  if (!loadCredentials()) {
10067
10455
  upsertEnvLocal(root, readEnvKey(root));
10068
10456
  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)}`);
10457
+ console.log(` ${import_chalk49.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
10458
+ console.log(` ${import_chalk49.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
10071
10459
  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."));
10460
+ console.log(import_chalk49.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
10073
10461
  return;
10074
10462
  }
10075
10463
  const { teamId, teamName } = await resolveTeam(opts.team);
@@ -10092,38 +10480,38 @@ async function runSidecar(opts) {
10092
10480
  throw err;
10093
10481
  }
10094
10482
  } 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).`));
10483
+ 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
10484
  }
10097
10485
  const envState = upsertEnvLocal(root, token);
10098
10486
  ensureGitignored(root);
10099
- console.log(` ${import_chalk48.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
10487
+ console.log(` ${import_chalk49.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
10100
10488
  const wireState = wireInstrumentation(root);
10101
- console.log(` ${import_chalk48.default.green("\u2713")} instrumentation.ts ${wireState}`);
10489
+ console.log(` ${import_chalk49.default.green("\u2713")} instrumentation.ts ${wireState}`);
10102
10490
  installSidecarPackage(root);
10103
10491
  let inspectorPath = null;
10104
10492
  if (!opts.noInspector) {
10105
- inspectorPath = generateInspector(root, detected.router);
10106
- if (inspectorPath) console.log(` ${import_chalk48.default.green("\u2713")} inspector at ${inspectorPath}`);
10493
+ inspectorPath = generateInspector(root, detected2.router);
10494
+ if (inspectorPath) console.log(` ${import_chalk49.default.green("\u2713")} inspector at ${inspectorPath}`);
10107
10495
  }
10108
10496
  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)`);
10497
+ console.log(import_chalk49.default.bold("Done. What happens next:"));
10498
+ console.log(` 1. ${import_chalk49.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
10499
+ console.log(` 2. The origins your app calls appear as ${import_chalk49.default.bold("candidates")} \u2014 list them: ${import_chalk49.default.cyan("apiblaze sidecar")}`);
10500
+ console.log(` 3. Approve the ones to route: ${import_chalk49.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
10113
10501
  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>\`.`));
10502
+ 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)`);
10503
+ 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
10504
  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)."));
10505
+ console.log(import_chalk49.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
10506
+ console.log(import_chalk49.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
10507
+ console.log(import_chalk49.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
10120
10508
  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."));
10509
+ 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."));
10510
+ console.log(import_chalk49.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
10123
10511
  }
10124
10512
 
10125
10513
  // src/commands/origins.ts
10126
- var import_chalk49 = __toESM(require("chalk"));
10514
+ var import_chalk50 = __toESM(require("chalk"));
10127
10515
  var import_ora26 = __toESM(require("ora"));
10128
10516
  init_admin();
10129
10517
  init_resolve();
@@ -10134,7 +10522,7 @@ async function runOriginsList(opts) {
10134
10522
  if (!loadCredentials()) {
10135
10523
  const cred = loadAnonCred();
10136
10524
  if (!cred) {
10137
- console.log(import_chalk49.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
10525
+ console.log(import_chalk50.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
10138
10526
  return;
10139
10527
  }
10140
10528
  out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
@@ -10152,27 +10540,27 @@ async function runOriginsList(opts) {
10152
10540
  }
10153
10541
  const routed = out.routed ?? [];
10154
10542
  const candidates = out.candidates ?? [];
10155
- console.log(import_chalk49.default.bold(`
10543
+ console.log(import_chalk50.default.bold(`
10156
10544
  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(`
10545
+ if (!routed.length) console.log(import_chalk50.default.dim(" none yet"));
10546
+ for (const r of routed) console.log(` ${import_chalk50.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk50.default.dim(`\u2192 ${r.project_id}`)}`);
10547
+ console.log(import_chalk50.default.bold(`
10160
10548
  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"));
10549
+ if (!candidates.length) console.log(import_chalk50.default.dim(" none \u2014 run your app to discover the origins it calls"));
10162
10550
  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}`)}`);
10551
+ console.log(` ${import_chalk50.default.yellow("\u25CB")} ${c.origin} ${import_chalk50.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
10164
10552
  }
10165
10553
  if (candidates.length) {
10166
- console.log(import_chalk49.default.dim(`
10554
+ console.log(import_chalk50.default.dim(`
10167
10555
  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://", "")}`));
10556
+ console.log(import_chalk50.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
10169
10557
  }
10170
10558
  }
10171
10559
  async function runOriginsApprove(origin, opts) {
10172
10560
  if (!loadCredentials()) {
10173
10561
  const cred = loadAnonCred();
10174
10562
  if (!cred) {
10175
- console.error(import_chalk49.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
10563
+ console.error(import_chalk50.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
10176
10564
  process.exit(1);
10177
10565
  }
10178
10566
  const spinner2 = (0, import_ora26.default)(`Approving ${origin} (anonymous)...`).start();
@@ -10225,13 +10613,13 @@ async function runOriginsRemove(origin, opts) {
10225
10613
  }
10226
10614
 
10227
10615
  // src/commands/op.ts
10228
- var import_chalk51 = __toESM(require("chalk"));
10616
+ var import_chalk52 = __toESM(require("chalk"));
10229
10617
  init_auth();
10230
10618
  init_trace();
10231
10619
  init_types();
10232
10620
 
10233
10621
  // src/commands/op-billing.ts
10234
- var import_chalk50 = __toESM(require("chalk"));
10622
+ var import_chalk51 = __toESM(require("chalk"));
10235
10623
  init_admin();
10236
10624
  var SANDBOX = {
10237
10625
  teamId: "team_1782844865835_zujrf",
@@ -10290,7 +10678,7 @@ async function rowsForRays(project, version2, tenant2, rays) {
10290
10678
  }
10291
10679
  function printDoors(data) {
10292
10680
  const checks = [];
10293
- console.log(import_chalk50.default.bold("\n Doors \u2014 is every way in metered?\n"));
10681
+ console.log(import_chalk51.default.bold("\n Doors \u2014 is every way in metered?\n"));
10294
10682
  const doors = data?.doors ?? [];
10295
10683
  const metered = doors.filter((d) => d.verdict === "metered");
10296
10684
  const allowed = doors.filter((d) => d.verdict === "allowed-free");
@@ -10299,29 +10687,29 @@ function printDoors(data) {
10299
10687
  const errs = data?.errors ?? [];
10300
10688
  const routeAuditBroke = errs.some((e) => e.startsWith("zone "));
10301
10689
  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(`
10690
+ console.log(import_chalk51.default.dim(` ${metered.length} route(s) behind main-proxy (metered)`));
10691
+ for (const d of metered) console.log(import_chalk51.default.green(` \u2713 ${d.pattern}`));
10692
+ console.log(import_chalk51.default.dim(`
10305
10693
  ${allowed.length} route(s) free ON PURPOSE`));
10306
10694
  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}`));
10695
+ console.log(import_chalk51.default.cyan(` \u2022 ${d.pattern}`) + import_chalk51.default.dim(` \u2192 ${d.script}`));
10696
+ console.log(import_chalk51.default.dim(` ${d.why}`));
10309
10697
  }
10310
10698
  if (known.length) {
10311
- console.log(import_chalk50.default.yellow(`
10699
+ console.log(import_chalk51.default.yellow(`
10312
10700
  ${known.length} route(s) KNOWN OPEN \u2014 unmetered, not yet closed`));
10313
10701
  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}`));
10702
+ console.log(import_chalk51.default.yellow(` ! ${d.pattern}`) + import_chalk51.default.dim(` \u2192 ${d.script}`));
10703
+ console.log(import_chalk51.default.dim(` ${d.why}`));
10316
10704
  }
10317
10705
  checks.push({ name: "no known-open doors", status: "KNOWN", detail: `${known.length} unmetered route(s) still open \u2014 see above` });
10318
10706
  }
10319
10707
  if (stray.length) {
10320
- console.log(import_chalk50.default.red(`
10708
+ console.log(import_chalk51.default.red(`
10321
10709
  ${stray.length} STRAY route(s) \u2014 not main-proxy, not on the allowlist`));
10322
10710
  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}`));
10711
+ console.log(import_chalk51.default.red(` \u2717 ${d.pattern}`) + import_chalk51.default.dim(` \u2192 ${d.script}`));
10712
+ console.log(import_chalk51.default.dim(` ${d.why}`));
10325
10713
  }
10326
10714
  checks.push({ name: "no stray routes", status: "FAIL", detail: `${stray.length}: ${stray.map((s) => s.pattern).join(", ")}` });
10327
10715
  } else if (routeAuditBroke) {
@@ -10332,22 +10720,22 @@ function printDoors(data) {
10332
10720
  const wd = data?.workers_dev ?? {};
10333
10721
  const open = wd.enabled ?? [];
10334
10722
  if (open.length) {
10335
- console.log(import_chalk50.default.red(`
10723
+ console.log(import_chalk51.default.red(`
10336
10724
  ${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."));
10725
+ 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})`));
10726
+ console.log(import_chalk51.default.dim(" A workers.dev hostname bypasses every CF route, WAF rule and the credit gate."));
10339
10727
  checks.push({ name: "no workers.dev doors", status: "FAIL", detail: `${open.length} script(s) publicly reachable: ${open.map((s) => s.script).join(", ")}` });
10340
10728
  } else if (devAuditBroke || !wd.total) {
10341
10729
  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
10730
  } else {
10343
- console.log(import_chalk50.default.green(`
10731
+ console.log(import_chalk51.default.green(`
10344
10732
  \u2713 0 of ${wd.total} workers reachable on *.workers.dev`));
10345
10733
  checks.push({ name: "no workers.dev doors", status: "PASS", detail: `all ${wd.total} scripts have workers.dev + previews disabled` });
10346
10734
  }
10347
- if (data?.how_to_fix) console.log(import_chalk50.default.yellow(`
10348
- ${data.reason}`) + import_chalk50.default.dim(`
10735
+ if (data?.how_to_fix) console.log(import_chalk51.default.yellow(`
10736
+ ${data.reason}`) + import_chalk51.default.dim(`
10349
10737
  ${data.how_to_fix}`));
10350
- else for (const e of errs) console.log(import_chalk50.default.red(`
10738
+ else for (const e of errs) console.log(import_chalk51.default.red(`
10351
10739
  audit error: ${e}`));
10352
10740
  if (errs.length) {
10353
10741
  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 +10745,9 @@ function printDoors(data) {
10357
10745
  async function runMeter(readLedger, opts) {
10358
10746
  const checks = [];
10359
10747
  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"));
10748
+ console.log(import_chalk51.default.bold("\n Meter \u2014 is 1 request charged exactly 1 request?\n"));
10361
10749
  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
10750
+ 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
10751
  `));
10364
10752
  const url = `https://${dpHost}/${SANDBOX.version}/${SANDBOX.environment}/`;
10365
10753
  const headers = opts.key ? { "X-API-Key": opts.key } : {};
@@ -10441,22 +10829,22 @@ async function runMeter(readLedger, opts) {
10441
10829
  return checks;
10442
10830
  }
10443
10831
  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") };
10832
+ console.log(import_chalk51.default.bold("\n Results\n"));
10833
+ 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
10834
  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}`));
10835
+ console.log(` ${mark[ch.status]} ${import_chalk51.default.bold(ch.name)}`);
10836
+ console.log(import_chalk51.default.dim(` ${ch.detail}`));
10449
10837
  }
10450
10838
  const fails = checks.filter((c) => c.status === "FAIL").length;
10451
10839
  const skips = checks.filter((c) => c.status === "SKIP").length;
10452
10840
  const known = checks.filter((c) => c.status === "KNOWN").length;
10453
10841
  console.log("");
10454
10842
  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.`));
10843
+ if (fails) console.log(import_chalk51.default.red(` ${fails} check(s) FAILED.`));
10844
+ else if (passes) console.log(import_chalk51.default.green(` ${passes} check(s) passed, 0 failed.`));
10845
+ else console.log(import_chalk51.default.yellow(" NOTHING WAS VERIFIED \u2014 every check was skipped."));
10846
+ if (known) console.log(import_chalk51.default.yellow(` ${known} known-open issue(s) still outstanding.`));
10847
+ if (skips) console.log(import_chalk51.default.dim(` ${skips} check(s) NOT RUN (see SKIP above) \u2014 those invariants are unverified.`));
10460
10848
  console.log("");
10461
10849
  }
10462
10850
 
@@ -10503,93 +10891,93 @@ var OP_COMMANDS = [
10503
10891
  function renderOpCommands() {
10504
10892
  const width = Math.max(...OP_COMMANDS.map((c) => c.cmd.length)) + 10;
10505
10893
  const lines = OP_COMMANDS.map((c) => {
10506
- const left = ` ${import_chalk51.default.cyan(`apiblaze ${c.cmd}`)}`;
10894
+ const left = ` ${import_chalk52.default.cyan(`apiblaze ${c.cmd}`)}`;
10507
10895
  const pad = " ".repeat(Math.max(1, width - c.cmd.length));
10508
- return `${left}${pad}${c.blurb}${c.extra ? " " + import_chalk51.default.dim(`(${c.extra})`) : ""}`;
10896
+ return `${left}${pad}${c.blurb}${c.extra ? " " + import_chalk52.default.dim(`(${c.extra})`) : ""}`;
10509
10897
  });
10510
10898
  return [
10511
- import_chalk51.default.bold("Operator commands"),
10899
+ import_chalk52.default.bold("Operator commands"),
10512
10900
  ...lines,
10513
10901
  "",
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`."),
10902
+ import_chalk52.default.dim(" Operators only. The gate is server-side (dashboard /api/cli/op checks the"),
10903
+ import_chalk52.default.dim(" signed-in email, admin-api re-checks with operatorGate) \u2014 a patched CLI just"),
10904
+ import_chalk52.default.dim(" gets 403s. Every op call is read-only except `op sweep`."),
10517
10905
  "",
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.")
10906
+ import_chalk52.default.dim(" Not a CLI command: to prune all non-CP data run scripts/nuke-but-cp.sh --apply --sweep"),
10907
+ import_chalk52.default.dim(" in the repo. Operator dashboards (dlq, thresholds, throttling, pricing, billing,"),
10908
+ import_chalk52.default.dim(" agent-spend, teams, tests, leak-detection, lifecycle) live at /operator/* in the app.")
10521
10909
  ].join("\n");
10522
10910
  }
10523
10911
  function printResidue(report, applied) {
10524
10912
  const up = report?.upstash ?? {};
10525
10913
  const fga = report?.fga ?? {};
10526
10914
  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"));
10915
+ console.log(import_chalk52.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
10916
+ console.log(import_chalk52.default.bold("\n Upstash"));
10529
10917
  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}`));
10918
+ if (orphans.length === 0) console.log(import_chalk52.default.green(" no orphaned keys"));
10919
+ for (const o of orphans) console.log(` ${import_chalk52.default.yellow(o.key)} ${import_chalk52.default.dim(`\u2014 ${o.reason}`)}`);
10920
+ console.log(import_chalk52.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
10533
10921
  if (up.anon_wallet_detail) {
10534
10922
  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)"}`));
10923
+ 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
10924
  }
10537
10925
  if (up.keyspace_census) {
10538
10926
  const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
10539
- console.log(import_chalk51.default.dim(` keyspace: ${census}`));
10927
+ console.log(import_chalk52.default.dim(` keyspace: ${census}`));
10540
10928
  }
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"));
10929
+ if (up.unknown?.length) console.log(import_chalk52.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
10930
+ if (applied) console.log(` ${import_chalk52.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
10931
+ for (const e of up.errors ?? []) console.log(import_chalk52.default.red(` error: ${e}`));
10932
+ console.log(import_chalk52.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
10545
10933
  if (applied) {
10546
10934
  const swept = fga?.swept ?? [];
10547
- if (swept.length === 0) console.log(import_chalk51.default.green(" no orphaned stores"));
10935
+ if (swept.length === 0) console.log(import_chalk52.default.green(" no orphaned stores"));
10548
10936
  for (const s of swept) {
10549
10937
  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`)}`
10938
+ ` ${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
10939
  );
10552
10940
  }
10553
- if (fga?.remaining) console.log(import_chalk51.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
10941
+ if (fga?.remaining) console.log(import_chalk52.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
10554
10942
  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})` : ""}`));
10943
+ 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
10944
  } else {
10557
10945
  const fgaOrphans = fga?.orphans ?? [];
10558
- if (fgaOrphans.length === 0) console.log(import_chalk51.default.green(" no orphaned stores"));
10946
+ if (fgaOrphans.length === 0) console.log(import_chalk52.default.green(" no orphaned stores"));
10559
10947
  for (const s of fgaOrphans) {
10560
10948
  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)`)}`);
10949
+ 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
10950
  }
10563
- console.log(import_chalk51.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
10951
+ console.log(import_chalk52.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
10564
10952
  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`));
10953
+ 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
10954
  }
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"));
10955
+ for (const e of fga?.errors ?? []) console.log(import_chalk52.default.red(` error: ${e}`));
10956
+ console.log(import_chalk52.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
10569
10957
  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)`)}`);
10958
+ if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk52.default.green(" no ghost tuples"));
10959
+ 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
10960
  } else {
10573
10961
  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)`)}`));
10962
+ 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
10963
  else {
10576
- console.log(import_chalk51.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
10964
+ console.log(import_chalk52.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
10577
10965
  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}`));
10966
+ console.log(import_chalk52.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
10579
10967
  }
10580
- if (n > 20) console.log(import_chalk51.default.dim(` \u2026 and ${n - 20} more`));
10968
+ if (n > 20) console.log(import_chalk52.default.dim(` \u2026 and ${n - 20} more`));
10581
10969
  }
10582
10970
  }
10583
- for (const e of ghosts?.errors ?? []) console.log(import_chalk51.default.red(` error: ${e}`));
10971
+ for (const e of ghosts?.errors ?? []) console.log(import_chalk52.default.red(` error: ${e}`));
10584
10972
  console.log();
10585
10973
  }
10586
10974
  async function runOp(sub, opts = {}, view) {
10587
10975
  if (!loadCredentials()) {
10588
- console.log(import_chalk51.default.dim("Not logged in. Run `apiblaze login`."));
10976
+ console.log(import_chalk52.default.dim("Not logged in. Run `apiblaze login`."));
10589
10977
  return;
10590
10978
  }
10591
10979
  if (!isOperatorLogin()) {
10592
- console.log(import_chalk51.default.dim("`apiblaze op` is only available to platform operators."));
10980
+ console.log(import_chalk52.default.dim("`apiblaze op` is only available to platform operators."));
10593
10981
  return;
10594
10982
  }
10595
10983
  switch (sub) {
@@ -10615,17 +11003,17 @@ async function runOp(sub, opts = {}, view) {
10615
11003
  const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
10616
11004
  printResidue(report, false);
10617
11005
  if (nUp + nFga + nGhost + nSide === 0) {
10618
- console.log(import_chalk51.default.green("Nothing to sweep."));
11006
+ console.log(import_chalk52.default.green("Nothing to sweep."));
10619
11007
  return;
10620
11008
  }
10621
11009
  if (!opts.yes) {
10622
11010
  const readline3 = await import("readline/promises");
10623
11011
  const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
10624
11012
  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: `)
11013
+ 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
11014
  );
10627
11015
  rl.close();
10628
- if (answer.trim() !== "sweep") return void console.log(import_chalk51.default.dim("Aborted."));
11016
+ if (answer.trim() !== "sweep") return void console.log(import_chalk52.default.dim("Aborted."));
10629
11017
  }
10630
11018
  const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
10631
11019
  if (opts.json) return void console.log(JSON.stringify(result, null, 2));
@@ -10635,25 +11023,25 @@ async function runOp(sub, opts = {}, view) {
10635
11023
  case "mark": {
10636
11024
  const label3 = (view ?? "").trim();
10637
11025
  if (!label3) {
10638
- console.log(import_chalk51.default.red("Give the change a name:") + import_chalk51.default.cyan(' apiblaze op mark "cached tenant count"'));
11026
+ console.log(import_chalk52.default.red("Give the change a name:") + import_chalk52.default.cyan(' apiblaze op mark "cached tenant count"'));
10639
11027
  return;
10640
11028
  }
10641
11029
  const res = await opCall({ method: "POST", path: "/operator/latency/mark", body: { label: label3 }, summary: "record change marker" });
10642
11030
  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");
11031
+ console.log(import_chalk52.default.green(`
11032
+ Marked: `) + import_chalk52.default.bold(label3));
11033
+ console.log(import_chalk52.default.dim(` ${ts}`));
11034
+ 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
11035
  return;
10648
11036
  }
10649
11037
  case "credits": {
10650
11038
  const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list credit wallets" });
10651
11039
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10652
11040
  const accounts = data?.accounts ?? [];
10653
- if (accounts.length === 0) return void console.log(import_chalk51.default.dim("No credit wallets."));
11041
+ if (accounts.length === 0) return void console.log(import_chalk52.default.dim("No credit wallets."));
10654
11042
  for (const a of accounts) {
10655
11043
  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") : ""}`);
11044
+ 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
11045
  }
10658
11046
  return;
10659
11047
  }
@@ -10664,7 +11052,7 @@ async function runOp(sub, opts = {}, view) {
10664
11052
  case "billing": {
10665
11053
  const which = (view ?? "").trim().toLowerCase();
10666
11054
  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.`));
11055
+ return void console.log(import_chalk52.default.red(`Unknown: apiblaze op billing ${which}. Use 'doors', 'meter', or neither for both.`));
10668
11056
  }
10669
11057
  const checks = [];
10670
11058
  let doorsData = null;
@@ -10725,29 +11113,29 @@ async function runOp(sub, opts = {}, view) {
10725
11113
  const data = await opCall({ method: "GET", path: `/operator/latency/grades${q}`, summary: "latency grades" });
10726
11114
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10727
11115
  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+
11116
+ 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)"));
11117
+ 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
11118
  `));
10731
- console.log(import_chalk51.default.dim(" date reqs excellent okay bad terrible"));
11119
+ console.log(import_chalk52.default.dim(" date reqs excellent okay bad terrible"));
10732
11120
  for (const d of data.days ?? []) {
10733
11121
  const p = d.pct;
10734
- const cell = (v, colour) => v > 0 ? colour(`${String(v).padStart(5)}%`) : import_chalk51.default.dim(`${String(v).padStart(5)}%`);
11122
+ const cell = (v, colour) => v > 0 ? colour(`${String(v).padStart(5)}%`) : import_chalk52.default.dim(`${String(v).padStart(5)}%`);
10735
11123
  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)}`
11124
+ ` ${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
11125
  );
10738
11126
  }
10739
11127
  const cul = data.culprits ?? [];
10740
11128
  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"));
11129
+ console.log(import_chalk52.default.bold("\n Who caused the bad and terrible ones\n"));
11130
+ console.log(import_chalk52.default.dim(" bad terrible feature \u2192 dependency"));
10743
11131
  for (const r of cul.slice(0, 12)) {
10744
11132
  if (!r.bad && !r.terrible) continue;
10745
11133
  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)}`
11134
+ ` ${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
11135
  );
10748
11136
  }
10749
11137
  }
10750
- if (data.caveat) console.log(import_chalk51.default.dim(`
11138
+ if (data.caveat) console.log(import_chalk52.default.dim(`
10751
11139
  \u26A0 ${data.caveat}
10752
11140
  `));
10753
11141
  return;
@@ -10756,24 +11144,24 @@ async function runOp(sub, opts = {}, view) {
10756
11144
  const data = await opCall({ method: "GET", path: `/operator/latency/compare${q}`, summary: "latency before/after" });
10757
11145
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10758
11146
  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
11147
+ console.log(import_chalk52.default.bold(`
11148
+ Before vs after: `) + import_chalk52.default.cyan(data.marker.label));
11149
+ console.log(import_chalk52.default.dim(` marked ${new Date(data.marker.ts).toISOString()} \xB7 ${data.window_hours}h either side
10762
11150
  `));
10763
11151
  const row = (name, before, after, delta) => {
10764
11152
  const arrow = delta === 0 ? "=" : delta < 0 ? "\u2193" : "\u2191";
10765
11153
  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)}`);
11154
+ 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
11155
  };
10768
- console.log(import_chalk51.default.dim(" metric before after change"));
11156
+ console.log(import_chalk52.default.dim(" metric before after change"));
10769
11157
  row("total p50", b.total_p50, a.total_p50, d.total_p50);
10770
11158
  row("total p95", b.total_p95, a.total_p95, d.total_p95);
10771
11159
  row("apiblaze overhead p50", b.gw_p50, a.gw_p50, d.gw_p50);
10772
11160
  row("apiblaze overhead p95", b.gw_p95, a.gw_p95, d.gw_p95);
10773
- console.log(import_chalk51.default.dim(`
11161
+ console.log(import_chalk52.default.dim(`
10774
11162
  requests: ${b.requests} before \xB7 ${a.requests} after`));
10775
11163
  for (const w of data.warnings ?? []) {
10776
- console.log((data.trustworthy ? import_chalk51.default.dim : import_chalk51.default.yellow)(` ${data.trustworthy ? "\xB7" : "\u26A0"} ${w}`));
11164
+ console.log((data.trustworthy ? import_chalk52.default.dim : import_chalk52.default.yellow)(` ${data.trustworthy ? "\xB7" : "\u26A0"} ${w}`));
10777
11165
  }
10778
11166
  console.log("");
10779
11167
  return;
@@ -10782,19 +11170,19 @@ Before vs after: `) + import_chalk51.default.cyan(data.marker.label));
10782
11170
  const data = await opCall({ method: "GET", path: `/operator/latency/slow${q}`, summary: "slowest requests" });
10783
11171
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10784
11172
  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(`
11173
+ if (!rows2.length) return void console.log(import_chalk52.default.dim("No requests over the threshold in that window."));
11174
+ console.log(import_chalk52.default.bold(`
10787
11175
  Slowest requests \u2014 last ${data.window_hours}h, over ${data.min_ms}ms
10788
11176
  `));
10789
- console.log(import_chalk51.default.dim(" total ours theirs blame request id"));
11177
+ console.log(import_chalk52.default.dim(" total ours theirs blame request id"));
10790
11178
  for (const r of rows2.slice(0, 30)) {
10791
11179
  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 || "")}`
11180
+ ` ${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
11181
  );
10794
11182
  }
10795
- console.log(import_chalk51.default.dim(`
11183
+ console.log(import_chalk52.default.dim(`
10796
11184
  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.
11185
+ console.log(import_chalk52.default.dim(` \`apiblaze logs\` for that request's exact per-feature breakdown \u2014 unsampled, unlike the table above.
10798
11186
  `));
10799
11187
  return;
10800
11188
  }
@@ -10802,18 +11190,18 @@ Slowest requests \u2014 last ${data.window_hours}h, over ${data.min_ms}ms
10802
11190
  const data = await opCall({ method: "GET", path: `/operator/latency/llm${q}`, summary: "llm latency" });
10803
11191
  if (opts.json) return void console.log(JSON.stringify(data, null, 2));
10804
11192
  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(`
11193
+ if (!rows2.length) return void console.log(import_chalk52.default.dim("No LLM traffic in that window."));
11194
+ console.log(import_chalk52.default.bold(`
10807
11195
  LLM timing \u2014 last ${data.window_hours}h
10808
11196
  `));
10809
- console.log(import_chalk51.default.dim(" turns turn p95 ttfc p95 gen p95 reserve p95 in/out tokens p95 model"));
11197
+ console.log(import_chalk52.default.dim(" turns turn p95 ttfc p95 gen p95 reserve p95 in/out tokens p95 model"));
10810
11198
  for (const r of rows2) {
10811
11199
  const n = r.turns ?? r.requests ?? 0;
10812
11200
  console.log(
10813
11201
  ` ${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
11202
  );
10815
11203
  }
10816
- console.log(import_chalk51.default.dim(`
11204
+ console.log(import_chalk52.default.dim(`
10817
11205
  ${data.note}
10818
11206
  `));
10819
11207
  return;
@@ -10824,26 +11212,26 @@ LLM timing \u2014 last ${data.window_hours}h
10824
11212
  ]);
10825
11213
  if (opts.json) return void console.log(JSON.stringify({ blame, summary }, null, 2));
10826
11214
  const ov = summary?.apiblaze_overhead_ms ?? {};
10827
- console.log(import_chalk51.default.bold(`
11215
+ console.log(import_chalk52.default.bold(`
10828
11216
  Latency \u2014 last ${summary?.window_hours ?? "?"}h, ${Number(summary?.requests ?? 0).toLocaleString()} requests
10829
11217
  `));
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)
11218
+ 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")}`);
11219
+ 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")}`);
11220
+ console.log(import_chalk52.default.dim(` (per-request percentiles \u2014 never subtract one from the other)
10833
11221
  `));
10834
11222
  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"));
11223
+ if (!rows.length) return void console.log(import_chalk52.default.dim("No latency rows in that window."));
11224
+ console.log(import_chalk52.default.bold(" Which feature ate the time, and what inside it\n"));
11225
+ console.log(import_chalk52.default.dim(" share p95 feature \u2192 dependency"));
10838
11226
  for (const r of rows.slice(0, 15)) {
10839
11227
  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)}`);
11228
+ 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
11229
  }
10842
11230
  console.log("");
10843
11231
  return;
10844
11232
  }
10845
11233
  default:
10846
- console.log(import_chalk51.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
11234
+ console.log(import_chalk52.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
10847
11235
  }
10848
11236
  }
10849
11237
 
@@ -10876,7 +11264,7 @@ program.command("login").description("Authenticate with APIblaze").option("--tea
10876
11264
  process.exit(1);
10877
11265
  }
10878
11266
  });
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) => {
11267
+ 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
11268
  try {
10881
11269
  await runCreate({ ...opts, openapi: opts.openapi ?? opts.openapispec });
10882
11270
  } catch (err) {
@@ -10889,7 +11277,7 @@ agent.command("authz").description("Chat to design and turn on access rules for
10889
11277
  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
11278
  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
11279
  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 })));
11280
+ 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("--verbose", "Show the per-turn proxy curl trace (hidden by default)").option("-p, --prompt <question>", "One-shot question: answered through the external agent CLI after an MCP install, or by apichat itself (exits after answering when there is no TTY)").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
11281
  var llm = program.command("llm").description("Manage a local LLM provider key for chat (optional \u2014 lifts model quality, bills your key)");
10894
11282
  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
11283
  llm.command("show").description("Show the locally stored LLM key (masked)").action(action(() => runLlmShow()));
@@ -10906,7 +11294,7 @@ program.command("dev").description("Put your localhost behind a public URL (dev
10906
11294
  try {
10907
11295
  const resolved = parseInt(port ?? opts.port, 10);
10908
11296
  if (Number.isNaN(resolved)) {
10909
- console.error(import_chalk52.default.red(`Invalid port: ${port ?? opts.port}`));
11297
+ console.error(import_chalk53.default.red(`Invalid port: ${port ?? opts.port}`));
10910
11298
  process.exit(1);
10911
11299
  }
10912
11300
  await runDev({ port: resolved, project: opts.project, yes: opts.yes, captureFile: opts.captureFile, newSession: opts.newSession });
@@ -11038,7 +11426,7 @@ function groupedCommandHelp() {
11038
11426
  const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
11039
11427
  return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
11040
11428
  }).filter(Boolean).join("\n");
11041
- return `${import_chalk52.default.bold(g.title)}
11429
+ return `${import_chalk53.default.bold(g.title)}
11042
11430
  ${rows}`;
11043
11431
  }).join("\n\n");
11044
11432
  }
@@ -11076,14 +11464,14 @@ async function recoverStaleTeam() {
11076
11464
  const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
11077
11465
  const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
11078
11466
  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."));
11467
+ console.error(import_chalk53.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
11080
11468
  return;
11081
11469
  }
11082
11470
  if (linked.teamId === creds.teamId) return;
11083
11471
  const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
11084
11472
  delete next.activeTenant;
11085
11473
  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.`));
11474
+ 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
11475
  } catch {
11088
11476
  }
11089
11477
  }
@@ -11091,16 +11479,16 @@ async function printError(err) {
11091
11479
  if (err instanceof ApiError) {
11092
11480
  const data = err.body;
11093
11481
  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(`
11482
+ console.error(import_chalk53.default.red(`
11095
11483
  API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
11096
11484
  if (err.status === 403 || err.status === 404) {
11097
11485
  await recoverStaleTeam();
11098
11486
  }
11099
11487
  } else if (err instanceof Error) {
11100
- console.error(import_chalk52.default.red(`
11488
+ console.error(import_chalk53.default.red(`
11101
11489
  Error: ${err.message}`));
11102
11490
  } else {
11103
- console.error(import_chalk52.default.red("\nUnknown error"));
11491
+ console.error(import_chalk53.default.red("\nUnknown error"));
11104
11492
  }
11105
11493
  }
11106
11494
  program.parse(process.argv);