apiblaze 0.21.72 → 0.21.73

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 +1067 -921
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ var __toESM = (mod, isNodeMode, target2) => (target2 = mod != null ? __create(__
34
34
  var version;
35
35
  var init_package = __esm({
36
36
  "package.json"() {
37
- version = "0.21.72";
37
+ version = "0.21.73";
38
38
  }
39
39
  });
40
40
 
@@ -424,7 +424,10 @@ function recordCall(e) {
424
424
  }
425
425
  function maskBody(body) {
426
426
  if (body === void 0) return void 0;
427
- return JSON.stringify(body, (k, v) => SECRET_KEY.test(k) && typeof v === "string" ? "***" : v);
427
+ return JSON.stringify(body, function(k, v) {
428
+ if (typeof v !== "string") return v;
429
+ return SECRET_KEY.test(k) || k === "value" && this?.value_secret === true ? "***" : v;
430
+ });
428
431
  }
429
432
  function renderTrace() {
430
433
  if (!verbose || entries.length === 0) return;
@@ -7227,6 +7230,261 @@ var init_create = __esm({
7227
7230
  }
7228
7231
  });
7229
7232
 
7233
+ // src/commands/config.ts
7234
+ var config_exports = {};
7235
+ __export(config_exports, {
7236
+ environmentsWithTarget: () => environmentsWithTarget,
7237
+ runRename: () => runRename,
7238
+ runTargetSet: () => runTargetSet
7239
+ });
7240
+ async function patchConfig(project, opts, body, summary) {
7241
+ const caller = requireCaller();
7242
+ const { teamId } = await resolveActingTeam(caller, opts.team);
7243
+ const proj2 = await resolveProjectVia(caller, teamId, project, opts.apiversion);
7244
+ const spinner = (0, import_ora9.default)(summary + "...").start();
7245
+ try {
7246
+ const out = await producer(caller, {
7247
+ method: "PATCH",
7248
+ path: `/projects/${proj2.projectId}/${proj2.apiVersion}`,
7249
+ body,
7250
+ summary
7251
+ });
7252
+ spinner.succeed(`${summary} \u2014 ${proj2.projectName} v${proj2.apiVersion}.`);
7253
+ if (opts.json) console.log(JSON.stringify(out ?? { ok: true }));
7254
+ } catch (err) {
7255
+ spinner.fail(summary + " failed.");
7256
+ throw err;
7257
+ }
7258
+ }
7259
+ async function runTargetSet(project, opts) {
7260
+ if (!opts.url) {
7261
+ console.error(import_chalk24.default.red("--url is required."));
7262
+ process.exit(1);
7263
+ }
7264
+ if (!opts.env) {
7265
+ await patchConfig(project, opts, { target_url: opts.url }, `Set target \u2192 ${opts.url}`);
7266
+ return;
7267
+ }
7268
+ const caller = requireCaller();
7269
+ const { teamId } = await resolveActingTeam(caller, opts.team);
7270
+ const proj2 = await resolveProjectVia(caller, teamId, project, opts.apiversion);
7271
+ const environments = await environmentsWithTarget(caller, teamId, proj2, opts.env, opts.url);
7272
+ await patchConfig(project, opts, { environments }, `Set target for env ${opts.env} \u2192 ${opts.url}`);
7273
+ }
7274
+ async function environmentsWithTarget(caller, teamId, proj2, env, url) {
7275
+ const listing = await pageAll(
7276
+ (cursor) => producer(caller, {
7277
+ method: "GET",
7278
+ path: withPage(`/projects?team_id=${encodeURIComponent(teamId)}`, cursor),
7279
+ summary: `Read environments for ${proj2.projectName}`
7280
+ }),
7281
+ (b) => b?.projects
7282
+ );
7283
+ const row = listing.items.find((r) => r.project_id === proj2.projectId && r.api_version === proj2.apiVersion);
7284
+ const current = row?.config?.environments;
7285
+ const existing = current && typeof current === "object" && !Array.isArray(current) ? current : {};
7286
+ const prev = existing[env];
7287
+ return { ...existing, [env]: { ...prev && typeof prev === "object" ? prev : {}, target: url } };
7288
+ }
7289
+ async function runRename(project, opts) {
7290
+ if (!opts.displayName) {
7291
+ console.error(import_chalk24.default.red("--display-name is required."));
7292
+ process.exit(1);
7293
+ }
7294
+ await patchConfig(project, opts, { display_name: opts.displayName }, `Rename \u2192 "${opts.displayName}"`);
7295
+ }
7296
+ var import_chalk24, import_ora9;
7297
+ var init_config = __esm({
7298
+ "src/commands/config.ts"() {
7299
+ "use strict";
7300
+ import_chalk24 = __toESM(require("chalk"));
7301
+ import_ora9 = __toESM(require("ora"));
7302
+ init_caller();
7303
+ init_paging();
7304
+ }
7305
+ });
7306
+
7307
+ // src/commands/transform.ts
7308
+ var transform_exports = {};
7309
+ __export(transform_exports, {
7310
+ parseEntries: () => parseEntries,
7311
+ runTransformList: () => runTransformList,
7312
+ runTransformMap: () => runTransformMap,
7313
+ runTransformMapping: () => runTransformMapping,
7314
+ runTransformRemove: () => runTransformRemove,
7315
+ runTransformSetHeader: () => runTransformSetHeader,
7316
+ setUpstreamHeader: () => setUpstreamHeader
7317
+ });
7318
+ async function target(project, opts) {
7319
+ const caller = requireCaller();
7320
+ const { teamId } = await resolveActingTeam(caller, opts.team);
7321
+ const proj2 = await resolveProjectVia(caller, teamId, project, opts.apiversion);
7322
+ const base2 = `/projects/${encodeURIComponent(proj2.projectId)}/${encodeURIComponent(proj2.apiVersion)}/transforms`;
7323
+ return { caller, proj: proj2, base: base2 };
7324
+ }
7325
+ async function listRules(t) {
7326
+ const out = await producer(t.caller, {
7327
+ method: "GET",
7328
+ path: t.base,
7329
+ summary: `List transforms for ${t.proj.projectName}`
7330
+ });
7331
+ return out?.rules ?? [];
7332
+ }
7333
+ function describe(r) {
7334
+ const a = r.action ?? { type: "?" };
7335
+ if (a.type === "hardcode") {
7336
+ const secret = !a.value || /^abzsec:|^__ABZSEC_|^•+$/.test(a.value);
7337
+ return `set ${a.destination} = ${secret ? "(secret)" : a.value}`;
7338
+ }
7339
+ if (a.type === "remove") return `remove ${a.field}`;
7340
+ if (a.type === "map") return `map ${a.source} \u2192 ${a.destination}${a.lookup?.mapping_id ? " (through a mapping table)" : ""}`;
7341
+ return a.type;
7342
+ }
7343
+ async function runTransformList(project, opts) {
7344
+ const t = await target(project, opts);
7345
+ const rules = await listRules(t);
7346
+ if (opts.json) {
7347
+ console.log(JSON.stringify(rules, null, 2));
7348
+ return;
7349
+ }
7350
+ if (!rules.length) {
7351
+ console.log(import_chalk25.default.dim(`No transforms on ${t.proj.projectName} v${t.proj.apiVersion}.`));
7352
+ return;
7353
+ }
7354
+ for (const r of rules) {
7355
+ console.log(`${r.enabled ? import_chalk25.default.green("\u25CF") : import_chalk25.default.gray("\u25CB")} ${import_chalk25.default.bold(r.name)} ${import_chalk25.default.dim(`[${r.phase}] ${r.id}`)}`);
7356
+ console.log(` ${describe(r)}`);
7357
+ }
7358
+ }
7359
+ async function headerUpsert(t, header, value, secret) {
7360
+ const name = ruleNameFor(header);
7361
+ const action = {
7362
+ type: "hardcode",
7363
+ destination: `header:${header}`,
7364
+ value,
7365
+ // Encrypted at rest and masked on every read; main-proxy decrypts it only
7366
+ // on the way to the upstream.
7367
+ ...secret ? { value_secret: true } : {}
7368
+ };
7369
+ const existing = (await listRules(t)).find((r) => r.name === name && r.phase === "request");
7370
+ const summary = `${existing ? "Update" : "Add"} transform: send ${header} to the upstream`;
7371
+ const send = () => producer(t.caller, existing ? { method: "PUT", path: `${t.base}/${encodeURIComponent(existing.id)}`, body: { action, enabled: true }, summary } : { method: "POST", path: t.base, body: { name, action, phase: "request", enabled: true }, summary });
7372
+ return { summary, send };
7373
+ }
7374
+ async function setUpstreamHeader(caller, proj2, header, value) {
7375
+ if (!HEADER_NAME.test(header)) throw new Error(`"${header}" is not a valid header name.`);
7376
+ if (!value) throw new Error(`The value for ${header} is empty.`);
7377
+ const base2 = `/projects/${encodeURIComponent(proj2.projectId)}/${encodeURIComponent(proj2.apiVersion)}/transforms`;
7378
+ await (await headerUpsert({ caller, proj: proj2, base: base2 }, header, value, true)).send();
7379
+ }
7380
+ async function runTransformSetHeader(project, header, opts) {
7381
+ if (!HEADER_NAME.test(header)) throw new Error(`"${header}" is not a valid header name.`);
7382
+ if (opts.value === void 0 === (opts.valueEnv === void 0)) {
7383
+ throw new Error("Pass exactly one of --value <value> or --value-env <VAR> (reads the value from that environment variable, so it stays out of your shell history).");
7384
+ }
7385
+ const value = opts.value ?? process.env[opts.valueEnv];
7386
+ if (!value) throw new Error(`Environment variable ${opts.valueEnv} is empty or not set.`);
7387
+ const t = await target(project, opts);
7388
+ const { summary, send } = await headerUpsert(t, header, value, !!opts.secret);
7389
+ const spinner = opts.json ? null : (0, import_ora10.default)(summary + "...").start();
7390
+ try {
7391
+ const out = await send();
7392
+ spinner?.succeed(`${summary} \u2014 ${t.proj.projectName} v${t.proj.apiVersion}${opts.secret ? " (stored encrypted)" : ""}.`);
7393
+ if (opts.json) console.log(JSON.stringify(out ?? { ok: true }));
7394
+ else console.log(import_chalk25.default.dim(` Every call the proxy forwards now carries ${header}. Your backend can reject calls without it.`));
7395
+ } catch (err) {
7396
+ spinner?.fail(summary + " failed.");
7397
+ throw err;
7398
+ }
7399
+ }
7400
+ async function runTransformRemove(project, nameOrId, opts) {
7401
+ const t = await target(project, opts);
7402
+ const rules = await listRules(t);
7403
+ const want = nameOrId.toLowerCase();
7404
+ const rule = rules.find((r) => r.id === nameOrId || r.name.toLowerCase() === want || r.name === ruleNameFor(nameOrId));
7405
+ if (!rule) {
7406
+ throw new Error(`No transform "${nameOrId}" on ${t.proj.projectName}.` + (rules.length ? ` Transforms: ${rules.map((r) => r.name).join(", ")}` : ""));
7407
+ }
7408
+ await producer(t.caller, {
7409
+ method: "DELETE",
7410
+ path: `${t.base}/${encodeURIComponent(rule.id)}`,
7411
+ summary: `Remove transform "${rule.name}"`
7412
+ });
7413
+ if (opts.json) console.log(JSON.stringify({ ok: true, removed: rule.id }));
7414
+ else console.log(`${import_chalk25.default.green("\u2713")} Removed transform ${import_chalk25.default.bold(rule.name)} from ${t.proj.projectName}.`);
7415
+ }
7416
+ function tablesBase(t) {
7417
+ return t.base.replace(/\/transforms$/, "/mappings");
7418
+ }
7419
+ async function listTables(t) {
7420
+ const out = await producer(t.caller, {
7421
+ method: "GET",
7422
+ path: tablesBase(t),
7423
+ summary: `List mapping tables for ${t.proj.projectName}`
7424
+ });
7425
+ return out?.tables ?? [];
7426
+ }
7427
+ function parseEntries(pairs) {
7428
+ return pairs.map((p) => {
7429
+ const i = p.indexOf("=");
7430
+ if (i <= 0) throw new Error(`"${p}" is not a from=to pair (e.g. FR=EUR).`);
7431
+ return { from: p.slice(0, i), to: p.slice(i + 1) };
7432
+ });
7433
+ }
7434
+ async function runTransformMapping(project, table, pairs, opts) {
7435
+ if (!pairs.length) throw new Error("Give at least one from=to pair, e.g. FR=EUR US=USD.");
7436
+ const entries2 = parseEntries(pairs);
7437
+ const t = await target(project, opts);
7438
+ const existing = (await listTables(t)).find((m) => m.name === table);
7439
+ const body = { name: table, entries: entries2, ...opts.secret ? { encrypt_values: true } : {} };
7440
+ const summary = `${existing ? "Replace" : "Create"} mapping table "${table}" (${entries2.length} entr${entries2.length === 1 ? "y" : "ies"})`;
7441
+ const out = await producer(t.caller, existing ? { method: "PUT", path: `${tablesBase(t)}/${encodeURIComponent(existing.id)}`, body, summary } : { method: "POST", path: tablesBase(t), body, summary });
7442
+ if (opts.json) {
7443
+ console.log(JSON.stringify(out ?? { ok: true }));
7444
+ return;
7445
+ }
7446
+ console.log(`${import_chalk25.default.green("\u2714")} ${summary} \u2014 ${t.proj.projectName} v${t.proj.apiVersion}.`);
7447
+ for (const e of entries2) console.log(import_chalk25.default.dim(` ${e.from} \u2192 ${opts.secret ? "(secret)" : e.to}`));
7448
+ }
7449
+ async function runTransformMap(project, source, destination, opts) {
7450
+ if (!FIELD_REF.test(source)) throw new Error(`Source "${source}" must look like header:X-Country, query:country or bodyvar:order.country.`);
7451
+ if (!/^(header|query|bodyvar):.+/.test(destination)) throw new Error(`Destination "${destination}" must look like header:X-Currency, query:currency or bodyvar:order.currency.`);
7452
+ if (!opts.table) throw new Error("--table <name> is required: the mapping table to look the value up in (create it with `transform mapping`).");
7453
+ const onNoMatch = opts.onNoMatch ?? "skip";
7454
+ if (!["skip", "fail", "passthrough"].includes(onNoMatch)) throw new Error("--on-no-match is skip, fail or passthrough.");
7455
+ const t = await target(project, opts);
7456
+ const table = (await listTables(t)).find((m) => m.name === opts.table);
7457
+ if (!table) throw new Error(`No mapping table "${opts.table}" on ${t.proj.projectName}. Create it: npx apiblaze transform mapping ${project} ${opts.table} FR=EUR \u2026`);
7458
+ const name = `map ${source} to ${destination}`;
7459
+ const action = {
7460
+ type: "map",
7461
+ source,
7462
+ destination,
7463
+ lookup: { mapping_id: table.id, on_no_match: onNoMatch }
7464
+ };
7465
+ const existing = (await listRules(t)).find((r) => r.name === name && r.phase === "request");
7466
+ const summary = `${existing ? "Update" : "Add"} transform: ${source} \u2192 ${destination} through "${table.name}"`;
7467
+ const out = await producer(t.caller, existing ? { method: "PUT", path: `${t.base}/${encodeURIComponent(existing.id)}`, body: { action, enabled: true }, summary } : { method: "POST", path: t.base, body: { name, action, phase: "request", enabled: true }, summary });
7468
+ if (opts.json) {
7469
+ console.log(JSON.stringify(out ?? { ok: true }));
7470
+ return;
7471
+ }
7472
+ console.log(`${import_chalk25.default.green("\u2714")} ${summary} \u2014 ${t.proj.projectName} v${t.proj.apiVersion}.`);
7473
+ console.log(import_chalk25.default.dim(` A value not in the table: ${onNoMatch === "skip" ? "nothing is written" : onNoMatch === "fail" ? "the call is refused" : "it is copied as-is"}.`));
7474
+ }
7475
+ var import_chalk25, import_ora10, HEADER_NAME, ruleNameFor, FIELD_REF;
7476
+ var init_transform = __esm({
7477
+ "src/commands/transform.ts"() {
7478
+ "use strict";
7479
+ import_chalk25 = __toESM(require("chalk"));
7480
+ import_ora10 = __toESM(require("ora"));
7481
+ init_caller();
7482
+ HEADER_NAME = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
7483
+ ruleNameFor = (header) => `set header ${header.toLowerCase()}`;
7484
+ FIELD_REF = /^(header|query|param|bodyvar|jwt):.+/;
7485
+ }
7486
+ });
7487
+
7230
7488
  // src/lib/tools.ts
7231
7489
  async function proj(teamId, name, version2) {
7232
7490
  return resolveProject(teamId, name, version2);
@@ -7237,11 +7495,11 @@ function toolCatalogue() {
7237
7495
  function findTool(name) {
7238
7496
  return TOOLS.find((t) => t.name === name);
7239
7497
  }
7240
- var import_chalk24, TOOLS;
7498
+ var import_chalk26, TOOLS;
7241
7499
  var init_tools = __esm({
7242
7500
  "src/lib/tools.ts"() {
7243
7501
  "use strict";
7244
- import_chalk24 = __toESM(require("chalk"));
7502
+ import_chalk26 = __toESM(require("chalk"));
7245
7503
  init_admin();
7246
7504
  init_api();
7247
7505
  init_resolve();
@@ -7270,15 +7528,15 @@ var init_tools = __esm({
7270
7528
  const key = keys.dev ?? Object.values(keys)[0];
7271
7529
  const url = `https://${a.name}.abz.run/${version2}/dev`;
7272
7530
  const tryIt = buildTryItCurl(url, auth, key, res.tenant);
7273
- const lines = [` ${import_chalk24.default.dim("Proxy URL:")} ${import_chalk24.default.bold(url)}`];
7274
- if (res.devPortal) lines.push(` ${import_chalk24.default.dim("Dev portal:")} ${res.devPortal}`);
7531
+ const lines = [` ${import_chalk26.default.dim("Proxy URL:")} ${import_chalk26.default.bold(url)}`];
7532
+ if (res.devPortal) lines.push(` ${import_chalk26.default.dim("Dev portal:")} ${res.devPortal}`);
7275
7533
  const envs = Object.keys(keys);
7276
7534
  if (envs.length) {
7277
- lines.push("", ` ${import_chalk24.default.bold("API keys")} ${import_chalk24.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
7535
+ lines.push("", ` ${import_chalk26.default.bold("API keys")} ${import_chalk26.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
7278
7536
  const w = Math.max(...envs.map((e) => e.length));
7279
- for (const env of envs) lines.push(` ${import_chalk24.default.cyan(env.padEnd(w))} ${import_chalk24.default.green(keys[env])}`);
7537
+ for (const env of envs) lines.push(` ${import_chalk26.default.cyan(env.padEnd(w))} ${import_chalk26.default.green(keys[env])}`);
7280
7538
  }
7281
- if (tryIt) lines.push("", ` ${import_chalk24.default.dim("Try it:")}`, ` ${import_chalk24.default.cyan(tryIt)}`);
7539
+ if (tryIt) lines.push("", ` ${import_chalk26.default.dim("Try it:")}`, ` ${import_chalk26.default.cyan(tryIt)}`);
7282
7540
  return { ...res, proxy_url: url, keys, ...tryIt ? { try_it: tryIt } : {}, display: lines.join("\n") };
7283
7541
  }
7284
7542
  },
@@ -7446,14 +7704,14 @@ function truncate(value, max = 1500) {
7446
7704
  }
7447
7705
  function printCost(resp) {
7448
7706
  const line = formatBilling(resp.billing);
7449
- if (line) console.log(import_chalk25.default.magenta(` ${line}`) + import_chalk25.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
7707
+ if (line) console.log(import_chalk27.default.magenta(` ${line}`) + import_chalk27.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
7450
7708
  }
7451
7709
  async function runAgent(opts) {
7452
7710
  requireAuth();
7453
7711
  const { teamId, teamName } = await resolveTeam(opts.team);
7454
7712
  const { default: inquirer3 } = await import("inquirer");
7455
- console.log(import_chalk25.default.bold("APIblaze agent") + import_chalk25.default.dim(` \xB7 team ${teamName ?? teamId}`));
7456
- console.log(import_chalk25.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
7713
+ console.log(import_chalk27.default.bold("APIblaze agent") + import_chalk27.default.dim(` \xB7 team ${teamName ?? teamId}`));
7714
+ console.log(import_chalk27.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
7457
7715
  const history = [];
7458
7716
  let queued = opts.first ?? (opts.seedFor ? `Seed realistic sample data through the proxy "${opts.seedFor}" so a directory reviewer sees a populated account: create a handful of records with each write tool, then list them back. Never mention or use credentials.` : null);
7459
7717
  while (true) {
@@ -7461,16 +7719,16 @@ async function runAgent(opts) {
7461
7719
  if (queued) {
7462
7720
  text = queued;
7463
7721
  queued = null;
7464
- console.log(import_chalk25.default.cyan("you") + " \u203A " + text);
7722
+ console.log(import_chalk27.default.cyan("you") + " \u203A " + text);
7465
7723
  } else {
7466
- const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk25.default.cyan("you") + " \u203A" }]);
7724
+ const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk27.default.cyan("you") + " \u203A" }]);
7467
7725
  text = (input ?? "").trim();
7468
7726
  }
7469
7727
  if (!text) continue;
7470
7728
  if (["exit", "quit", ":q"].includes(text.toLowerCase())) break;
7471
7729
  history.push({ role: "user", content: text });
7472
7730
  for (let step = 0; step < MAX_TOOL_STEPS; step++) {
7473
- const spinner = (0, import_ora9.default)({ text: "thinking...", color: "magenta" }).start();
7731
+ const spinner = (0, import_ora11.default)({ text: "thinking...", color: "magenta" }).start();
7474
7732
  let resp;
7475
7733
  try {
7476
7734
  resp = await callAgent(history, teamId);
@@ -7485,14 +7743,14 @@ async function runAgent(opts) {
7485
7743
  }
7486
7744
  history.push({ role: "assistant", content: resp.raw });
7487
7745
  printCost(resp);
7488
- if (resp.reply) console.log(import_chalk25.default.green("agent") + " \u203A " + resp.reply);
7746
+ if (resp.reply) console.log(import_chalk27.default.green("agent") + " \u203A " + resp.reply);
7489
7747
  if (!resp.action) break;
7490
7748
  const tool = findTool(resp.action.tool);
7491
7749
  if (!tool) {
7492
7750
  history.push({ role: "user", content: `TOOL_RESULT ${resp.action.tool}: error \u2014 unknown tool` });
7493
7751
  continue;
7494
7752
  }
7495
- const runSpinner = (0, import_ora9.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
7753
+ const runSpinner = (0, import_ora11.default)({ text: `running ${tool.name}...`, color: "cyan" }).start();
7496
7754
  try {
7497
7755
  const result = await tool.run(resp.action.args, { teamId });
7498
7756
  runSpinner.succeed(`${tool.name} \u2713`);
@@ -7510,18 +7768,18 @@ async function runAgent(opts) {
7510
7768
  }
7511
7769
  renderTrace();
7512
7770
  if (step === MAX_TOOL_STEPS - 1) {
7513
- console.log(import_chalk25.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
7771
+ console.log(import_chalk27.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
7514
7772
  }
7515
7773
  }
7516
7774
  }
7517
- console.log(import_chalk25.default.dim("\nBye."));
7775
+ console.log(import_chalk27.default.dim("\nBye."));
7518
7776
  }
7519
- var import_chalk25, import_ora9, DASHBOARD_BASE7, MAX_TOOL_STEPS;
7777
+ var import_chalk27, import_ora11, DASHBOARD_BASE7, MAX_TOOL_STEPS;
7520
7778
  var init_agent = __esm({
7521
7779
  "src/commands/agent.ts"() {
7522
7780
  "use strict";
7523
- import_chalk25 = __toESM(require("chalk"));
7524
- import_ora9 = __toESM(require("ora"));
7781
+ import_chalk27 = __toESM(require("chalk"));
7782
+ import_ora11 = __toESM(require("ora"));
7525
7783
  init_auth();
7526
7784
  init_admin();
7527
7785
  init_resolve();
@@ -8157,10 +8415,10 @@ async function runConnectorExercise(project, opts = {}) {
8157
8415
  if (!json) console.log(s);
8158
8416
  };
8159
8417
  const deps = opts.deps ?? {};
8160
- if (opts.report !== false) say(import_chalk26.default.cyan(` Report: ${reportLink(proj2.projectId, proj2.apiVersion)}`));
8418
+ if (opts.report !== false) say(import_chalk28.default.cyan(` Report: ${reportLink(proj2.projectId, proj2.apiVersion)}`));
8161
8419
  if (opts.emptyOk?.length) {
8162
8420
  await producer(caller, { method: "PATCH", path: projectPath(proj2), body: { directory_metadata: { empty_ok: opts.emptyOk } }, summary: "Mark tools legitimately empty" });
8163
- say(import_chalk26.default.dim(` marked legitimately empty: ${opts.emptyOk.join(", ")}`));
8421
+ say(import_chalk28.default.dim(` marked legitimately empty: ${opts.emptyOk.join(", ")}`));
8164
8422
  }
8165
8423
  let r = await fetchDirectoryReport(caller, proj2, { probe: false });
8166
8424
  const target2 = r.target ?? {};
@@ -8195,9 +8453,9 @@ async function runConnectorExercise(project, opts = {}) {
8195
8453
  bearer = login.accessToken;
8196
8454
  asMeta = login.as;
8197
8455
  reviewerUsername = acct.username;
8198
- say(import_chalk26.default.dim(` signed in as the reviewer (${acct.username}); the token expires in 1 h`));
8456
+ say(import_chalk28.default.dim(` signed in as the reviewer (${acct.username}); the token expires in 1 h`));
8199
8457
  } else {
8200
- say(import_chalk26.default.dim(" open mode: no sign-in; this run's calls count as yours"));
8458
+ say(import_chalk28.default.dim(" open mode: no sign-in; this run's calls count as yours"));
8201
8459
  }
8202
8460
  const ua = `apiblaze-cli/${version} directory-exercise`;
8203
8461
  const headers = { [RUN_HEADER]: runId2 };
@@ -8217,14 +8475,14 @@ async function runConnectorExercise(project, opts = {}) {
8217
8475
  if (!go) {
8218
8476
  row.note = "not exercised: producer declined";
8219
8477
  notes.push({ tool: t.name, note: "not exercised: producer declined" });
8220
- say(` ${import_chalk26.default.yellow("\u2013")} ${t.name} not exercised (${interactive2 ? "declined" : "non-interactive: writes need a y"})`);
8478
+ say(` ${import_chalk28.default.yellow("\u2013")} ${t.name} not exercised (${interactive2 ? "declined" : "non-interactive: writes need a y"})`);
8221
8479
  continue;
8222
8480
  }
8223
8481
  }
8224
8482
  let v = localOutcome(await call3(t.name, args));
8225
8483
  if (role === "read" && v.outcome !== "ok" && interactive2 && Object.keys(args).length) {
8226
8484
  const { default: inquirer3 } = await import("inquirer");
8227
- say(` ${mark(v.outcome)} ${t.name} refused ${JSON.stringify(args)}: ${import_chalk26.default.dim(redactHead(v.text, 120) || v.outcome)}`);
8485
+ say(` ${mark(v.outcome)} ${t.name} refused ${JSON.stringify(args)}: ${import_chalk28.default.dim(redactHead(v.text, 120) || v.outcome)}`);
8228
8486
  const fixed = {};
8229
8487
  for (const [name, cur] of Object.entries(args)) {
8230
8488
  const p = t.inputProperties?.[name] ?? {};
@@ -8263,11 +8521,11 @@ async function runConnectorExercise(project, opts = {}) {
8263
8521
  row.invalidText = redactHead(`${bad.broke} \u2192 ${e.text}`);
8264
8522
  }
8265
8523
  }
8266
- say(` ${mark(v.outcome)} ${t.name} ${import_chalk26.default.dim(v.text.replace(/\s+/g, " ").slice(0, 80))}${row.invalid !== "skipped" ? import_chalk26.default.dim(` \xB7 bad arg: ${row.invalid === "error" ? "refused with a message" : row.invalid}`) : ""}`);
8524
+ say(` ${mark(v.outcome)} ${t.name} ${import_chalk28.default.dim(v.text.replace(/\s+/g, " ").slice(0, 80))}${row.invalid !== "skipped" ? import_chalk28.default.dim(` \xB7 bad arg: ${row.invalid === "error" ? "refused with a message" : row.invalid}`) : ""}`);
8267
8525
  }
8268
8526
  if (Object.keys(learned).length) {
8269
8527
  await producer(caller, { method: "PATCH", path: projectPath(proj2), body: { directory_metadata: { tool_examples: learned } }, summary: "Remember the working arguments" });
8270
- say(import_chalk26.default.green(` \u2713 remembered the working arguments for ${Object.keys(learned).join(", ")} (used on every run from now on)`));
8528
+ say(import_chalk28.default.green(` \u2713 remembered the working arguments for ${Object.keys(learned).join(", ")} (used on every run from now on)`));
8271
8529
  }
8272
8530
  const creators = tools.filter((t) => toolRole(t) === "create");
8273
8531
  if (!open && !opts.promptsOnly && opts.seed !== false && emptyReads.length && creators.length) {
@@ -8275,21 +8533,21 @@ async function runConnectorExercise(project, opts = {}) {
8275
8533
  let go = opts.seed === true;
8276
8534
  if (!go && interactive2) go = await confirm(`${emptyReads.length} read${emptyReads.length > 1 ? "s" : ""} returned nothing for the reviewer (${names}). Create a few records the reviewer will see, through ${creators.map((c) => c.name).join(", ")}? They are kept, not deleted.`, interactive2);
8277
8535
  if (!go) {
8278
- say(import_chalk26.default.dim(` seed skipped${interactive2 ? "" : " (non-interactive: pass --seed to create records for the reviewer, --no-seed to silence this)"}: ${names} stay empty for the reviewer (REVIEWER_ACCOUNT_POPULATED)`));
8536
+ say(import_chalk28.default.dim(` seed skipped${interactive2 ? "" : " (non-interactive: pass --seed to create records for the reviewer, --no-seed to silence this)"}: ${names} stay empty for the reviewer (REVIEWER_ACCOUNT_POPULATED)`));
8279
8537
  notes.push({ kind: "seed", note: "skipped", tools: emptyReads.map((t) => t.name) });
8280
8538
  } else {
8281
8539
  for (const c of creators) {
8282
8540
  const args = validArgs(c, {}, examples[c.name]);
8283
8541
  const v = localOutcome(await call3(c.name, args));
8284
8542
  if (v.outcome !== "ok") {
8285
- say(` ${mark(v.outcome)} seed via ${c.name} ${JSON.stringify(args)}: ${import_chalk26.default.dim(redactHead(v.text, 100) || v.outcome)}`);
8543
+ say(` ${mark(v.outcome)} seed via ${c.name} ${JSON.stringify(args)}: ${import_chalk28.default.dim(redactHead(v.text, 100) || v.outcome)}`);
8286
8544
  continue;
8287
8545
  }
8288
8546
  const id = extractCreatedId(parseResultJson(v.text));
8289
8547
  const idText = id ? String(id.value).slice(0, 64) : "(no id in the answer)";
8290
8548
  seeded[c.name] = [...seeded[c.name] ?? [], idText];
8291
8549
  notes.push({ kind: "seed", tool: c.name, note: `seeded ${id ? `${id.name}=${idText}` : "a record"}` });
8292
- say(` ${import_chalk26.default.green("\u2713")} seeded via ${c.name}: ${idText} ${import_chalk26.default.dim("(kept for the reviewer)")}`);
8550
+ say(` ${import_chalk28.default.green("\u2713")} seeded via ${c.name}: ${idText} ${import_chalk28.default.dim("(kept for the reviewer)")}`);
8293
8551
  }
8294
8552
  if (Object.keys(seeded).length) {
8295
8553
  for (const t of emptyReads) {
@@ -8303,9 +8561,9 @@ async function runConnectorExercise(project, opts = {}) {
8303
8561
  row.args = args;
8304
8562
  row.resultShape = describeResult(v.text);
8305
8563
  }
8306
- say(` ${nonEmpty ? import_chalk26.default.green("\u2713") : import_chalk26.default.yellow("\u2013")} ${t.name} after seeding: ${import_chalk26.default.dim(nonEmpty ? v.text.replace(/\s+/g, " ").slice(0, 80) : "still nothing (a different filter or tenant? mark it --empty-ok if that is correct)")}`);
8564
+ say(` ${nonEmpty ? import_chalk28.default.green("\u2713") : import_chalk28.default.yellow("\u2013")} ${t.name} after seeding: ${import_chalk28.default.dim(nonEmpty ? v.text.replace(/\s+/g, " ").slice(0, 80) : "still nothing (a different filter or tenant? mark it --empty-ok if that is correct)")}`);
8307
8565
  }
8308
- await producer(caller, { method: "PATCH", path: projectPath(proj2), body: { directory_metadata: { seeded } }, summary: "Remember what was seeded for the reviewer" }).catch((e) => say(import_chalk26.default.dim(` (could not store the seeded ids: ${e.message})`)));
8566
+ await producer(caller, { method: "PATCH", path: projectPath(proj2), body: { directory_metadata: { seeded } }, summary: "Remember what was seeded for the reviewer" }).catch((e) => say(import_chalk28.default.dim(` (could not store the seeded ids: ${e.message})`)));
8309
8567
  }
8310
8568
  }
8311
8569
  }
@@ -8323,11 +8581,11 @@ async function runConnectorExercise(project, opts = {}) {
8323
8581
  for (const client of clients) {
8324
8582
  if (opts.noClaude && client === "claude") continue;
8325
8583
  if (client === "claude" && !claudeInstalled) {
8326
- say(import_chalk26.default.dim(" Claude Code is not installed here: the Claude pass is skipped (TESTED_FROM_CLAUDE and EXAMPLE_PROMPTS_WORK stay open with their instruction)."));
8584
+ say(import_chalk28.default.dim(" Claude Code is not installed here: the Claude pass is skipped (TESTED_FROM_CLAUDE and EXAMPLE_PROMPTS_WORK stay open with their instruction)."));
8327
8585
  continue;
8328
8586
  }
8329
8587
  if (client === "codex" && !(codex.installed && codex.loggedIn)) {
8330
- say(import_chalk26.default.dim(` Codex CLI is ${codex.installed ? "not logged in" : "not installed"} here: the Codex pass is skipped (TESTED_FROM_OPENAI_CLIENT, EXAMPLE_PROMPTS_WORK_OPENAI and NEGATIVE_PROMPTS_HOLD stay open with their instruction).${codex.installed ? " Run `codex login` once." : " Install it: npm i -g @openai/codex, then `codex login`."}`));
8588
+ say(import_chalk28.default.dim(` Codex CLI is ${codex.installed ? "not logged in" : "not installed"} here: the Codex pass is skipped (TESTED_FROM_OPENAI_CLIENT, EXAMPLE_PROMPTS_WORK_OPENAI and NEGATIVE_PROMPTS_HOLD stay open with their instruction).${codex.installed ? " Run `codex login` once." : " Install it: npm i -g @openai/codex, then `codex login`."}`));
8331
8589
  continue;
8332
8590
  }
8333
8591
  const already = provenFor(client);
@@ -8342,9 +8600,9 @@ async function runConnectorExercise(project, opts = {}) {
8342
8600
  ...client === "codex" && !opts.promptsOnly ? negatives.map((p) => ({ prompt: p, kind: "negative" })) : []
8343
8601
  ];
8344
8602
  const label3 = client === "claude" ? "Claude Code" : "Codex CLI";
8345
- if (already.size) say(import_chalk26.default.dim(` ${already.size} prompt${already.size > 1 ? "s" : ""} already run through ${label3} as ${already.size > 1 ? "they were" : "it was"} typed`));
8603
+ if (already.size) say(import_chalk28.default.dim(` ${already.size} prompt${already.size > 1 ? "s" : ""} already run through ${label3} as ${already.size > 1 ? "they were" : "it was"} typed`));
8346
8604
  if (!runs.length) continue;
8347
- say(import_chalk26.default.dim(` ${label3} pass: ${runs.length} one-shot${runs.length > 1 ? "s" : ""} (10\u201325 s each; read-only tools only)`));
8605
+ say(import_chalk28.default.dim(` ${label3} pass: ${runs.length} one-shot${runs.length > 1 ? "s" : ""} (10\u201325 s each; read-only tools only)`));
8348
8606
  let cfgPath = null;
8349
8607
  if (client === "claude") {
8350
8608
  configDir = configDir ?? import_fs5.default.mkdtempSync(import_path4.default.join(deps.tmpdir ?? import_os2.default.tmpdir(), "abz-exercise-"));
@@ -8358,7 +8616,7 @@ async function runConnectorExercise(project, opts = {}) {
8358
8616
  if (x.kind === "tool") notes.push({ kind: "claude-tool", client, tool: firstRead.name, tool_called: calls.length > 0 });
8359
8617
  else notes.push({ kind: x.kind, prompt: x.prompt, tool_called: calls.length > 0, tools: calls, client });
8360
8618
  const good = x.kind === "negative" ? calls.length === 0 : calls.length > 0;
8361
- say(` ${good ? import_chalk26.default.green("\u2713") : import_chalk26.default.yellow("\u2013")} ${client}: "${x.prompt.slice(0, 60)}" \u2192 ${calls.length ? `called ${calls.join(", ")}` : "no tool call"}${x.kind === "negative" ? calls.length ? import_chalk26.default.yellow(" (a negative prompt must hold)") : import_chalk26.default.dim(" (held)") : ""}${status2 !== 0 && status2 != null ? import_chalk26.default.dim(` (exit ${status2})`) : ""}`);
8619
+ say(` ${good ? import_chalk28.default.green("\u2713") : import_chalk28.default.yellow("\u2013")} ${client}: "${x.prompt.slice(0, 60)}" \u2192 ${calls.length ? `called ${calls.join(", ")}` : "no tool call"}${x.kind === "negative" ? calls.length ? import_chalk28.default.yellow(" (a negative prompt must hold)") : import_chalk28.default.dim(" (held)") : ""}${status2 !== 0 && status2 != null ? import_chalk28.default.dim(` (exit ${status2})`) : ""}`);
8362
8620
  }
8363
8621
  }
8364
8622
  if (bearer && asMeta) userinfo = await probeUserinfo(asMeta, bearer, deps);
@@ -8412,13 +8670,13 @@ async function runConnectorExercise(project, opts = {}) {
8412
8670
  if (card) {
8413
8671
  console.log(card);
8414
8672
  console.log();
8415
- console.log(import_chalk26.default.bold(` ${summaryOf(r)}`) + import_chalk26.default.dim(` \xB7 ${pageLinkOf(r, proj2)}`));
8673
+ console.log(import_chalk28.default.bold(` ${summaryOf(r)}`) + import_chalk28.default.dim(` \xB7 ${pageLinkOf(r, proj2)}`));
8416
8674
  } else {
8417
8675
  printReport(r, false);
8418
- console.log(import_chalk26.default.cyan(` Report: ${reportLink(proj2.projectId, proj2.apiVersion)}`));
8676
+ console.log(import_chalk28.default.cyan(` Report: ${reportLink(proj2.projectId, proj2.apiVersion)}`));
8419
8677
  }
8420
8678
  }
8421
- console.log(import_chalk26.default.dim(opts.noEmail ? " (no email for this run)" : closed?.emailed ? " (the result was emailed to you; --no-email or the project setting turns it off)" : " (no email: the run has no address to send to)"));
8679
+ console.log(import_chalk28.default.dim(opts.noEmail ? " (no email for this run)" : closed?.emailed ? " (the result was emailed to you; --no-email or the project setting turns it off)" : " (no email: the run has no address to send to)"));
8422
8680
  return summary;
8423
8681
  }
8424
8682
  function claudeOneShot2(spawn5, cfgPath, prompt, allowed) {
@@ -8439,10 +8697,10 @@ async function createPromptTester(caller, proj2, opts = {}) {
8439
8697
  const codex = deps.codexInstalled !== void 0 ? { installed: deps.codexInstalled, loggedIn: deps.codexInstalled } : wanted.includes("codex") ? detectCodex(deps.spawn ?? import_child_process5.spawnSync) : { installed: false, loggedIn: false };
8440
8698
  const clients = wanted.filter((c) => c === "claude" ? claudeInstalled : codex.installed && codex.loggedIn);
8441
8699
  if (!clients.length) {
8442
- say(import_chalk26.default.dim(` (${wanted.includes("codex") && !wanted.includes("claude") ? `Codex CLI is ${codex.installed ? "not logged in" : "not installed"}` : "Claude Code is not installed"} here: each prompt is run at the end, in the exercise)`));
8700
+ say(import_chalk28.default.dim(` (${wanted.includes("codex") && !wanted.includes("claude") ? `Codex CLI is ${codex.installed ? "not logged in" : "not installed"}` : "Claude Code is not installed"} here: each prompt is run at the end, in the exercise)`));
8443
8701
  return null;
8444
8702
  }
8445
- for (const missing of wanted.filter((c) => !clients.includes(c))) say(import_chalk26.default.dim(` (${missing === "claude" ? "Claude Code is not installed" : `Codex CLI is ${codex.installed ? "not logged in" : "not installed"}`} here: that pass runs at the end, in the exercise, once it is)`));
8703
+ for (const missing of wanted.filter((c) => !clients.includes(c))) say(import_chalk28.default.dim(` (${missing === "claude" ? "Claude Code is not installed" : `Codex CLI is ${codex.installed ? "not logged in" : "not installed"}`} here: that pass runs at the end, in the exercise, once it is)`));
8446
8704
  const r = await fetchDirectoryReport(caller, proj2, { probe: false });
8447
8705
  const target2 = r.target ?? {};
8448
8706
  const publishedUrl = r.report.project.publishedUrl;
@@ -8455,12 +8713,12 @@ async function createPromptTester(caller, proj2, opts = {}) {
8455
8713
  const packet = await producer(caller, { method: "GET", path: `${projectPath(proj2)}/directory-packet?probe=0&force=1`, summary: "Reviewer account (for the login)" }).catch(() => null);
8456
8714
  const acct = packet?.json?.test_account ?? null;
8457
8715
  if (!acct) {
8458
- say(import_chalk26.default.dim(" (no reviewer account yet: each prompt is run at the end, in the exercise)"));
8716
+ say(import_chalk28.default.dim(" (no reviewer account yet: each prompt is run at the end, in the exercise)"));
8459
8717
  return null;
8460
8718
  }
8461
8719
  const login = await headlessPasswordLogin({ mcpUrl: publishedUrl, username: acct.username, password: acct.password }, deps);
8462
8720
  if (!login.accessToken) {
8463
- say(import_chalk26.default.yellow(` (the reviewer could not sign in at ${login.failedAt}: ${login.detail}; each prompt is run at the end, in the exercise)`));
8721
+ say(import_chalk28.default.yellow(` (the reviewer could not sign in at ${login.failedAt}: ${login.detail}; each prompt is run at the end, in the exercise)`));
8464
8722
  return null;
8465
8723
  }
8466
8724
  bearer = login.accessToken;
@@ -8503,7 +8761,7 @@ async function createPromptTester(caller, proj2, opts = {}) {
8503
8761
  };
8504
8762
  }
8505
8763
  function mark(o) {
8506
- return o === "ok" ? import_chalk26.default.green("\u2713") : o === "error" ? import_chalk26.default.yellow("!") : import_chalk26.default.red("\u2717");
8764
+ return o === "ok" ? import_chalk28.default.green("\u2713") : o === "error" ? import_chalk28.default.yellow("!") : import_chalk28.default.red("\u2717");
8507
8765
  }
8508
8766
  function parseResultJson(text) {
8509
8767
  try {
@@ -8548,14 +8806,14 @@ async function runConnectorAnswers(project, opts = {}) {
8548
8806
  try {
8549
8807
  await producer(caller, { method: "PATCH", path: projectPath(proj2), body: part, summary: "Save an answer" });
8550
8808
  } catch (e) {
8551
- console.log(import_chalk26.default.yellow(` not saved: ${e instanceof Error ? e.message : String(e)}`));
8809
+ console.log(import_chalk28.default.yellow(` not saved: ${e instanceof Error ? e.message : String(e)}`));
8552
8810
  }
8553
8811
  };
8554
8812
  let headed = opts.derived !== false;
8555
8813
  const ask3 = async (qs) => {
8556
8814
  if (!headed) {
8557
8815
  headed = true;
8558
- console.log(import_chalk26.default.bold(" What the portal asks that only you can answer (saved as you go):"));
8816
+ console.log(import_chalk28.default.bold(" What the portal asks that only you can answer (saved as you go):"));
8559
8817
  }
8560
8818
  return inquirer3.prompt(qs);
8561
8819
  };
@@ -8610,7 +8868,7 @@ async function runConnectorAnswers(project, opts = {}) {
8610
8868
  const ask22 = async (qs) => {
8611
8869
  if (!headed2) {
8612
8870
  headed2 = true;
8613
- console.log(import_chalk26.default.bold(" What OpenAI's form asks (saved as you go):"));
8871
+ console.log(import_chalk28.default.bold(" What OpenAI's form asks (saved as you go):"));
8614
8872
  }
8615
8873
  return inquirer4.prompt(qs);
8616
8874
  };
@@ -8669,7 +8927,7 @@ async function runConnectorAnswers(project, opts = {}) {
8669
8927
  const open = current.target?.project?.authMode === "open";
8670
8928
  const tools = current.target?.tools ?? [];
8671
8929
  const defaults = defaultNegativePrompts2({ open, tools, serverName: typeof cm.serverName === "string" ? cm.serverName : null });
8672
- console.log(import_chalk26.default.dim(" Three prompts the plugin must NOT act on (OpenAI asks for them; the exercise checks that no tool is called):"));
8930
+ console.log(import_chalk28.default.dim(" Three prompts the plugin must NOT act on (OpenAI asks for them; the exercise checks that no tool is called):"));
8673
8931
  const negative = [];
8674
8932
  for (let i = 0; i < 3; i++) {
8675
8933
  const a = await ask22([{ type: "input", name: "value", message: `Negative prompt ${i + 1}:`, default: defaults[i].prompt }]);
@@ -8681,16 +8939,16 @@ async function runConnectorAnswers(project, opts = {}) {
8681
8939
  }
8682
8940
  const prompts = Array.isArray(cm.examplePrompts) ? cm.examplePrompts.filter((p) => typeof p === "string" && p.trim()) : [];
8683
8941
  if (prompts.length >= 3 && prompts.length < 5) {
8684
- console.log(import_chalk26.default.dim(` OpenAI wants five positive cases; you have ${prompts.length} prompts. ${5 - prompts.length} more a reviewer can try:`));
8942
+ console.log(import_chalk28.default.dim(` OpenAI wants five positive cases; you have ${prompts.length} prompts. ${5 - prompts.length} more a reviewer can try:`));
8685
8943
  const extra = [...prompts];
8686
8944
  for (let i = prompts.length; i < 5; i++) {
8687
8945
  const a = await ask22([{ type: "input", name: "value", message: `Prompt ${i + 1} (Enter to stop here):`, validate: (v) => v.trim().length <= 128 ? true : `${v.trim().length} characters; ChatGPT allows 128` }]);
8688
8946
  const p = a.value.trim();
8689
8947
  if (!p) break;
8690
8948
  if (opts.testPrompt) {
8691
- console.log(import_chalk26.default.dim(" trying it\u2026"));
8949
+ console.log(import_chalk28.default.dim(" trying it\u2026"));
8692
8950
  const res = await opts.testPrompt(p);
8693
- console.log(res.called ? import_chalk26.default.green(` \u2713 called ${res.tools.join(", ")}`) : import_chalk26.default.yellow(" \u2013 no tool call; kept (the exercise will say so)"));
8951
+ console.log(res.called ? import_chalk28.default.green(` \u2713 called ${res.tools.join(", ")}`) : import_chalk28.default.yellow(" \u2013 no tool call; kept (the exercise will say so)"));
8694
8952
  }
8695
8953
  extra.push(p);
8696
8954
  }
@@ -8706,7 +8964,7 @@ async function runConnectorAnswers(project, opts = {}) {
8706
8964
  if (Object.keys(meta).length) body.directory_metadata = meta;
8707
8965
  if (!Object.keys(body).length) {
8708
8966
  if (json) process.stdout.write(JSON.stringify({ project: proj2.projectId, changed: [] }) + "\n");
8709
- else if (opts.derived !== false) console.log(import_chalk26.default.dim(" Nothing to record: pass flags (--use-cases, --data-handling \u2026) or run interactively."));
8967
+ else if (opts.derived !== false) console.log(import_chalk28.default.dim(" Nothing to record: pass flags (--use-cases, --data-handling \u2026) or run interactively."));
8710
8968
  return;
8711
8969
  }
8712
8970
  await producer(caller, { method: "PATCH", path: projectPath(proj2), body, summary: "Store the portal answers" });
@@ -8715,15 +8973,15 @@ async function runConnectorAnswers(project, opts = {}) {
8715
8973
  process.stdout.write(JSON.stringify({ project: proj2.projectId, changed: Object.keys({ ...answers, ...meta }), headline: r.rendered.headline, report: r.report }) + "\n");
8716
8974
  return;
8717
8975
  }
8718
- console.log(import_chalk26.default.green(` \u2713 recorded: ${Object.keys({ ...answers, ...meta }).join(", ")}`));
8719
- if (opts.derived !== false) console.log(import_chalk26.default.dim(` ${summaryOf(r) ?? r.rendered.headline}${summaryOf(r) ? ` \xB7 ${pageLinkOf(r, proj2)}` : ""}`));
8720
- else console.log(import_chalk26.default.dim(` ${r.rendered.headline}`));
8976
+ console.log(import_chalk28.default.green(` \u2713 recorded: ${Object.keys({ ...answers, ...meta }).join(", ")}`));
8977
+ if (opts.derived !== false) console.log(import_chalk28.default.dim(` ${summaryOf(r) ?? r.rendered.headline}${summaryOf(r) ? ` \xB7 ${pageLinkOf(r, proj2)}` : ""}`));
8978
+ else console.log(import_chalk28.default.dim(` ${r.rendered.headline}`));
8721
8979
  }
8722
- var import_chalk26, import_fs5, import_os2, import_path4, import_child_process5, DASHBOARD_BASE8, RUN_META_KEY, RUN_HEADER, projectPath, openRuns, QUESTIONS;
8980
+ var import_chalk28, import_fs5, import_os2, import_path4, import_child_process5, DASHBOARD_BASE8, RUN_META_KEY, RUN_HEADER, projectPath, openRuns, QUESTIONS;
8723
8981
  var init_connector_exercise = __esm({
8724
8982
  "src/commands/connector-exercise.ts"() {
8725
8983
  "use strict";
8726
- import_chalk26 = __toESM(require("chalk"));
8984
+ import_chalk28 = __toESM(require("chalk"));
8727
8985
  import_fs5 = __toESM(require("fs"));
8728
8986
  import_os2 = __toESM(require("os"));
8729
8987
  import_path4 = __toESM(require("path"));
@@ -8907,8 +9165,8 @@ async function runConnectorDocs(project, opts = {}) {
8907
9165
  how = `from ${opts.from}`;
8908
9166
  } else if (opts.promptOut) {
8909
9167
  import_fs6.default.writeFileSync(opts.promptOut, prompt + "\n", { mode: 384 });
8910
- say(import_chalk27.default.green(` \u2713 prompt written to ${opts.promptOut}`));
8911
- say(import_chalk27.default.dim(` Run it through a model that answers JSON matching the schema, save the answer, then: ${B.cli} connector docs ${proj2.projectName} --from <answer.json>`));
9168
+ say(import_chalk29.default.green(` \u2713 prompt written to ${opts.promptOut}`));
9169
+ say(import_chalk29.default.dim(` Run it through a model that answers JSON matching the schema, save the answer, then: ${B.cli} connector docs ${proj2.projectName} --from <answer.json>`));
8912
9170
  return;
8913
9171
  } else {
8914
9172
  const installed3 = deps.claudeInstalled ?? detectExternalClis().some((c) => c.kind === "claude");
@@ -8917,7 +9175,7 @@ async function runConnectorDocs(project, opts = {}) {
8917
9175
  import_fs6.default.writeFileSync(file2, prompt + "\n", { mode: 384 });
8918
9176
  throw new Error(`Claude Code is not installed here, so the documents were not generated. The prompt is at ${file2}: run it through any model that answers JSON, then \`${B.cli} connector docs ${proj2.projectName} --from <answer.json>\`; or write them on the dashboard page.`);
8919
9177
  }
8920
- say(import_chalk27.default.dim(" generating the three documents on Claude Code (30\u201390 s)\u2026"));
9178
+ say(import_chalk29.default.dim(" generating the three documents on Claude Code (30\u201390 s)\u2026"));
8921
9179
  const g = generateWithClaude(prompt, deps);
8922
9180
  if (!g.docs) throw new Error(`${g.detail}. Run again, or \`${B.cli} connector docs ${proj2.projectName} --prompt-out prompt.txt\` to use another model.`);
8923
9181
  docs = g.docs;
@@ -8928,8 +9186,8 @@ async function runConnectorDocs(project, opts = {}) {
8928
9186
  process.stdout.write(JSON.stringify({ project: proj2.projectId, changed, docs_url: fr.generated_docs_url, how }) + "\n");
8929
9187
  return;
8930
9188
  }
8931
- console.log(import_chalk27.default.green(` \u2713 documents stored (${how}): ${changed.join(", ")}`));
8932
- console.log(` Documentation page: ${import_chalk27.default.cyan(fr.generated_docs_url)} \u2014 link it from your site; edit it on the dashboard any time.`);
9189
+ console.log(import_chalk29.default.green(` \u2713 documents stored (${how}): ${changed.join(", ")}`));
9190
+ console.log(` Documentation page: ${import_chalk29.default.cyan(fr.generated_docs_url)} \u2014 link it from your site; edit it on the dashboard any time.`);
8933
9191
  await printProgressTrailer(caller, proj2);
8934
9192
  }
8935
9193
  async function askDocsQuestion(caller, proj2, state, interactive2, say, deps = {}) {
@@ -8938,29 +9196,29 @@ async function askDocsQuestion(caller, proj2, state, interactive2, say, deps = {
8938
9196
  const a = await inquirer3.prompt([{ type: "input", name: "value", message: `Documentation for this connector on your site? Paste the URL, or N to use the generated page at ${state.generatedDocsUrl} (and link it from your site):`, default: state.docsUrl ?? "N" }]);
8939
9197
  const v = a.value.trim();
8940
9198
  if (!v || /^n(o)?$/i.test(v)) {
8941
- say(import_chalk27.default.dim(" using the generated page"));
9199
+ say(import_chalk29.default.dim(" using the generated page"));
8942
9200
  try {
8943
9201
  await runConnectorDocs(proj2.projectId, { deps, yes: true, team: proj2.teamId });
8944
9202
  } catch (e) {
8945
- say(import_chalk27.default.yellow(` ${e instanceof Error ? e.message : String(e)}`));
9203
+ say(import_chalk29.default.yellow(` ${e instanceof Error ? e.message : String(e)}`));
8946
9204
  await producer(caller, { method: "PUT", path: `${projectPath2(proj2)}/directory-documents`, body: { use_generated_docs_url: true }, summary: "Point docs at the generated page" });
8947
9205
  }
8948
9206
  return true;
8949
9207
  }
8950
9208
  const check = await verifyDocsUrl(v, state.serverName, deps.fetch);
8951
9209
  if (!check.ok) {
8952
- say(import_chalk27.default.yellow(` ${v} is not usable as documentation yet: ${check.reason}. Not stored.`));
9210
+ say(import_chalk29.default.yellow(` ${v} is not usable as documentation yet: ${check.reason}. Not stored.`));
8953
9211
  return false;
8954
9212
  }
8955
9213
  await producer(caller, { method: "PATCH", path: projectPath2(proj2), body: { directory_metadata: { docs_url: v, docs_confirmed: true } }, summary: "Store the documentation URL" });
8956
- say(import_chalk27.default.green(` \u2713 docs: ${v} (live, names ${state.serverName ?? "the server"})`));
9214
+ say(import_chalk29.default.green(` \u2713 docs: ${v} (live, names ${state.serverName ?? "the server"})`));
8957
9215
  return true;
8958
9216
  }
8959
- var import_chalk27, import_fs6, import_os3, import_path5, import_child_process6, projectPath2;
9217
+ var import_chalk29, import_fs6, import_os3, import_path5, import_child_process6, projectPath2;
8960
9218
  var init_connector_docs = __esm({
8961
9219
  "src/commands/connector-docs.ts"() {
8962
9220
  "use strict";
8963
- import_chalk27 = __toESM(require("chalk"));
9221
+ import_chalk29 = __toESM(require("chalk"));
8964
9222
  init_directory();
8965
9223
  import_fs6 = __toESM(require("fs"));
8966
9224
  import_os3 = __toESM(require("os"));
@@ -9036,24 +9294,24 @@ var init_plugin_package = __esm({
9036
9294
  // src/lib/agent-chat.ts
9037
9295
  async function runAgentChatRepl(opts) {
9038
9296
  const { title, subtitle, endpoint, buildBody, seedPrompt, summarizeProposal, commands } = opts;
9039
- console.log("\n" + import_chalk28.default.cyan.bold(title));
9040
- if (subtitle) console.log(import_chalk28.default.dim(subtitle));
9297
+ console.log("\n" + import_chalk30.default.cyan.bold(title));
9298
+ if (subtitle) console.log(import_chalk30.default.dim(subtitle));
9041
9299
  const messages = [];
9042
9300
  const ctx = { proposal: null, lastData: null, log: (s) => console.log(s) };
9043
9301
  const cmdByName = new Map(commands.map((c) => [c.name, c]));
9044
9302
  const footer = () => {
9045
9303
  const parts = [
9046
- import_chalk28.default.dim("type to chat/refine"),
9047
- ...commands.map((c) => import_chalk28.default.dim(`/${c.name} ${c.describe}`)),
9048
- import_chalk28.default.dim("/show"),
9049
- import_chalk28.default.dim("/exit when done"),
9050
- import_chalk28.default.dim("/drop discard changes")
9304
+ import_chalk30.default.dim("type to chat/refine"),
9305
+ ...commands.map((c) => import_chalk30.default.dim(`/${c.name} ${c.describe}`)),
9306
+ import_chalk30.default.dim("/show"),
9307
+ import_chalk30.default.dim("/exit when done"),
9308
+ import_chalk30.default.dim("/drop discard changes")
9051
9309
  ];
9052
- return " " + import_chalk28.default.dim("[ ") + parts.join(import_chalk28.default.dim(" \xB7 ")) + import_chalk28.default.dim(" ]");
9310
+ return " " + import_chalk30.default.dim("[ ") + parts.join(import_chalk30.default.dim(" \xB7 ")) + import_chalk30.default.dim(" ]");
9053
9311
  };
9054
9312
  async function turn(content) {
9055
9313
  messages.push({ role: "user", content });
9056
- process.stdout.write(import_chalk28.default.dim(" \u2026thinking\n"));
9314
+ process.stdout.write(import_chalk30.default.dim(" \u2026thinking\n"));
9057
9315
  const { status: status2, data } = await agentCall(endpoint, "POST", { messages, ...buildBody(messages) });
9058
9316
  if (status2 === 402 || status2 === 503 || parseProblem(data)) {
9059
9317
  await reportRefusal(status2, data, { cli: B.cli });
@@ -9062,7 +9320,7 @@ async function runAgentChatRepl(opts) {
9062
9320
  return;
9063
9321
  }
9064
9322
  if (status2 >= 400 || !data) {
9065
- console.log(import_chalk28.default.red(` Error (${status2}): ${(data && data.error) ?? "request failed"}
9323
+ console.log(import_chalk30.default.red(` Error (${status2}): ${(data && data.error) ?? "request failed"}
9066
9324
  `));
9067
9325
  messages.pop();
9068
9326
  return;
@@ -9070,24 +9328,24 @@ async function runAgentChatRepl(opts) {
9070
9328
  ctx.lastData = data;
9071
9329
  const reply = data.reply ?? data.message ?? "(no reply)";
9072
9330
  messages.push({ role: "assistant", content: reply });
9073
- console.log("\n" + import_chalk28.default.cyan("agent \u203A ") + reply + "\n");
9331
+ console.log("\n" + import_chalk30.default.cyan("agent \u203A ") + reply + "\n");
9074
9332
  if (data.proposal) {
9075
9333
  ctx.proposal = data.proposal;
9076
9334
  const summary = summarizeProposal?.(data);
9077
- if (summary) console.log(import_chalk28.default.yellow(" " + summary));
9335
+ if (summary) console.log(import_chalk30.default.yellow(" " + summary));
9078
9336
  const applies = commands.filter((c) => c.needsProposal);
9079
9337
  const primary = applies[applies.length - 1];
9080
9338
  if (primary) {
9081
- console.log(import_chalk28.default.bold.green(" \u279C Next: type ") + import_chalk28.default.bold.cyan(`/${primary.name}`) + import_chalk28.default.bold.green(" to apply this, then ") + import_chalk28.default.bold.cyan("/exit") + import_chalk28.default.bold.green(" to leave."));
9339
+ console.log(import_chalk30.default.bold.green(" \u279C Next: type ") + import_chalk30.default.bold.cyan(`/${primary.name}`) + import_chalk30.default.bold.green(" to apply this, then ") + import_chalk30.default.bold.cyan("/exit") + import_chalk30.default.bold.green(" to leave."));
9082
9340
  const rest = applies.slice(0, -1).map((c) => `/${c.name} = ${c.describe}`).join(" \xB7 ");
9083
- console.log(import_chalk28.default.dim(` (or keep chatting to refine${rest ? ` \xB7 ${rest}` : ""} \xB7 /show = inspect)`));
9341
+ console.log(import_chalk30.default.dim(` (or keep chatting to refine${rest ? ` \xB7 ${rest}` : ""} \xB7 /show = inspect)`));
9084
9342
  }
9085
9343
  console.log();
9086
9344
  }
9087
9345
  const line = formatBilling(data.billing);
9088
9346
  if (line) {
9089
9347
  const llm = data.llm;
9090
- console.log(import_chalk28.default.dim(` ${line}${llm?.model ? ` \xB7 ${llm.model}` : ""}`));
9348
+ console.log(import_chalk30.default.dim(` ${line}${llm?.model ? ` \xB7 ${llm.model}` : ""}`));
9091
9349
  }
9092
9350
  }
9093
9351
  const rl = import_readline.default.createInterface({ input: process.stdin, output: process.stdout });
@@ -9095,31 +9353,31 @@ async function runAgentChatRepl(opts) {
9095
9353
  await turn(seedPrompt);
9096
9354
  for (; ; ) {
9097
9355
  console.log(footer());
9098
- const line = (await ask3(import_chalk28.default.green("you \u203A "))).trim();
9356
+ const line = (await ask3(import_chalk30.default.green("you \u203A "))).trim();
9099
9357
  if (!line) continue;
9100
9358
  const lower = line.toLowerCase();
9101
9359
  if (line === "/exit" || line === "/quit" || lower === "exit" || lower === "quit" || lower === "q") {
9102
- console.log(import_chalk28.default.dim(" Bye \u2014 anything you enabled or published stays in place.\n"));
9360
+ console.log(import_chalk30.default.dim(" Bye \u2014 anything you enabled or published stays in place.\n"));
9103
9361
  break;
9104
9362
  }
9105
9363
  if (line === "/drop") {
9106
- console.log(import_chalk28.default.dim(" Dropped the pending proposal \u2014 rules you already enabled/published are untouched.\n"));
9364
+ console.log(import_chalk30.default.dim(" Dropped the pending proposal \u2014 rules you already enabled/published are untouched.\n"));
9107
9365
  break;
9108
9366
  }
9109
9367
  if (line === "/show") {
9110
- if (!ctx.proposal) console.log(import_chalk28.default.dim(" No proposal yet \u2014 keep chatting until the agent proposes one.\n"));
9368
+ if (!ctx.proposal) console.log(import_chalk30.default.dim(" No proposal yet \u2014 keep chatting until the agent proposes one.\n"));
9111
9369
  else console.log("\n" + JSON.stringify(ctx.proposal, null, 2) + "\n");
9112
9370
  continue;
9113
9371
  }
9114
9372
  if (line.startsWith("/")) {
9115
9373
  const cmd = cmdByName.get(line.slice(1));
9116
9374
  if (!cmd) {
9117
- console.log(import_chalk28.default.red(` Unknown command "${line}". Try one of: ${commands.map((c) => "/" + c.name).join(", ")}, /show, /drop
9375
+ console.log(import_chalk30.default.red(` Unknown command "${line}". Try one of: ${commands.map((c) => "/" + c.name).join(", ")}, /show, /drop
9118
9376
  `));
9119
9377
  continue;
9120
9378
  }
9121
9379
  if (cmd.needsProposal && !ctx.proposal) {
9122
- console.log(import_chalk28.default.yellow(" No proposal yet \u2014 keep chatting until the agent generates one, then try again.\n"));
9380
+ console.log(import_chalk30.default.yellow(" No proposal yet \u2014 keep chatting until the agent generates one, then try again.\n"));
9123
9381
  continue;
9124
9382
  }
9125
9383
  await cmd.run(ctx);
@@ -9129,12 +9387,12 @@ async function runAgentChatRepl(opts) {
9129
9387
  }
9130
9388
  rl.close();
9131
9389
  }
9132
- var import_readline, import_chalk28;
9390
+ var import_readline, import_chalk30;
9133
9391
  var init_agent_chat = __esm({
9134
9392
  "src/lib/agent-chat.ts"() {
9135
9393
  "use strict";
9136
9394
  import_readline = __toESM(require("readline"));
9137
- import_chalk28 = __toESM(require("chalk"));
9395
+ import_chalk30 = __toESM(require("chalk"));
9138
9396
  init_problem();
9139
9397
  init_brand();
9140
9398
  init_api();
@@ -9190,11 +9448,11 @@ async function runMcp(projectArg, apiVersionArg, opts) {
9190
9448
  const spec = ctx.proposal;
9191
9449
  const pub = await agentCall(`/projects/${projectId}/${apiVersion}/mcp/spec`, "PUT", { environment, spec });
9192
9450
  if (pub.status >= 400) {
9193
- ctx.log(import_chalk29.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
9451
+ ctx.log(import_chalk31.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
9194
9452
  `));
9195
9453
  return;
9196
9454
  }
9197
- ctx.log(import_chalk29.default.green(` \u2713 Published MCP server \u2014 ${mcpHost2}.mcp.apiblaze.com/${apiVersion}/${environment}.
9455
+ ctx.log(import_chalk31.default.green(` \u2713 Published MCP server \u2014 ${mcpHost2}.mcp.apiblaze.com/${apiVersion}/${environment}.
9198
9456
  `));
9199
9457
  }
9200
9458
  await runAgentChatRepl({
@@ -9425,7 +9683,7 @@ function renderOps(cat) {
9425
9683
  });
9426
9684
  const w = Math.min(40, Math.max(4, ...rows.map((r) => r.name.length)));
9427
9685
  const rw = Math.min(40, Math.max(5, ...rows.map((r) => r.route.length)));
9428
- return rows.map((r) => ` ${r.name.padEnd(w)} ${r.route.padEnd(rw)} ${r.eff}${r.custom ? import_chalk29.default.yellow(" (override)") : ""}`);
9686
+ return rows.map((r) => ` ${r.name.padEnd(w)} ${r.route.padEnd(rw)} ${r.eff}${r.custom ? import_chalk31.default.yellow(" (override)") : ""}`);
9429
9687
  }
9430
9688
  async function resolveMcpTarget(projectArg, opts) {
9431
9689
  const creds = loadCredentials();
@@ -9467,7 +9725,7 @@ async function runMcpPrompts(action, project, name, opts) {
9467
9725
  if (action === "list") {
9468
9726
  if (opts.json) return void console.log(JSON.stringify({ environment: t.environment, prompts }, null, 2));
9469
9727
  if (!prompts.length) {
9470
- console.log(import_chalk29.default.dim(`
9728
+ console.log(import_chalk31.default.dim(`
9471
9729
  No prompts on ${t.projectId} (${t.environment}). Prompts are drafted by the MCP agent (\`${B.cli} agent mcp ${t.projectId}\`) or added with \`${B.cli} mcp prompts set\`.
9472
9730
  `));
9473
9731
  return;
@@ -9475,7 +9733,7 @@ async function runMcpPrompts(action, project, name, opts) {
9475
9733
  console.log("");
9476
9734
  for (const p of prompts) {
9477
9735
  const args = (p.arguments ?? []).map((a) => a.required ? a.name : `${a.name}?`).join(", ");
9478
- console.log(` ${import_chalk29.default.bold(p.name)}${args ? import_chalk29.default.dim(`(${args})`) : ""}${p.title || p.description ? ` ${p.title ?? p.description}` : ""}`);
9736
+ console.log(` ${import_chalk31.default.bold(p.name)}${args ? import_chalk31.default.dim(`(${args})`) : ""}${p.title || p.description ? ` ${p.title ?? p.description}` : ""}`);
9479
9737
  }
9480
9738
  console.log("");
9481
9739
  return;
@@ -9486,9 +9744,9 @@ async function runMcpPrompts(action, project, name, opts) {
9486
9744
  if (!p) throw new Error(`No prompt named "${name}". See \`${B.cli} mcp prompts list ${project}\`.`);
9487
9745
  if (opts.json) return void console.log(JSON.stringify(p, null, 2));
9488
9746
  console.log(`
9489
- ${import_chalk29.default.bold(p.name)}${p.title ? ` \u2014 ${p.title}` : ""}`);
9747
+ ${import_chalk31.default.bold(p.name)}${p.title ? ` \u2014 ${p.title}` : ""}`);
9490
9748
  if (p.description) console.log(` ${p.description}`);
9491
- for (const a of p.arguments ?? []) console.log(import_chalk29.default.dim(` ${a.name}${a.required ? " (required)" : ""}${a.description ? `: ${a.description}` : ""}`));
9749
+ for (const a of p.arguments ?? []) console.log(import_chalk31.default.dim(` ${a.name}${a.required ? " (required)" : ""}${a.description ? `: ${a.description}` : ""}`));
9492
9750
  for (const m of p.messages) console.log(`
9493
9751
  [${m.role}] ${m.text}`);
9494
9752
  console.log("");
@@ -9509,7 +9767,7 @@ async function runMcpPrompts(action, project, name, opts) {
9509
9767
  }
9510
9768
  await saveCatalogue(t, next);
9511
9769
  if (opts.json) return void console.log(JSON.stringify({ saved: true, environment: t.environment, prompts: next.prompts }, null, 2));
9512
- console.log(import_chalk29.default.green(` \u2713 ${action === "set" ? "Saved" : "Removed"} prompt "${name}" on ${t.projectId} (${t.environment}).`));
9770
+ console.log(import_chalk31.default.green(` \u2713 ${action === "set" ? "Saved" : "Removed"} prompt "${name}" on ${t.projectId} (${t.environment}).`));
9513
9771
  }
9514
9772
  async function runMcpOps(action, project, tool, opts) {
9515
9773
  const t = await resolveMcpTarget(project, opts);
@@ -9533,13 +9791,13 @@ async function runMcpOps(action, project, tool, opts) {
9533
9791
  });
9534
9792
  return void console.log(JSON.stringify({ environment: t.environment, instruction: cat.contextNote ?? null, tools, hidden: (hidden ?? []).map((c) => ({ method: c.method.toUpperCase(), path: c.path, name: c.name, group: c.group, description: c.description ?? null })) }, null, 2));
9535
9793
  }
9536
- console.log(import_chalk29.default.dim(`
9794
+ console.log(import_chalk31.default.dim(`
9537
9795
  ${cat.tools.length} tool(s) on ${t.projectId} (${t.environment}). Defaults come from the HTTP method: GET/HEAD/OPTIONS read-only, PUT/DELETE idempotent, DELETE destructive + asks to confirm.
9538
9796
  `));
9539
9797
  for (const l of renderOps(cat)) console.log(l);
9540
- console.log(import_chalk29.default.dim(`
9798
+ console.log(import_chalk31.default.dim(`
9541
9799
  Override: ${B.cli} mcp ops set ${project} <tool> --name | --description | --read-only | --destructive | --confirm | --no-confirm | --always-async \xB7 Reset: ${B.cli} mcp ops reset ${project} <tool>`));
9542
- if (hidden?.length) console.log(import_chalk29.default.dim(` ${hidden.length} operation(s) of the spec are not tools (${B.cli} mcp ops list ${project} --json shows them; ${B.cli} mcp ops show ${project} <tool> adds one).`));
9800
+ if (hidden?.length) console.log(import_chalk31.default.dim(` ${hidden.length} operation(s) of the spec are not tools (${B.cli} mcp ops list ${project} --json shows them; ${B.cli} mcp ops show ${project} <tool> adds one).`));
9543
9801
  console.log("");
9544
9802
  return;
9545
9803
  }
@@ -9548,7 +9806,7 @@ async function runMcpOps(action, project, tool, opts) {
9548
9806
  const next2 = withoutTool(cat, tool);
9549
9807
  await saveCatalogue(t, next2);
9550
9808
  if (opts.json) return void console.log(JSON.stringify({ saved: true, hidden: tool, tools: next2.tools.length }, null, 2));
9551
- console.log(import_chalk29.default.green(` \u2713 ${tool} is no longer a tool. ${next2.tools.length} tool(s) remain; \`${B.cli} mcp ops show ${project} ${tool}\` brings it back.`));
9809
+ console.log(import_chalk31.default.green(` \u2713 ${tool} is no longer a tool. ${next2.tools.length} tool(s) remain; \`${B.cli} mcp ops show ${project} ${tool}\` brings it back.`));
9552
9810
  return;
9553
9811
  }
9554
9812
  if (action === "show") {
@@ -9562,7 +9820,7 @@ async function runMcpOps(action, project, tool, opts) {
9562
9820
  const next2 = withTool(cat, c);
9563
9821
  await saveCatalogue(t, next2);
9564
9822
  if (opts.json) return void console.log(JSON.stringify({ saved: true, shown: c.name, method: c.method.toUpperCase(), path: c.path, tools: next2.tools.length }, null, 2));
9565
- console.log(import_chalk29.default.green(` \u2713 ${c.name} (${c.method.toUpperCase()} ${c.path}) is a tool. ${next2.tools.length} tool(s). Give it a description: \`${B.cli} mcp ops set ${project} ${c.name} --description "\u2026"\`.`));
9823
+ console.log(import_chalk31.default.green(` \u2713 ${c.name} (${c.method.toUpperCase()} ${c.path}) is a tool. ${next2.tools.length} tool(s). Give it a description: \`${B.cli} mcp ops set ${project} ${c.name} --description "\u2026"\`.`));
9566
9824
  return;
9567
9825
  }
9568
9826
  let next = cat;
@@ -9584,7 +9842,7 @@ async function runMcpOps(action, project, tool, opts) {
9584
9842
  const eff = effectiveBehavior(method, next.overrides?.[finalName]);
9585
9843
  const edited = next.tools.find((x) => x.name === finalName);
9586
9844
  if (opts.json) return void console.log(JSON.stringify({ saved: true, tool: finalName, ...finalName !== tool ? { renamed_from: tool } : {}, description: edited?.description ?? null, override: next.overrides?.[finalName] ?? null, effective: eff }, null, 2));
9587
- console.log(import_chalk29.default.green(` \u2713 ${finalName}${finalName !== tool ? ` (was ${tool})` : ""}: ${flagsLine(eff)}${action === "reset" ? " (automatic default)" : ""}${opts.description !== void 0 ? ` \u2014 ${edited?.description}` : ""}`));
9845
+ console.log(import_chalk31.default.green(` \u2713 ${finalName}${finalName !== tool ? ` (was ${tool})` : ""}: ${flagsLine(eff)}${action === "reset" ? " (automatic default)" : ""}${opts.description !== void 0 ? ` \u2014 ${edited?.description}` : ""}`));
9588
9846
  }
9589
9847
  async function runMcpInstructions(action, project, text, opts) {
9590
9848
  const t = await resolveMcpTarget(project, opts);
@@ -9593,7 +9851,7 @@ async function runMcpInstructions(action, project, text, opts) {
9593
9851
  if (opts.json) return void console.log(JSON.stringify({ environment: t.environment, instruction: cat.contextNote ?? null }, null, 2));
9594
9852
  console.log(cat.contextNote ? `
9595
9853
  ${cat.contextNote}
9596
- ` : import_chalk29.default.dim(`
9854
+ ` : import_chalk31.default.dim(`
9597
9855
  No instruction on ${t.projectId} (${t.environment}). Set one: ${B.cli} mcp instructions set ${project} "What this MCP is for, how to start, what it will not do."
9598
9856
  `));
9599
9857
  return;
@@ -9610,7 +9868,7 @@ async function runMcpInstructions(action, project, text, opts) {
9610
9868
  const next = withInstruction(cat, body);
9611
9869
  await saveCatalogue(t, next);
9612
9870
  if (opts.json) return void console.log(JSON.stringify({ saved: true, environment: t.environment, instruction: next.contextNote ?? null }, null, 2));
9613
- console.log(import_chalk29.default.green(next.contextNote ? ` \u2713 Instruction saved (${next.contextNote.length} characters).` : " \u2713 Instruction cleared."));
9871
+ console.log(import_chalk31.default.green(next.contextNote ? ` \u2713 Instruction saved (${next.contextNote.length} characters).` : " \u2713 Instruction cleared."));
9614
9872
  }
9615
9873
  async function runMcpCatalogue(project, opts) {
9616
9874
  const t = await resolveMcpTarget(project, opts);
@@ -9618,7 +9876,7 @@ async function runMcpCatalogue(project, opts) {
9618
9876
  const candidates = await loadCandidates(t).catch(() => null);
9619
9877
  const hidden = candidates ? hiddenCandidates(candidates, cat) : null;
9620
9878
  if (opts.json) return void console.log(JSON.stringify({ environment: t.environment, catalogue: cat, hidden: (hidden ?? []).map((c) => ({ method: c.method.toUpperCase(), path: c.path, name: c.name, group: c.group })) }, null, 2));
9621
- console.log(import_chalk29.default.dim(`
9879
+ console.log(import_chalk31.default.dim(`
9622
9880
  ${t.projectId} (${t.environment}) \u2014 ${cat.tools.length} tool(s)
9623
9881
  `));
9624
9882
  for (const l of renderCatalogue(cat, { hidden })) console.log(` ${l}`);
@@ -9631,17 +9889,17 @@ async function runMcpUi(project, tool, opts) {
9631
9889
  const uri = uiResourceUri(t.projectId, tool);
9632
9890
  if (opts.json) return void console.log(JSON.stringify({ tool, uri, kind: "automatic" }, null, 2));
9633
9891
  console.log(`
9634
- ${import_chalk29.default.bold(uri)}
9892
+ ${import_chalk31.default.bold(uri)}
9635
9893
  `);
9636
- console.log(import_chalk29.default.dim(" This is the automatic viewer: MCP Apps clients render the tool's result with a generic UI built"));
9637
- console.log(import_chalk29.default.dim(" from its response schema \u2014 nothing to configure. Uploading your own HTML for it comes later.\n"));
9894
+ console.log(import_chalk31.default.dim(" This is the automatic viewer: MCP Apps clients render the tool's result with a generic UI built"));
9895
+ console.log(import_chalk31.default.dim(" from its response schema \u2014 nothing to configure. Uploading your own HTML for it comes later.\n"));
9638
9896
  }
9639
- var import_fs8, import_chalk29, PROMPT_NAME_RE, TOOL_NAME_RE, MAX_INSTRUCTION;
9897
+ var import_fs8, import_chalk31, PROMPT_NAME_RE, TOOL_NAME_RE, MAX_INSTRUCTION;
9640
9898
  var init_mcp = __esm({
9641
9899
  "src/commands/mcp.ts"() {
9642
9900
  "use strict";
9643
9901
  import_fs8 = __toESM(require("fs"));
9644
- import_chalk29 = __toESM(require("chalk"));
9902
+ import_chalk31 = __toESM(require("chalk"));
9645
9903
  init_brand();
9646
9904
  init_auth();
9647
9905
  init_api();
@@ -10257,24 +10515,24 @@ ready.then((c) => {
10257
10515
 
10258
10516
  // src/lib/log-view.ts
10259
10517
  function statusColor(status2) {
10260
- if (status2 < 300) return import_chalk31.default.green;
10261
- if (status2 < 400) return import_chalk31.default.blue;
10262
- if (status2 < 500) return import_chalk31.default.yellow;
10263
- return import_chalk31.default.red;
10518
+ if (status2 < 300) return import_chalk33.default.green;
10519
+ if (status2 < 400) return import_chalk33.default.blue;
10520
+ if (status2 < 500) return import_chalk33.default.yellow;
10521
+ return import_chalk33.default.red;
10264
10522
  }
10265
10523
  function methodColor(method) {
10266
10524
  switch ((method || "").toUpperCase()) {
10267
10525
  case "GET":
10268
- return import_chalk31.default.green;
10526
+ return import_chalk33.default.green;
10269
10527
  case "POST":
10270
- return import_chalk31.default.blue;
10528
+ return import_chalk33.default.blue;
10271
10529
  case "PUT":
10272
10530
  case "PATCH":
10273
- return import_chalk31.default.yellow;
10531
+ return import_chalk33.default.yellow;
10274
10532
  case "DELETE":
10275
- return import_chalk31.default.red;
10533
+ return import_chalk33.default.red;
10276
10534
  default:
10277
- return import_chalk31.default.white;
10535
+ return import_chalk33.default.white;
10278
10536
  }
10279
10537
  }
10280
10538
  function clock(ts2) {
@@ -10285,12 +10543,12 @@ function routeCell(route) {
10285
10543
  return (r.length > ROUTE_W ? `\u2026${r.slice(-(ROUTE_W - 1))}` : r).padEnd(ROUTE_W);
10286
10544
  }
10287
10545
  function formatRow(r) {
10288
- const time = import_chalk31.default.dim(clock(r.ts));
10546
+ const time = import_chalk33.default.dim(clock(r.ts));
10289
10547
  const method = methodColor(r.method)(String(r.method || "\u2014").padEnd(6));
10290
10548
  const route = routeCell(String(r.route || "\u2014"));
10291
10549
  const status2 = statusColor(r.status)(String(r.status ?? "\u2014").padStart(3));
10292
- const ms2 = import_chalk31.default.dim(`${r.duration_ms}ms`.padStart(8));
10293
- const step = r.error_step ? import_chalk31.default.dim(` ${r.error_step}`) : "";
10550
+ const ms2 = import_chalk33.default.dim(`${r.duration_ms}ms`.padStart(8));
10551
+ const step = r.error_step ? import_chalk33.default.dim(` ${r.error_step}`) : "";
10294
10552
  return `${time} ${method} ${route} ${status2} ${ms2}${step}`;
10295
10553
  }
10296
10554
  function printRow(r, json) {
@@ -10344,13 +10602,13 @@ async function runTailSession(opts) {
10344
10602
  if (!held.length && !heldRowsDropped && !heldNotesDropped) return;
10345
10603
  const rows = held.filter((h) => h.kind === "row").length;
10346
10604
  const total = rows + heldRowsDropped;
10347
- if (total) console.log(import_chalk31.default.dim(`\u2500\u2500\u2500 ${total} request${total === 1 ? "" : "s"} arrived while paused \u2500\u2500\u2500`));
10605
+ if (total) console.log(import_chalk33.default.dim(`\u2500\u2500\u2500 ${total} request${total === 1 ? "" : "s"} arrived while paused \u2500\u2500\u2500`));
10348
10606
  for (const h of held) {
10349
10607
  if (h.kind === "row") printRow(h.row, opts.json);
10350
10608
  else console.error(h.msg);
10351
10609
  }
10352
10610
  if (heldRowsDropped || heldNotesDropped) {
10353
- console.log(import_chalk31.default.dim(`\u2500\u2500\u2500 ${heldRowsDropped} older one${heldRowsDropped === 1 ? "" : "s"} not shown (pause buffer full) \u2014 browse them with \`logs list\` \u2500\u2500\u2500`));
10611
+ console.log(import_chalk33.default.dim(`\u2500\u2500\u2500 ${heldRowsDropped} older one${heldRowsDropped === 1 ? "" : "s"} not shown (pause buffer full) \u2014 browse them with \`logs list\` \u2500\u2500\u2500`));
10354
10612
  }
10355
10613
  held.length = 0;
10356
10614
  heldRowsDropped = 0;
@@ -10364,7 +10622,7 @@ async function runTailSession(opts) {
10364
10622
  activeSocket?.close();
10365
10623
  } catch {
10366
10624
  }
10367
- if (!opts.json) console.log(import_chalk31.default.dim("\nStopped."));
10625
+ if (!opts.json) console.log(import_chalk33.default.dim("\nStopped."));
10368
10626
  process.exit(0);
10369
10627
  }
10370
10628
  function onKeypress(_s, key) {
@@ -10392,17 +10650,17 @@ async function runTailSession(opts) {
10392
10650
  async function openInspector() {
10393
10651
  if (paused) return;
10394
10652
  if (recent.length === 0) {
10395
- console.log(import_chalk31.default.dim(" nothing captured yet \u2014 waiting for a request\u2026"));
10653
+ console.log(import_chalk33.default.dim(" nothing captured yet \u2014 waiting for a request\u2026"));
10396
10654
  return;
10397
10655
  }
10398
10656
  paused = true;
10399
10657
  unbindKeys();
10400
10658
  try {
10401
10659
  const { default: inquirer3 } = await import("inquirer");
10402
- console.log(import_chalk31.default.dim("\n\u2500\u2500\u2500 paused \xB7 still capturing in the background \u2500\u2500\u2500"));
10660
+ console.log(import_chalk33.default.dim("\n\u2500\u2500\u2500 paused \xB7 still capturing in the background \u2500\u2500\u2500"));
10403
10661
  for (; ; ) {
10404
10662
  const choices = recent.slice(-TAIL_INSPECT_CHOICES).reverse().map((r) => ({ name: formatRow(r), value: r.request_id }));
10405
- choices.push({ name: import_chalk31.default.dim("\u2039resume tail\u203A"), value: "__resume__" });
10663
+ choices.push({ name: import_chalk33.default.dim("\u2039resume tail\u203A"), value: "__resume__" });
10406
10664
  const { picked } = await inquirer3.prompt([{
10407
10665
  type: "list",
10408
10666
  name: "picked",
@@ -10413,12 +10671,12 @@ async function runTailSession(opts) {
10413
10671
  if (picked === "__resume__") break;
10414
10672
  const row = recent.find((r) => r.request_id === picked);
10415
10673
  if (row) printDetail(row, opts.detail);
10416
- else console.log(import_chalk31.default.dim(" that request has scrolled out of the tail buffer \u2014 find it with `logs list`.\n"));
10674
+ else console.log(import_chalk33.default.dim(" that request has scrolled out of the tail buffer \u2014 find it with `logs list`.\n"));
10417
10675
  }
10418
10676
  } finally {
10419
10677
  paused = false;
10420
10678
  flushHeld();
10421
- console.log(import_chalk31.default.dim("\u2500\u2500\u2500 resumed \u2500\u2500\u2500"));
10679
+ console.log(import_chalk33.default.dim("\u2500\u2500\u2500 resumed \u2500\u2500\u2500"));
10422
10680
  bindKeys();
10423
10681
  }
10424
10682
  }
@@ -10428,12 +10686,12 @@ async function runTailSession(opts) {
10428
10686
  if (reconnects >= MAX_RECONNECTS) {
10429
10687
  paused = false;
10430
10688
  flushHeld();
10431
- console.error(import_chalk31.default.red(`Connection lost \u2014 giving up after repeated reconnects${lastFailure ? ` (last error: ${lastFailure})` : ""}.`));
10689
+ console.error(import_chalk33.default.red(`Connection lost \u2014 giving up after repeated reconnects${lastFailure ? ` (last error: ${lastFailure})` : ""}.`));
10432
10690
  process.exit(1);
10433
10691
  }
10434
10692
  const delay = Math.min(1e3 * 2 ** reconnects, 15e3);
10435
10693
  reconnects++;
10436
- diag(import_chalk31.default.dim(`disconnected${lastFailure ? ` (${lastFailure})` : ""} \u2014 reconnecting in ${Math.round(delay / 1e3)}s\u2026`));
10694
+ diag(import_chalk33.default.dim(`disconnected${lastFailure ? ` (${lastFailure})` : ""} \u2014 reconnecting in ${Math.round(delay / 1e3)}s\u2026`));
10437
10695
  setTimeout(() => {
10438
10696
  if (!closed) void connect();
10439
10697
  }, delay);
@@ -10444,7 +10702,7 @@ async function runTailSession(opts) {
10444
10702
  url = await opts.mintTicket();
10445
10703
  } catch (err) {
10446
10704
  if (!everConnected) {
10447
- console.error(import_chalk31.default.red(`Could not start tail: ${err.message}`));
10705
+ console.error(import_chalk33.default.red(`Could not start tail: ${err.message}`));
10448
10706
  process.exit(1);
10449
10707
  }
10450
10708
  lastFailure = `ticket mint failed: ${err.message}`;
@@ -10457,7 +10715,7 @@ async function runTailSession(opts) {
10457
10715
  } catch (err) {
10458
10716
  lastFailure = `bad tail URL: ${err.message}`;
10459
10717
  if (!everConnected) {
10460
- console.error(import_chalk31.default.red(`Could not start tail: ${lastFailure}`));
10718
+ console.error(import_chalk33.default.red(`Could not start tail: ${lastFailure}`));
10461
10719
  process.exit(1);
10462
10720
  }
10463
10721
  scheduleReconnect();
@@ -10472,9 +10730,9 @@ async function runTailSession(opts) {
10472
10730
  lastInbound = Date.now();
10473
10731
  lastFailure = "";
10474
10732
  if (isReconnect) {
10475
- diag(import_chalk31.default.dim("reconnected \u2014 requests during the gap were not replayed (browse them with `logs list`)."));
10733
+ diag(import_chalk33.default.dim("reconnected \u2014 requests during the gap were not replayed (browse them with `logs list`)."));
10476
10734
  } else {
10477
- diag(import_chalk31.default.dim(interactive2 ? "[Enter] inspect a request \xB7 [Ctrl+C] stop\n" : "Ctrl+C to stop."));
10735
+ diag(import_chalk33.default.dim(interactive2 ? "[Enter] inspect a request \xB7 [Ctrl+C] stop\n" : "Ctrl+C to stop."));
10478
10736
  }
10479
10737
  bindKeys();
10480
10738
  pingTimer = setInterval(() => {
@@ -10501,7 +10759,7 @@ async function runTailSession(opts) {
10501
10759
  return;
10502
10760
  }
10503
10761
  if (frame?.type === "ceiling") {
10504
- diag(import_chalk31.default.yellow(
10762
+ diag(import_chalk33.default.yellow(
10505
10763
  `\u26A0 volume ceiling \u2014 ${Number(frame.dropped_this_hour) || 0} rows dropped this hour; errors keep streaming.`
10506
10764
  ));
10507
10765
  return;
@@ -10577,10 +10835,10 @@ async function fetchPage(fetchWindow3, params, notices) {
10577
10835
  return { rows, nextCursor: res.next_cursor ?? void 0 };
10578
10836
  }
10579
10837
  if (hop >= MAX_EMPTY_HOPS) {
10580
- console.error(import_chalk31.default.yellow("\u26A0 stopped after scanning a long empty span \u2014 older rows may still exist."));
10838
+ console.error(import_chalk33.default.yellow("\u26A0 stopped after scanning a long empty span \u2014 older rows may still exist."));
10581
10839
  return { rows: [], nextCursor: res.next_cursor, fuseTripped: true };
10582
10840
  }
10583
- if (hop === 0) console.error(import_chalk31.default.dim("searching older history\u2026"));
10841
+ if (hop === 0) console.error(import_chalk33.default.dim("searching older history\u2026"));
10584
10842
  cursor = res.next_cursor;
10585
10843
  }
10586
10844
  }
@@ -10618,18 +10876,18 @@ async function runPlainList(opts, notices) {
10618
10876
  }
10619
10877
  }
10620
10878
  if (rows.length === 0) {
10621
- console.log(import_chalk31.default.dim(fuseTripped ? "Nothing found in the scanned span \u2014 older requests may still exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
10879
+ console.log(import_chalk33.default.dim(fuseTripped ? "Nothing found in the scanned span \u2014 older requests may still exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
10622
10880
  return;
10623
10881
  }
10624
10882
  const now = Date.now();
10625
10883
  for (const d of groupIntoDays(rows)) {
10626
- console.log(import_chalk31.default.bold(dayLabel(d.dayMs, now)));
10884
+ console.log(import_chalk33.default.bold(dayLabel(d.dayMs, now)));
10627
10885
  for (const r of d.rows) console.log(` ${formatRow(r)}`);
10628
10886
  console.log("");
10629
10887
  }
10630
10888
  const errs = rows.filter((r) => r.status >= 400).length;
10631
10889
  const tail = fuseTripped ? " \xB7 stopped early (long empty span) \u2014 older requests may still exist" : more ? " \xB7 showing the most recent \u2014 `--json` streams the rest" : "";
10632
- console.log(import_chalk31.default.dim(
10890
+ console.log(import_chalk33.default.dim(
10633
10891
  `${rows.length} request${rows.length === 1 ? "" : "s"} \xB7 ${errs} error${errs === 1 ? "" : "s"}${tail}`
10634
10892
  ));
10635
10893
  }
@@ -10648,7 +10906,7 @@ async function runHistoryBrowser(opts) {
10648
10906
  for (const r of page.rows) console.log(JSON.stringify(r));
10649
10907
  any = any || page.rows.length > 0;
10650
10908
  if (page.fuseTripped || !page.nextCursor) {
10651
- if (!any && !page.fuseTripped) console.error(import_chalk31.default.dim(opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
10909
+ if (!any && !page.fuseTripped) console.error(import_chalk33.default.dim(opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
10652
10910
  return;
10653
10911
  }
10654
10912
  cursor2 = page.nextCursor;
@@ -10669,7 +10927,7 @@ async function runHistoryBrowser(opts) {
10669
10927
  scanRows = first.rows;
10670
10928
  scanCursor = first.nextCursor;
10671
10929
  if (scanRows.length === 0) {
10672
- console.log(import_chalk31.default.dim(first.fuseTripped ? "Nothing found in the scanned span \u2014 older rows may exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
10930
+ console.log(import_chalk33.default.dim(first.fuseTripped ? "Nothing found in the scanned span \u2014 older rows may exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
10673
10931
  return;
10674
10932
  }
10675
10933
  }
@@ -10680,10 +10938,10 @@ async function runHistoryBrowser(opts) {
10680
10938
  const now2 = Date.now();
10681
10939
  const oldestKey = days[days.length - 1]?.key;
10682
10940
  const choices = days.map((d) => ({
10683
- name: `${dayLabel(d.dayMs, now2).padEnd(12)} ${String(d.rows.length).padStart(4)}${(scanCursor !== void 0 || scanFloorUnknown) && d.key === oldestKey ? "+" : ""} requests${d.errors ? import_chalk31.default.red(` ${d.errors} errors`) : ""}`,
10941
+ name: `${dayLabel(d.dayMs, now2).padEnd(12)} ${String(d.rows.length).padStart(4)}${(scanCursor !== void 0 || scanFloorUnknown) && d.key === oldestKey ? "+" : ""} requests${d.errors ? import_chalk33.default.red(` ${d.errors} errors`) : ""}`,
10684
10942
  value: d.key
10685
10943
  }));
10686
- if (scanCursor) choices.push({ name: import_chalk31.default.dim("\u2026 older days"), value: "__older__" });
10944
+ if (scanCursor) choices.push({ name: import_chalk33.default.dim("\u2026 older days"), value: "__older__" });
10687
10945
  const { chosenDay } = await inquirer3.prompt([{
10688
10946
  type: "list",
10689
10947
  name: "chosenDay",
@@ -10703,7 +10961,7 @@ async function runHistoryBrowser(opts) {
10703
10961
  scanCursor = void 0;
10704
10962
  } else {
10705
10963
  scanCursor = more.nextCursor;
10706
- if (more.rows.length === 0 && !scanCursor) console.log(import_chalk31.default.dim("That was everything \u2014 no older requests."));
10964
+ if (more.rows.length === 0 && !scanCursor) console.log(import_chalk33.default.dim("That was everything \u2014 no older requests."));
10707
10965
  }
10708
10966
  continue;
10709
10967
  }
@@ -10725,11 +10983,11 @@ async function runHistoryBrowser(opts) {
10725
10983
  cursor
10726
10984
  }, notices);
10727
10985
  if (page.rows.length === 0 && pageRows.length === 0) {
10728
- console.log(import_chalk31.default.dim(page.fuseTripped ? "Stopped scanning this day (long empty span) \u2014 older rows in it may exist." : "No requests for this day."));
10986
+ console.log(import_chalk33.default.dim(page.fuseTripped ? "Stopped scanning this day (long empty span) \u2014 older rows in it may exist." : "No requests for this day."));
10729
10987
  return;
10730
10988
  }
10731
10989
  if (page.rows.length === 0) {
10732
- console.log(import_chalk31.default.dim(page.fuseTripped ? "Stopped scanning further into this day (long empty span) \u2014 older rows in it may exist." : "That was everything for this day."));
10990
+ console.log(import_chalk33.default.dim(page.fuseTripped ? "Stopped scanning further into this day (long empty span) \u2014 older rows in it may exist." : "That was everything for this day."));
10733
10991
  moreCursor = void 0;
10734
10992
  } else {
10735
10993
  pageRows = page.rows;
@@ -10740,8 +10998,8 @@ async function runHistoryBrowser(opts) {
10740
10998
  name: formatRow(r),
10741
10999
  value: r.request_id
10742
11000
  }));
10743
- if (moreCursor) choices.push({ name: import_chalk31.default.dim("\u2026 load more"), value: "__more__" });
10744
- choices.push({ name: import_chalk31.default.dim("quit"), value: "__quit__" });
11001
+ if (moreCursor) choices.push({ name: import_chalk33.default.dim("\u2026 load more"), value: "__more__" });
11002
+ choices.push({ name: import_chalk33.default.dim("quit"), value: "__quit__" });
10745
11003
  for (; ; ) {
10746
11004
  const { picked } = await inquirer3.prompt([{
10747
11005
  type: "list",
@@ -10776,19 +11034,19 @@ function wrapCells(items, width) {
10776
11034
  ${PANE_INDENT}`);
10777
11035
  }
10778
11036
  function renderHeaders(h) {
10779
- if (!h) return import_chalk31.default.dim("\u2014");
11037
+ if (!h) return import_chalk33.default.dim("\u2014");
10780
11038
  const width = process.stdout.columns || 100;
10781
11039
  if (h.values) {
10782
11040
  const e = Object.entries(h.values);
10783
- if (!e.length) return import_chalk31.default.dim("none");
11041
+ if (!e.length) return import_chalk33.default.dim("none");
10784
11042
  const rank = (k) => {
10785
11043
  const i = HEADER_PRIORITY.indexOf(k.toLowerCase());
10786
11044
  return i === -1 ? NOISE_HEADER.test(k) ? 999 : 500 : i;
10787
11045
  };
10788
- return e.sort((a, b) => rank(a[0]) - rank(b[0])).map(([k, v]) => `${import_chalk31.default.dim(k + ":")} ${v}`).join(`
11046
+ return e.sort((a, b) => rank(a[0]) - rank(b[0])).map(([k, v]) => `${import_chalk33.default.dim(k + ":")} ${v}`).join(`
10789
11047
  ${PANE_INDENT}`);
10790
11048
  }
10791
- if (!h.names?.length) return import_chalk31.default.dim("none");
11049
+ if (!h.names?.length) return import_chalk33.default.dim("none");
10792
11050
  const names = [...h.names];
10793
11051
  const noise = names.filter((n) => NOISE_HEADER.test(n));
10794
11052
  const shown = names.filter((n) => !NOISE_HEADER.test(n)).sort((a, b) => {
@@ -10796,77 +11054,77 @@ ${PANE_INDENT}`);
10796
11054
  const ib = HEADER_PRIORITY.indexOf(b.toLowerCase());
10797
11055
  return (ia === -1 ? 500 : ia) - (ib === -1 ? 500 : ib) || a.localeCompare(b);
10798
11056
  });
10799
- const body = shown.length ? wrapCells(shown, width) : import_chalk31.default.dim("(all forwarding headers)");
11057
+ const body = shown.length ? wrapCells(shown, width) : import_chalk33.default.dim("(all forwarding headers)");
10800
11058
  const tail = noise.length ? `
10801
- ${PANE_INDENT}${import_chalk31.default.dim(`+ ${noise.length} forwarding/client-hint header${noise.length === 1 ? "" : "s"} (cf-*, sec-*)`)}` : "";
10802
- return `${body}${tail} ${import_chalk31.default.dim("(names only)")}`;
11059
+ ${PANE_INDENT}${import_chalk33.default.dim(`+ ${noise.length} forwarding/client-hint header${noise.length === 1 ? "" : "s"} (cf-*, sec-*)`)}` : "";
11060
+ return `${body}${tail} ${import_chalk33.default.dim("(names only)")}`;
10803
11061
  }
10804
11062
  function renderBody(b) {
10805
- if (!b) return import_chalk31.default.dim("\u2014");
11063
+ if (!b) return import_chalk33.default.dim("\u2014");
10806
11064
  const meta = [b.content_type, b.size != null ? `${b.size}B` : null, b.truncated ? "truncated" : null].filter(Boolean).join(" \xB7 ");
10807
- if (b.not_captured) return import_chalk31.default.dim(`not captured (${b.not_captured})${meta ? " \xB7 " + meta : ""}`);
11065
+ if (b.not_captured) return import_chalk33.default.dim(`not captured (${b.not_captured})${meta ? " \xB7 " + meta : ""}`);
10808
11066
  const isShape = b.value === void 0 && b.shape !== void 0;
10809
11067
  const content = b.value !== void 0 ? b.value : b.shape;
10810
11068
  if (content === null || content === void 0 || content === "" || content === "empty") {
10811
- return import_chalk31.default.dim(`empty${meta ? " \xB7 " + meta : ""}`);
11069
+ return import_chalk33.default.dim(`empty${meta ? " \xB7 " + meta : ""}`);
10812
11070
  }
10813
11071
  const text = typeof content === "string" ? content : JSON.stringify(content, null, 2);
10814
- const head = isShape ? import_chalk31.default.dim("shape only (values not captured)\n ") : "";
11072
+ const head = isShape ? import_chalk33.default.dim("shape only (values not captured)\n ") : "";
10815
11073
  return head + text.split("\n").join("\n ");
10816
11074
  }
10817
11075
  function pane(title, tone, view, empty) {
10818
11076
  console.log(` ${tone(title)}`);
10819
11077
  if (empty !== void 0) {
10820
- console.log(` ${import_chalk31.default.dim(empty)}`);
11078
+ console.log(` ${import_chalk33.default.dim(empty)}`);
10821
11079
  return;
10822
11080
  }
10823
11081
  const v = view ?? {};
10824
- if (v.url) console.log(` ${import_chalk31.default.dim("target")} ${v.url}`);
11082
+ if (v.url) console.log(` ${import_chalk33.default.dim("target")} ${v.url}`);
10825
11083
  if (v.status != null) {
10826
- console.log(` ${import_chalk31.default.dim("status")} ${statusColor(v.status)(String(v.status))}${v.status_text ? import_chalk31.default.dim(" " + v.status_text) : ""}`);
11084
+ console.log(` ${import_chalk33.default.dim("status")} ${statusColor(v.status)(String(v.status))}${v.status_text ? import_chalk33.default.dim(" " + v.status_text) : ""}`);
10827
11085
  }
10828
- if (v.raw_path) console.log(` ${import_chalk31.default.dim("path")} ${v.raw_path}`);
11086
+ if (v.raw_path) console.log(` ${import_chalk33.default.dim("path")} ${v.raw_path}`);
10829
11087
  if (v.query && Object.keys(v.query).length) {
10830
- console.log(` ${import_chalk31.default.dim("query")} ${Object.entries(v.query).map(([k, q]) => `${k}=${q}`).join(" ")}`);
11088
+ console.log(` ${import_chalk33.default.dim("query")} ${Object.entries(v.query).map(([k, q]) => `${k}=${q}`).join(" ")}`);
10831
11089
  }
10832
- if (v.jwt !== void 0) console.log(` ${import_chalk31.default.dim("jwt")} ${JSON.stringify(v.jwt)}`);
10833
- console.log(` ${import_chalk31.default.dim("headers")} ${renderHeaders(v.headers)}`);
10834
- console.log(` ${import_chalk31.default.dim("body")} ${renderBody(v.body)}`);
11090
+ if (v.jwt !== void 0) console.log(` ${import_chalk33.default.dim("jwt")} ${JSON.stringify(v.jwt)}`);
11091
+ console.log(` ${import_chalk33.default.dim("headers")} ${renderHeaders(v.headers)}`);
11092
+ console.log(` ${import_chalk33.default.dim("body")} ${renderBody(v.body)}`);
10835
11093
  }
10836
11094
  function printDetail(r, mode = "producer") {
10837
11095
  const v = r.views;
10838
11096
  console.log("");
10839
- console.log(import_chalk31.default.bold(`${r.method} ${r.route}`) + " " + statusColor(r.status)(String(r.status)) + import_chalk31.default.dim(` ${r.duration_ms}ms`));
11097
+ console.log(import_chalk33.default.bold(`${r.method} ${r.route}`) + " " + statusColor(r.status)(String(r.status)) + import_chalk33.default.dim(` ${r.duration_ms}ms`));
10840
11098
  const cost = typeof r.cost_cents === "number" && r.cost_cents > 0 ? ` \xB7 ${r.cost_cents}\xA2` : "";
10841
- console.log(import_chalk31.default.dim(` request_id ${r.request_id}${r.environment ? ` \xB7 env ${r.environment}` : ""}${r.consumer_id ? ` \xB7 consumer ${r.consumer_id}` : ""}${cost}`));
11099
+ console.log(import_chalk33.default.dim(` request_id ${r.request_id}${r.environment ? ` \xB7 env ${r.environment}` : ""}${r.consumer_id ? ` \xB7 consumer ${r.consumer_id}` : ""}${cost}`));
10842
11100
  console.log("");
10843
11101
  if (!v) {
10844
- console.log(import_chalk31.default.dim(" No view detail captured for this request.\n"));
11102
+ console.log(import_chalk33.default.dim(" No view detail captured for this request.\n"));
10845
11103
  return;
10846
11104
  }
10847
- pane("Request (before) \u2014 client \u2192 APIblaze", import_chalk31.default.cyan, v.request);
11105
+ pane("Request (before) \u2014 client \u2192 APIblaze", import_chalk33.default.cyan, v.request);
10848
11106
  if (mode === "producer") {
10849
11107
  pane(
10850
11108
  "Request (after) \u2014 APIblaze \u2192 upstream",
10851
- import_chalk31.default.cyan,
11109
+ import_chalk33.default.cyan,
10852
11110
  v.forwarded_request,
10853
11111
  v.forwarded_request ? void 0 : "Request did not reach an upstream."
10854
11112
  );
10855
11113
  pane(
10856
11114
  "Response (before) \u2014 upstream \u2192 APIblaze",
10857
- import_chalk31.default.magenta,
11115
+ import_chalk33.default.magenta,
10858
11116
  v.upstream_response,
10859
11117
  v.upstream_response ? void 0 : "No upstream response."
10860
11118
  );
10861
11119
  }
10862
- pane("Response (after) \u2014 APIblaze \u2192 client", import_chalk31.default.magenta, v.response);
11120
+ pane("Response (after) \u2014 APIblaze \u2192 client", import_chalk33.default.magenta, v.response);
10863
11121
  console.log("");
10864
11122
  }
10865
- var import_chalk31, readline2, ROUTE_W, WindowNotices, MAX_RECONNECTS, PING_MS, LIVENESS_MS, STABLE_MS, SEEN_CAP, TAIL_INSPECT_BUFFER, TAIL_INSPECT_CHOICES, SCAN_LIMIT, PAGE_LIMIT2, JSON_PAGE_LIMIT, MAX_EMPTY_HOPS, epipeGuarded, PLAIN_MAX_ROWS, NOISE_HEADER, HEADER_PRIORITY, PANE_INDENT;
11123
+ var import_chalk33, readline2, ROUTE_W, WindowNotices, MAX_RECONNECTS, PING_MS, LIVENESS_MS, STABLE_MS, SEEN_CAP, TAIL_INSPECT_BUFFER, TAIL_INSPECT_CHOICES, SCAN_LIMIT, PAGE_LIMIT2, JSON_PAGE_LIMIT, MAX_EMPTY_HOPS, epipeGuarded, PLAIN_MAX_ROWS, NOISE_HEADER, HEADER_PRIORITY, PANE_INDENT;
10866
11124
  var init_log_view = __esm({
10867
11125
  "src/lib/log-view.ts"() {
10868
11126
  "use strict";
10869
- import_chalk31 = __toESM(require("chalk"));
11127
+ import_chalk33 = __toESM(require("chalk"));
10870
11128
  readline2 = __toESM(require("readline"));
10871
11129
  ROUTE_W = 34;
10872
11130
  WindowNotices = class {
@@ -10878,15 +11136,15 @@ var init_log_view = __esm({
10878
11136
  note(res) {
10879
11137
  if (res.history_unavailable && !this.saidUnavailable) {
10880
11138
  this.saidUnavailable = true;
10881
- console.error(import_chalk31.default.yellow("\u26A0 log history is unreachable right now \u2014 showing the live buffer only, older requests exist but cannot be read."));
11139
+ console.error(import_chalk33.default.yellow("\u26A0 log history is unreachable right now \u2014 showing the live buffer only, older requests exist but cannot be read."));
10882
11140
  }
10883
11141
  if ((res.history_markers?.length ?? 0) > 0 && !this.saidGap) {
10884
11142
  this.saidGap = true;
10885
- console.error(import_chalk31.default.yellow("\u26A0 this range includes a volume-ceiling gap \u2014 some rows were dropped at intake and are gone; counts are incomplete."));
11143
+ console.error(import_chalk33.default.yellow("\u26A0 this range includes a volume-ceiling gap \u2014 some rows were dropped at intake and are gone; counts are incomplete."));
10886
11144
  }
10887
11145
  if ((res.dropped_this_hour ?? 0) > 0 && !this.saidDropped) {
10888
11146
  this.saidDropped = true;
10889
- console.error(import_chalk31.default.yellow(`\u26A0 volume ceiling \u2014 ${res.dropped_this_hour} rows dropped this hour; errors keep logging.`));
11147
+ console.error(import_chalk33.default.yellow(`\u26A0 volume ceiling \u2014 ${res.dropped_this_hour} rows dropped this hour; errors keep logging.`));
10890
11148
  }
10891
11149
  }
10892
11150
  };
@@ -10973,7 +11231,7 @@ async function resolve(projectArg, versionArg, opts) {
10973
11231
  return { projectId, projectName: match.projectName, version: version2, tenant };
10974
11232
  }
10975
11233
  function otherPlaneHint() {
10976
- if (loadConsumer()) console.log(import_chalk32.default.dim(" \u2039consumer view: apiblaze consumer logs\u203A"));
11234
+ if (loadConsumer()) console.log(import_chalk34.default.dim(" \u2039consumer view: apiblaze consumer logs\u203A"));
10977
11235
  }
10978
11236
  function fetchWindow(projectId, version2, tenant) {
10979
11237
  return (params) => {
@@ -10992,8 +11250,8 @@ function fetchWindow(projectId, version2, tenant) {
10992
11250
  async function runLogsTail(projectArg, versionArg, opts) {
10993
11251
  const { projectId, projectName, version: version2, tenant } = await resolve(projectArg, versionArg, opts);
10994
11252
  if (!opts.json) {
10995
- console.log(import_chalk32.default.bold("API Producer logs") + import_chalk32.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
10996
- console.log(import_chalk32.default.dim("every caller's requests, with cost and upstream detail"));
11253
+ console.log(import_chalk34.default.bold("API Producer logs") + import_chalk34.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
11254
+ console.log(import_chalk34.default.dim("every caller's requests, with cost and upstream detail"));
10997
11255
  otherPlaneHint();
10998
11256
  }
10999
11257
  await runTailSession({
@@ -11014,8 +11272,8 @@ async function runLogsTail(projectArg, versionArg, opts) {
11014
11272
  async function runLogsList(projectArg, versionArg, opts) {
11015
11273
  const { projectId, projectName, version: version2, tenant } = await resolve(projectArg, versionArg, opts);
11016
11274
  if (!opts.json) {
11017
- console.log(import_chalk32.default.bold("API Producer logs") + import_chalk32.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
11018
- console.log(import_chalk32.default.dim("every caller's requests, with cost and upstream detail"));
11275
+ console.log(import_chalk34.default.bold("API Producer logs") + import_chalk34.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
11276
+ console.log(import_chalk34.default.dim("every caller's requests, with cost and upstream detail"));
11019
11277
  otherPlaneHint();
11020
11278
  console.log("");
11021
11279
  }
@@ -11027,11 +11285,11 @@ async function runLogsList(projectArg, versionArg, opts) {
11027
11285
  detail: "producer"
11028
11286
  });
11029
11287
  }
11030
- var import_chalk32, activeCaller, viaCaller;
11288
+ var import_chalk34, activeCaller, viaCaller;
11031
11289
  var init_logs = __esm({
11032
11290
  "src/commands/logs.ts"() {
11033
11291
  "use strict";
11034
- import_chalk32 = __toESM(require("chalk"));
11292
+ import_chalk34 = __toESM(require("chalk"));
11035
11293
  init_caller();
11036
11294
  init_auth();
11037
11295
  init_consumer_auth();
@@ -11312,12 +11570,12 @@ async function waitThrough(apiUrl, serverKey) {
11312
11570
  async function confirmStep(opts, question) {
11313
11571
  if (opts.yes || !interactive()) return true;
11314
11572
  console.log();
11315
- return ask(`${import_chalk33.default.bold("?")} ${question} ${import_chalk33.default.dim("(Y/n)")} `);
11573
+ return ask(`${import_chalk35.default.bold("?")} ${question} ${import_chalk35.default.dim("(Y/n)")} `);
11316
11574
  }
11317
11575
  async function busy(text, fn, minMs = 0) {
11318
11576
  if (!process.stdout.isTTY) return fn();
11319
11577
  const t = Date.now();
11320
- const spinner = (0, import_ora11.default)({ text: import_chalk33.default.dim(text), indent: 3, discardStdin: false }).start();
11578
+ const spinner = (0, import_ora13.default)({ text: import_chalk35.default.dim(text), indent: 3, discardStdin: false }).start();
11321
11579
  try {
11322
11580
  const out = await fn();
11323
11581
  const left = minMs - (Date.now() - t);
@@ -11350,7 +11608,7 @@ async function offerBrowserAndLogs(dir, opts) {
11350
11608
  console.log();
11351
11609
  if (await ask(` Open ${url} in your browser? (Y/n) `)) openBrowser3(url);
11352
11610
  if (await ask(` Show the requests reaching ${B.product} here, live? (Y/n) `)) {
11353
- console.log(import_chalk33.default.dim(` $ ${logsCommand(env)}`));
11611
+ console.log(import_chalk35.default.dim(` $ ${logsCommand(env)}`));
11354
11612
  const { runLogsTail: runLogsTail2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
11355
11613
  await runLogsTail2(env.APIBLAZE_NAME, void 0, { tenant: env.APIBLAZE_TENANT });
11356
11614
  }
@@ -11387,7 +11645,7 @@ async function runDemo(opts = {}) {
11387
11645
  const e = err instanceof DemoError ? err : new DemoError(`The demo could not start (${err.message}).`, `Run again: ${LATEST} demo`);
11388
11646
  countRun({ event: `demo-failed-${e.why}` });
11389
11647
  await stopDemos().catch(() => 0);
11390
- console.log(`${import_chalk33.default.red("\u2717")} ${e.message}`);
11648
+ console.log(`${import_chalk35.default.red("\u2717")} ${e.message}`);
11391
11649
  console.log(` ${e.fix}`);
11392
11650
  process.exit(1);
11393
11651
  }
@@ -11398,11 +11656,11 @@ function titleCard(lines) {
11398
11656
  const left = Math.floor((inner - t.length) / 2);
11399
11657
  return " ".repeat(left) + t + " ".repeat(inner - t.length - left);
11400
11658
  };
11401
- const edge = import_chalk33.default.magenta;
11659
+ const edge = import_chalk35.default.magenta;
11402
11660
  console.log();
11403
11661
  console.log(` ${edge(`\u256D${"\u2500".repeat(inner)}\u256E`)}`);
11404
11662
  console.log(` ${edge("\u2502")}${" ".repeat(inner)}${edge("\u2502")}`);
11405
- lines.forEach((l, i) => console.log(` ${edge("\u2502")}${i === 0 ? import_chalk33.default.bold(center(l)) : import_chalk33.default.dim(center(l))}${edge("\u2502")}`));
11663
+ lines.forEach((l, i) => console.log(` ${edge("\u2502")}${i === 0 ? import_chalk35.default.bold(center(l)) : import_chalk35.default.dim(center(l))}${edge("\u2502")}`));
11406
11664
  console.log(` ${edge("\u2502")}${" ".repeat(inner)}${edge("\u2502")}`);
11407
11665
  console.log(` ${edge(`\u2570${"\u2500".repeat(inner)}\u256F`)}`);
11408
11666
  }
@@ -11422,15 +11680,15 @@ function printTable(rows) {
11422
11680
  if (line) out.push(line);
11423
11681
  return out;
11424
11682
  };
11425
- const head = (l, r) => console.log(` ${import_chalk33.default.dim(l.padEnd(leftW))} ${import_chalk33.default.dim(r)}`);
11683
+ const head = (l, r) => console.log(` ${import_chalk35.default.dim(l.padEnd(leftW))} ${import_chalk35.default.dim(r)}`);
11426
11684
  head(`What ${B.product} set up`, "The command that does this");
11427
11685
  head("\u2500".repeat(leftW), "\u2500".repeat(Math.min(rightW, 60)));
11428
11686
  for (const r of rows) {
11429
- const left = `${import_chalk33.default.green("\u2713")} ${import_chalk33.default.bold(r.label.padEnd(17))} ${r.what}`;
11687
+ const left = `${import_chalk35.default.green("\u2713")} ${import_chalk35.default.bold(r.label.padEnd(17))} ${r.what}`;
11430
11688
  const leftPlain = `\u2713 ${r.label.padEnd(17)} ${r.what}`;
11431
11689
  const right = r.cmds.length ? r.cmds.flatMap(wrap2) : ["\u2014"];
11432
- console.log(` ${left}${" ".repeat(Math.max(0, leftW - leftPlain.length))} ${import_chalk33.default.cyan(right[0])}`);
11433
- for (const extra of right.slice(1)) console.log(` ${" ".repeat(leftW)} ${import_chalk33.default.cyan(extra)}`);
11690
+ console.log(` ${left}${" ".repeat(Math.max(0, leftW - leftPlain.length))} ${import_chalk35.default.cyan(right[0])}`);
11691
+ for (const extra of right.slice(1)) console.log(` ${" ".repeat(leftW)} ${import_chalk35.default.cyan(extra)}`);
11434
11692
  }
11435
11693
  }
11436
11694
  async function startDemo(opts) {
@@ -11439,8 +11697,8 @@ async function startDemo(opts) {
11439
11697
  const dir = import_fs11.default.existsSync(import_path9.default.join(here, STATE_DIR, "state.json")) ? here : import_path9.default.resolve(here, DIR_NAME);
11440
11698
  const rel = import_path9.default.relative(here, dir) || ".";
11441
11699
  const cdDir = rel === "." ? "" : `cd ${rel} && `;
11442
- const shell = (c, note = "") => console.log(` ${import_chalk33.default.dim("$")} ${import_chalk33.default.cyan(c)}${note ? ` ${import_chalk33.default.dim(note)}` : ""}`);
11443
- const ok = (text, note = "") => console.log(` ${import_chalk33.default.green("\u2713")} ${text}${note ? ` ${import_chalk33.default.dim(note)}` : ""}`);
11700
+ const shell = (c, note = "") => console.log(` ${import_chalk35.default.dim("$")} ${import_chalk35.default.cyan(c)}${note ? ` ${import_chalk35.default.dim(note)}` : ""}`);
11701
+ const ok = (text, note = "") => console.log(` ${import_chalk35.default.green("\u2713")} ${text}${note ? ` ${import_chalk35.default.dim(note)}` : ""}`);
11444
11702
  const stopHere = (step, lines) => {
11445
11703
  console.log();
11446
11704
  for (const l of lines) console.log(` ${l}`);
@@ -11466,14 +11724,14 @@ paths:`));
11466
11724
  const L = (c) => `${LATEST} ${c}`;
11467
11725
  writeEnv(dir, { BACKEND_SECRET: backendSecret, DEMO_NINO_TENANT: ninoTenant, APP_PORT: appPort, BACKEND_PORT: backendPort2, DIRECT_PORT: directPort });
11468
11726
  console.log();
11469
- console.log(import_chalk33.default.bold("1. The app: ResiResi, a table booking app for Tenants (Nino and Gino Pizzas) to allow end-users to book tables in their restaurants") + import_chalk33.default.dim(` (no ${B.product} yet)`));
11727
+ console.log(import_chalk35.default.bold("1. The app: ResiResi, a table booking app for Tenants (Nino and Gino Pizzas) to allow end-users to book tables in their restaurants") + import_chalk35.default.dim(` (no ${B.product} yet)`));
11470
11728
  console.log(` Written to ${rel}. Its routes, from openapi.yaml:`);
11471
- for (const r of routesOf(openapi)) console.log(` ${r.method.padEnd(7)}${r.path.padEnd(21)}${import_chalk33.default.dim(r.summary)}`);
11472
- console.log(import_chalk33.default.dim(" No login, no API keys, no permission checks in its code. It only checks one shared backend secret (in .env.local)."));
11729
+ for (const r of routesOf(openapi)) console.log(` ${r.method.padEnd(7)}${r.path.padEnd(21)}${import_chalk35.default.dim(r.summary)}`);
11730
+ console.log(import_chalk35.default.dim(" No login, no API keys, no permission checks in its code. It only checks one shared backend secret (in .env.local)."));
11473
11731
  if (!await confirmStep(opts, `Ok to serve the backend on localhost:${backendPort2}?`)) {
11474
11732
  return stopHere("backend", [
11475
11733
  `Stopped before starting anything. ResiResi is written to ${rel}.`,
11476
- `Start it any time: ${cdDir}npm run start ${import_chalk33.default.dim("\xB7")} or run the whole demo again: ${LATEST} demo`
11734
+ `Start it any time: ${cdDir}npm run start ${import_chalk35.default.dim("\xB7")} or run the whole demo again: ${LATEST} demo`
11477
11735
  ]);
11478
11736
  }
11479
11737
  shell(`${cdDir}npm run start`, "npm run stop \xB7 npm run restart");
@@ -11481,23 +11739,23 @@ paths:`));
11481
11739
  registerDemo(dir);
11482
11740
  const appUp = await busy("Starting the reservation backend and its front-end\u2026", () => waitPorts([backendPort2, directPort]), 1800);
11483
11741
  if (!appUp) throw new DemoError(`The ResiResi app did not start (see ${import_path9.default.join(rel, STATE_DIR, "app.log")}).`, `Run again: ${LATEST} demo`, "app-not-up");
11484
- ok(`${import_chalk33.default.bold("Reservation backend")}: localhost:${backendPort2}`, "unprotected");
11485
- ok(`${import_chalk33.default.bold("Unprotected reservation front-end")}, going directly to the reservation backend: ${import_chalk33.default.bold(`http://localhost:${directPort}`)}`);
11742
+ ok(`${import_chalk35.default.bold("Reservation backend")}: localhost:${backendPort2}`, "unprotected");
11743
+ ok(`${import_chalk35.default.bold("Unprotected reservation front-end")}, going directly to the reservation backend: ${import_chalk35.default.bold(`http://localhost:${directPort}`)}`);
11486
11744
  console.log(" Book a table directly, the way the unprotected front-end does:");
11487
- console.log(import_chalk33.default.cyan(` curl -X POST http://localhost:${backendPort2}/reservations \\`));
11488
- console.log(import_chalk33.default.cyan(` -H "x-target-api-key: $(grep BACKEND_SECRET ${import_path9.default.join(rel, ".env.local")} | cut -d= -f2)" \\`));
11489
- console.log(import_chalk33.default.cyan(` -H "x-abz-user-id: ana" -H "x-abz-tenant-id: ${ninoTenant}" \\`));
11745
+ console.log(import_chalk35.default.cyan(` curl -X POST http://localhost:${backendPort2}/reservations \\`));
11746
+ console.log(import_chalk35.default.cyan(` -H "x-target-api-key: $(grep BACKEND_SECRET ${import_path9.default.join(rel, ".env.local")} | cut -d= -f2)" \\`));
11747
+ console.log(import_chalk35.default.cyan(` -H "x-abz-user-id: ana" -H "x-abz-tenant-id: ${ninoTenant}" \\`));
11490
11748
  const tomorrow = new Date(Date.now() + 864e5);
11491
11749
  const day = `${tomorrow.getFullYear()}-${String(tomorrow.getMonth() + 1).padStart(2, "0")}-${String(tomorrow.getDate()).padStart(2, "0")}`;
11492
- console.log(import_chalk33.default.cyan(` -H "content-type: application/json" -d '{"date":"${day}","time":"19:30","guests":2}'`));
11750
+ console.log(import_chalk35.default.cyan(` -H "content-type: application/json" -d '{"date":"${day}","time":"19:30","guests":2}'`));
11493
11751
  if (!await confirmStep(opts, `Ok to put an ${B.product} proxy and MCP in front of the reservation backend?`)) {
11494
11752
  return stopHere("proxy", [
11495
- `Stopped before ${B.product}. ResiResi keeps running on this laptop: http://localhost:${directPort} ${import_chalk33.default.dim(`(${cdDir}npm run stop stops it)`)}`,
11753
+ `Stopped before ${B.product}. ResiResi keeps running on this laptop: http://localhost:${directPort} ${import_chalk35.default.dim(`(${cdDir}npm run stop stops it)`)}`,
11496
11754
  `Run the whole demo again any time: ${LATEST} demo`
11497
11755
  ]);
11498
11756
  }
11499
11757
  console.log();
11500
- console.log(import_chalk33.default.bold(`2. ${B.product}, in front of it`));
11758
+ console.log(import_chalk35.default.bold(`2. ${B.product}, in front of it`));
11501
11759
  const tCreate = Date.now();
11502
11760
  const setup = await busy(`Creating the proxy, its tenants, admins, rules and limits\u2026`, async () => {
11503
11761
  const r = await createProxy2(name, backendPort2, openapi, ninoTenant);
@@ -11603,13 +11861,13 @@ paths:`));
11603
11861
  ]);
11604
11862
  }
11605
11863
  console.log();
11606
- console.log(import_chalk33.default.bold("3. Live on the internet"));
11864
+ console.log(import_chalk35.default.bold("3. Live on the internet"));
11607
11865
  shell(`${LATEST} dev --port ${backendPort2} --project ${project} --auto`, "the tunnel, in the background");
11608
11866
  await busy(`Opening the tunnel to localhost:${backendPort2} and checking it with a real call\u2026`, async () => {
11609
11867
  await spawnTunnel(dir, state);
11610
11868
  await waitThrough(apiUrl, serverKey);
11611
11869
  }, 1200);
11612
- ok(`${import_chalk33.default.bold("Tunnel")}: the public address reaches localhost:${backendPort2} on this laptop`, `checked with a real call \xB7 ${Math.round((Date.now() - t0) / 1e3)} s so far`);
11870
+ ok(`${import_chalk35.default.bold("Tunnel")}: the public address reaches localhost:${backendPort2} on this laptop`, `checked with a real call \xB7 ${Math.round((Date.now() - t0) / 1e3)} s so far`);
11613
11871
  printAddresses(dir);
11614
11872
  if (!await confirmStep(opts, "Ok to launch the protected website, which will use the proxy to reach the backend?")) {
11615
11873
  return stopHere("website", [
@@ -11618,7 +11876,7 @@ paths:`));
11618
11876
  ]);
11619
11877
  }
11620
11878
  console.log();
11621
- console.log(import_chalk33.default.bold(`4. The protected website, through ${B.product}`));
11879
+ console.log(import_chalk35.default.bold(`4. The protected website, through ${B.product}`));
11622
11880
  shell(`${cdDir}npm run restart`, "picks up the keys in .env.local");
11623
11881
  const siteUp = await busy("Starting the protected website\u2026", async () => {
11624
11882
  appCtl(dir, "--stop");
@@ -11626,16 +11884,16 @@ paths:`));
11626
11884
  return waitPorts([appPort, directPort, backendPort2]);
11627
11885
  }, 1500);
11628
11886
  if (!siteUp) throw new DemoError(`The protected website did not start (see ${import_path9.default.join(rel, STATE_DIR, "app.log")}).`, `Try: ${cdDir}npm run restart`, "site-not-up");
11629
- ok(`${import_chalk33.default.bold("Protected reservation website")}, going through the ${B.product} proxy ${apiUrl}: ${import_chalk33.default.bold(`http://localhost:${appPort}`)}`);
11630
- ok(`${import_chalk33.default.bold("Unprotected reservation front-end")}, still going directly to the backend: http://localhost:${directPort}`, "the switch at the top of the page goes between them");
11887
+ ok(`${import_chalk35.default.bold("Protected reservation website")}, going through the ${B.product} proxy ${apiUrl}: ${import_chalk35.default.bold(`http://localhost:${appPort}`)}`);
11888
+ ok(`${import_chalk35.default.bold("Unprotected reservation front-end")}, still going directly to the backend: http://localhost:${directPort}`, "the switch at the top of the page goes between them");
11631
11889
  console.log();
11632
- console.log(import_chalk33.default.dim(` Logs: ${logsCommand(readEnvFile(import_path9.default.join(dir, ".env.local")))} \xB7 Stop the tunnel: ${LATEST} demo stop \xB7 Your own app: ${LATEST} dev --port <port>`));
11890
+ console.log(import_chalk35.default.dim(` Logs: ${logsCommand(readEnvFile(import_path9.default.join(dir, ".env.local")))} \xB7 Stop the tunnel: ${LATEST} demo stop \xB7 Your own app: ${LATEST} dev --port <port>`));
11633
11891
  await offerBrowserAndLogs(dir, opts);
11634
11892
  return "demo-ready";
11635
11893
  }
11636
11894
  function printAddresses(dir) {
11637
11895
  const env = readEnvFile(import_path9.default.join(dir, ".env.local"));
11638
- const row = (label3, value, note = "") => console.log(` ${label3.padEnd(11)} ${value}${note ? ` ${import_chalk33.default.dim(note)}` : ""}`);
11896
+ const row = (label3, value, note = "") => console.log(` ${label3.padEnd(11)} ${value}${note ? ` ${import_chalk35.default.dim(note)}` : ""}`);
11639
11897
  row("Public API", env.APIBLAZE_URL ?? "", `${B.product} tunnel \u2192 localhost:${env.BACKEND_PORT}`);
11640
11898
  row("MCP", env.APIBLAZE_MCP_URL ?? "", "for Claude, ChatGPT, Cursor (Nino Pizza)");
11641
11899
  if (env.APIBLAZE_PORTAL_URL) row("Dev portal", env.APIBLAZE_PORTAL_URL, "sign in, get a key, try the API");
@@ -11654,7 +11912,7 @@ async function runDemoStart(opts = {}) {
11654
11912
  const state = loadState(dir);
11655
11913
  const env = readEnvFile(import_path9.default.join(dir, ".env.local"));
11656
11914
  if (!state || !env.APIBLAZE_SERVER_KEY) {
11657
- console.log(`${import_chalk33.default.red("\u2717")} There is no demo here to start.`);
11915
+ console.log(`${import_chalk35.default.red("\u2717")} There is no demo here to start.`);
11658
11916
  console.log(` Make one: ${LATEST} demo`);
11659
11917
  process.exit(1);
11660
11918
  }
@@ -11664,31 +11922,31 @@ async function runDemoStart(opts = {}) {
11664
11922
  } catch (err) {
11665
11923
  const e = err instanceof DemoError ? err : new DemoError(`The tunnel could not start (${err.message}).`, `Start over: ${LATEST} demo`);
11666
11924
  countRun({ event: `demo-restart-failed-${e.why}` });
11667
- console.log(`${import_chalk33.default.red("\u2717")} ${e.message}`);
11925
+ console.log(`${import_chalk35.default.red("\u2717")} ${e.message}`);
11668
11926
  console.log(` ${e.fix}`);
11669
11927
  process.exit(1);
11670
11928
  }
11671
11929
  countRun({ event: "demo-restarted" });
11672
- console.log(`${import_chalk33.default.green("\u2713")} Tunnel open: the public address reaches localhost:${env.BACKEND_PORT} again ${import_chalk33.default.dim(`(${Math.round((Date.now() - t0) / 1e3)} s)`)}`);
11930
+ console.log(`${import_chalk35.default.green("\u2713")} Tunnel open: the public address reaches localhost:${env.BACKEND_PORT} again ${import_chalk35.default.dim(`(${Math.round((Date.now() - t0) / 1e3)} s)`)}`);
11673
11931
  printAddresses(dir);
11674
11932
  const appUp = await fetch(`http://127.0.0.1:${env.APP_PORT}/api/config`).then(() => true).catch(() => false);
11675
- if (!appUp) console.log(import_chalk33.default.yellow(` ResiResi is not running: cd ${import_path9.default.relative(process.cwd(), dir) || "."} && npm run start`));
11933
+ if (!appUp) console.log(import_chalk35.default.yellow(` ResiResi is not running: cd ${import_path9.default.relative(process.cwd(), dir) || "."} && npm run start`));
11676
11934
  await offerBrowserAndLogs(dir, opts);
11677
11935
  }
11678
11936
  async function runDemoLogs() {
11679
11937
  const env = readEnvFile(import_path9.default.join(demoDir(), ".env.local"));
11680
11938
  if (!env.APIBLAZE_NAME) {
11681
- console.log(`${import_chalk33.default.red("\u2717")} There is no demo here.`);
11939
+ console.log(`${import_chalk35.default.red("\u2717")} There is no demo here.`);
11682
11940
  console.log(` Make one: ${LATEST} demo`);
11683
11941
  process.exit(1);
11684
11942
  }
11685
- console.log(import_chalk33.default.dim(`$ ${logsCommand(env)}`));
11943
+ console.log(import_chalk35.default.dim(`$ ${logsCommand(env)}`));
11686
11944
  const { runLogsTail: runLogsTail2 } = await Promise.resolve().then(() => (init_logs(), logs_exports));
11687
11945
  await runLogsTail2(env.APIBLAZE_NAME, void 0, { tenant: env.APIBLAZE_TENANT });
11688
11946
  }
11689
11947
  async function runDemoStop() {
11690
11948
  const n = await stopTunnels();
11691
- console.log(n ? `${import_chalk33.default.green("\u2713")} Stopped the tunnel. ResiResi still runs on this laptop (npm run stop stops it).` : "No demo tunnel is running.");
11949
+ console.log(n ? `${import_chalk35.default.green("\u2713")} Stopped the tunnel. ResiResi still runs on this laptop (npm run stop stops it).` : "No demo tunnel is running.");
11692
11950
  }
11693
11951
  async function serveTunnel(dir) {
11694
11952
  const state = loadState(dir);
@@ -11746,7 +12004,7 @@ async function serveTunnel(dir) {
11746
12004
  await new Promise(() => {
11747
12005
  });
11748
12006
  }
11749
- var import_fs11, import_path9, import_net2, import_child_process7, import_crypto, import_chalk33, import_ora11, DIR_NAME, STATE_DIR, LATEST, DEMO_RPS, DEMO_ADMIN_EMAIL, DEMO_GINO_ADMIN_EMAIL, RULE_SENTENCE, DemoError, ADJ, NOUN, pick2, registryFile, alive, interactive, logsCommand;
12007
+ var import_fs11, import_path9, import_net2, import_child_process7, import_crypto, import_chalk35, import_ora13, DIR_NAME, STATE_DIR, LATEST, DEMO_RPS, DEMO_ADMIN_EMAIL, DEMO_GINO_ADMIN_EMAIL, RULE_SENTENCE, DemoError, ADJ, NOUN, pick2, registryFile, alive, interactive, logsCommand;
11750
12008
  var init_demo = __esm({
11751
12009
  "src/commands/demo.ts"() {
11752
12010
  "use strict";
@@ -11755,8 +12013,8 @@ var init_demo = __esm({
11755
12013
  import_net2 = __toESM(require("net"));
11756
12014
  import_child_process7 = require("child_process");
11757
12015
  import_crypto = __toESM(require("crypto"));
11758
- import_chalk33 = __toESM(require("chalk"));
11759
- import_ora11 = __toESM(require("ora"));
12016
+ import_chalk35 = __toESM(require("chalk"));
12017
+ import_ora13 = __toESM(require("ora"));
11760
12018
  init_api();
11761
12019
  init_tunnel_client();
11762
12020
  init_auth();
@@ -12849,8 +13107,8 @@ Not ready: ${lines.length} blocker${lines.length === 1 ? "" : "s"} (${r.rendered
12849
13107
  // src/commands/connector.ts
12850
13108
  var import_fs9 = __toESM(require("fs"));
12851
13109
  var import_path7 = __toESM(require("path"));
12852
- var import_chalk30 = __toESM(require("chalk"));
12853
- var import_ora10 = __toESM(require("ora"));
13110
+ var import_chalk32 = __toESM(require("chalk"));
13111
+ var import_ora12 = __toESM(require("ora"));
12854
13112
  init_caller();
12855
13113
  init_directory();
12856
13114
  init_brand();
@@ -13152,14 +13410,14 @@ async function promptForMissing(r, interactive2, defaults = { prompts: [] }, pla
13152
13410
  if (testPrompt) {
13153
13411
  let res = await testPrompt(text);
13154
13412
  if (!res.called) {
13155
- say_(import_chalk30.default.yellow(` \u2013 No tool call for "${text}". A prompt should say what the tool does (a real URL, name or id helps).`));
13413
+ say_(import_chalk32.default.yellow(` \u2013 No tool call for "${text}". A prompt should say what the tool does (a real URL, name or id helps).`));
13156
13414
  const again = await inquirer3.prompt([{ type: "input", name: "line", message: "Reword it (Enter keeps it):", default: text, validate: withinLimit(a) }]);
13157
13415
  if (again.line?.trim() && again.line.trim() !== text) {
13158
13416
  text = again.line.trim();
13159
13417
  res = await testPrompt(text);
13160
13418
  }
13161
13419
  }
13162
- if (!res.called) say_(import_chalk30.default.yellow(" \u2013 still no tool call; kept (the report will say so)"));
13420
+ if (!res.called) say_(import_chalk32.default.yellow(" \u2013 still no tool call; kept (the report will say so)"));
13163
13421
  }
13164
13422
  lines.push(text);
13165
13423
  }
@@ -13167,7 +13425,7 @@ async function promptForMissing(r, interactive2, defaults = { prompts: [] }, pla
13167
13425
  out.prompt = lines;
13168
13426
  if (save) {
13169
13427
  const why = await save({ prompt: lines });
13170
- if (why) say_(import_chalk30.default.yellow(` not saved: ${why}`));
13428
+ if (why) say_(import_chalk32.default.yellow(` not saved: ${why}`));
13171
13429
  }
13172
13430
  }
13173
13431
  continue;
@@ -13190,7 +13448,7 @@ async function promptForMissing(r, interactive2, defaults = { prompts: [] }, pla
13190
13448
  if (save) {
13191
13449
  const why = await save({ [a.key]: value.trim() });
13192
13450
  if (why) {
13193
- say_(import_chalk30.default.yellow(` not saved: ${why}`));
13451
+ say_(import_chalk32.default.yellow(` not saved: ${why}`));
13194
13452
  delete out[a.key];
13195
13453
  }
13196
13454
  }
@@ -13223,7 +13481,7 @@ async function askOpenMode(caller, proj2, r, opts, interactive2, say) {
13223
13481
  const { open } = await inquirer3.prompt([{ type: "confirm", name: "open", message: OPEN_MODE_QUESTION, default: false }]);
13224
13482
  if (!open) return false;
13225
13483
  await patchProject(caller, proj2, { directory_metadata: { auth_mode: "open" } }, "Open mode: no sign-in on the connector");
13226
- say(import_chalk30.default.green(" \u2713 open mode: the connector takes no sign-in (public data); no reviewer account is needed."));
13484
+ say(import_chalk32.default.green(" \u2713 open mode: the connector takes no sign-in (public data); no reviewer account is needed."));
13227
13485
  return true;
13228
13486
  }
13229
13487
  async function promptListingBasics(r, interactive2, defaults, given, platforms = PLATFORMS, save) {
@@ -13251,7 +13509,7 @@ async function promptListingBasics(r, interactive2, defaults, given, platforms =
13251
13509
  if (save) {
13252
13510
  const why = await save({ [w.key]: value.trim() });
13253
13511
  if (why) {
13254
- say_(import_chalk30.default.yellow(` not saved: ${why}`));
13512
+ say_(import_chalk32.default.yellow(` not saved: ${why}`));
13255
13513
  delete out[w.key];
13256
13514
  }
13257
13515
  }
@@ -13262,7 +13520,7 @@ async function promptListingBasics(r, interactive2, defaults, given, platforms =
13262
13520
  async function createFromSpec(spec, opts, say) {
13263
13521
  const { runCreate: runCreate2 } = await Promise.resolve().then(() => (init_create(), create_exports));
13264
13522
  let created = null;
13265
- say(import_chalk30.default.bold(`Creating a directory-ready ${B.thingShort} from ${spec}\u2026`));
13523
+ say(import_chalk32.default.bold(`Creating a directory-ready ${B.thingShort} from ${spec}\u2026`));
13266
13524
  await runCreate2({
13267
13525
  openapi: spec,
13268
13526
  directoryReady: true,
@@ -13334,20 +13592,20 @@ async function ensureMcpDomain(caller, proj2, r, opts, defaults, interactive2, s
13334
13592
  }
13335
13593
  }
13336
13594
  if (!hostname2) throw new Error("A custom MCP hostname is required for the directories (--domain mcp.<your domain>).");
13337
- const sp2 = opts.json ? null : (0, import_ora10.default)(`Registering ${hostname2}\u2026`).start();
13595
+ const sp2 = opts.json ? null : (0, import_ora12.default)(`Registering ${hostname2}\u2026`).start();
13338
13596
  row = await producer(caller, { method: "POST", path: base2, body: { hostname: hostname2, api_version: proj2.apiVersion, kind: "mcp" }, summary: `Add custom MCP domain ${hostname2}` });
13339
13597
  sp2?.succeed(`Registered ${row.hostname ?? hostname2} as the MCP server's domain.`);
13340
13598
  }
13341
13599
  const hostname = row.hostname ?? opts.domain ?? "";
13342
13600
  if (row.status === "active") return { active: true, hostname, id: row.id };
13343
13601
  say("");
13344
- say(import_chalk30.default.bold(" Add this DNS record at your DNS provider (one record; nothing else to add):"));
13345
- say(` ${import_chalk30.default.cyan("CNAME")} ${row.cnameRecord?.name ?? hostname} \u2192 ${row.cnameRecord?.value ?? "proxy.abz.run"}`);
13346
- if (row.dcv) say(` ${import_chalk30.default.cyan("TXT")} ${row.dcv.name} = ${row.dcv.value}`);
13602
+ say(import_chalk32.default.bold(" Add this DNS record at your DNS provider (one record; nothing else to add):"));
13603
+ say(` ${import_chalk32.default.cyan("CNAME")} ${row.cnameRecord?.name ?? hostname} \u2192 ${row.cnameRecord?.value ?? "proxy.abz.run"}`);
13604
+ if (row.dcv) say(` ${import_chalk32.default.cyan("TXT")} ${row.dcv.name} = ${row.dcv.value}`);
13347
13605
  say("");
13348
13606
  const minutes = opts.wait === void 0 ? 15 : Number(opts.wait);
13349
13607
  if (!(minutes > 0) || !row.id) return { active: false, hostname, id: row.id };
13350
- const sp = opts.json ? null : (0, import_ora10.default)(`Waiting for ${hostname} to activate (Cloudflare validates it once the CNAME resolves; up to ${minutes} min, Ctrl-C to stop and re-run later)\u2026`).start();
13608
+ const sp = opts.json ? null : (0, import_ora12.default)(`Waiting for ${hostname} to activate (Cloudflare validates it once the CNAME resolves; up to ${minutes} min, Ctrl-C to stop and re-run later)\u2026`).start();
13351
13609
  const until = Date.now() + minutes * 6e4;
13352
13610
  let status2 = row.status ?? "pending";
13353
13611
  while (Date.now() < until) {
@@ -13364,6 +13622,93 @@ async function ensureMcpDomain(caller, proj2, r, opts, defaults, interactive2, s
13364
13622
  sp?.fail(`${hostname} is not active yet (${status2}).`);
13365
13623
  return { active: false, hostname, id: row.id };
13366
13624
  }
13625
+ var HOSTED_RULE = "UPSTREAM_HOSTED";
13626
+ var PROTECTED_RULE = "UPSTREAM_PROTECTED";
13627
+ function validateProductionUrl(input) {
13628
+ const v = (input ?? "").trim();
13629
+ if (!/^https:\/\//i.test(v)) return "It must start with https://";
13630
+ let host = "";
13631
+ try {
13632
+ host = new URL(v).hostname.toLowerCase().replace(/^\[|\]$/g, "");
13633
+ } catch {
13634
+ return `${v} is not a URL.`;
13635
+ }
13636
+ const privateHost = host === "localhost" || host === "::1" || /\.(localhost|local|internal)$/.test(host) || /^(127\.|10\.|192\.168\.|169\.254\.|0\.)/.test(host) || /^172\.(1[6-9]|2\d|3[01])\./.test(host);
13637
+ return privateHost ? `${host} is this machine or a private network; reviewers cannot reach it.` : true;
13638
+ }
13639
+ function parseUpstreamHeader(opts) {
13640
+ if (opts.upstreamHeader !== void 0 && opts.upstreamHeaderEnv !== void 0) throw new Error("Pass one of --upstream-header and --upstream-header-env.");
13641
+ if (opts.upstreamHeaderEnv !== void 0) {
13642
+ const i2 = opts.upstreamHeaderEnv.indexOf("=");
13643
+ const name2 = i2 > 0 ? opts.upstreamHeaderEnv.slice(0, i2).trim() : "";
13644
+ const variable = i2 > 0 ? opts.upstreamHeaderEnv.slice(i2 + 1).trim() : "";
13645
+ if (!name2 || !variable) throw new Error("--upstream-header-env wants NAME=ENVVAR.");
13646
+ const value2 = process.env[variable];
13647
+ if (!value2) throw new Error(`Environment variable ${variable} is empty or not set.`);
13648
+ return { name: name2, value: value2 };
13649
+ }
13650
+ if (opts.upstreamHeader === void 0) return null;
13651
+ const i = opts.upstreamHeader.indexOf(":");
13652
+ const name = i > 0 ? opts.upstreamHeader.slice(0, i).trim() : "";
13653
+ const value = i > 0 ? opts.upstreamHeader.slice(i + 1).trim() : "";
13654
+ if (!name || !value) throw new Error('--upstream-header wants "Name: value".');
13655
+ return { name, value };
13656
+ }
13657
+ async function ensureHostedUpstream(caller, teamId, proj2, r, opts, interactive2, say, refetch) {
13658
+ const failing = (x, id) => x.report.results.some((y) => y.id === id && !y.pass);
13659
+ const shape = (x) => x.target ?? {};
13660
+ let cur = r;
13661
+ const header = parseUpstreamHeader(opts);
13662
+ if (header && opts.upstreamOpen) throw new Error("Pass one of --upstream-header and --upstream-open.");
13663
+ if (failing(cur, HOSTED_RULE)) {
13664
+ let url = opts.targetUrl?.trim();
13665
+ if (url) {
13666
+ const ok = validateProductionUrl(url);
13667
+ if (ok !== true) throw new Error(`--target-url: ${ok}`);
13668
+ } else if (interactive2) {
13669
+ say(" A listing has to stay up when your laptop sleeps, so reviewers and users need the hosted app, not this machine.");
13670
+ const { default: inquirer3 } = await import("inquirer");
13671
+ const { value } = await inquirer3.prompt([{ type: "input", name: "value", message: "Where does this run in production? (https URL; Enter to skip for now)", validate: (v) => !(v ?? "").trim() ? true : validateProductionUrl(v) }]);
13672
+ url = value?.trim();
13673
+ }
13674
+ if (url) {
13675
+ const env = cur.report.project.environment;
13676
+ const { environmentsWithTarget: environmentsWithTarget2 } = await Promise.resolve().then(() => (init_config(), config_exports));
13677
+ const environments = await environmentsWithTarget2(caller, teamId, proj2, env, url);
13678
+ await patchProject(caller, proj2, { environments }, `Point ${env} at ${url}`);
13679
+ say(import_chalk32.default.green(` \u2713 ${env} now forwards to ${url}`));
13680
+ cur = await refetch();
13681
+ } else {
13682
+ say(import_chalk32.default.dim(` Skipped: still not hosted, so this cannot be submitted yet. Everything else goes on; ${B.cli} connector ${proj2.projectName} --target-url <url> finishes it.`));
13683
+ }
13684
+ } else if (opts.targetUrl) {
13685
+ say(import_chalk32.default.dim(` --target-url ignored: this already forwards to a hosted server (${shape(cur).hosts?.upstreamTarget ?? "see the scorecard"}).`));
13686
+ }
13687
+ const skipped = shape(cur).metadata?.skippedRules ?? [];
13688
+ if (failing(cur, PROTECTED_RULE) && !skipped.includes(PROTECTED_RULE)) {
13689
+ let chosen = header;
13690
+ let open = !!opts.upstreamOpen;
13691
+ if (!chosen && !open && interactive2) {
13692
+ if (shape(cur).hosts?.upstreamKind === "public" && !shape(cur).hosts?.upstreamHeader) say(import_chalk32.default.dim(" An open backend can be called around sign-in and the per-user rules; a shared secret header closes that."));
13693
+ const { default: inquirer3 } = await import("inquirer");
13694
+ const { name } = await inquirer3.prompt([{ type: "input", name: "name", message: `Does the backend need a header to accept calls from ${B.product}, such as an API key or a shared secret? (Header name; Enter = no, it checks its own credentials)` }]);
13695
+ if (name?.trim()) {
13696
+ const { value } = await inquirer3.prompt([{ type: "password", name: "value", mask: "*", message: `Value of ${name.trim()} (stored encrypted, never shown again):`, validate: (v) => (v ?? "").length > 0 ? true : "A value is needed; Ctrl-C leaves." }]);
13697
+ chosen = { name: name.trim(), value };
13698
+ } else open = true;
13699
+ }
13700
+ if (chosen) {
13701
+ const { setUpstreamHeader: setUpstreamHeader2 } = await Promise.resolve().then(() => (init_transform(), transform_exports));
13702
+ await setUpstreamHeader2(caller, proj2, chosen.name, chosen.value);
13703
+ say(import_chalk32.default.green(` \u2713 every forwarded call now carries ${chosen.name} (stored encrypted)`));
13704
+ cur = await refetch();
13705
+ } else if (open) {
13706
+ await patchProject(caller, proj2, { directory_metadata: { skipped_rules: [.../* @__PURE__ */ new Set([...skipped, PROTECTED_RULE])] } }, "The backend checks its own credentials");
13707
+ cur = await refetch();
13708
+ }
13709
+ }
13710
+ return cur;
13711
+ }
13367
13712
  function generatePassword(bytes = () => crypto.getRandomValues(new Uint8Array(20))) {
13368
13713
  const alphabet = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";
13369
13714
  return Array.from(bytes(), (b) => alphabet[b % alphabet.length]).join("");
@@ -13399,12 +13744,12 @@ async function ensureReviewerAccount(caller, teamId, proj2, opts = {}) {
13399
13744
  return { username: finalUser, password, tenant: proj2.tenant };
13400
13745
  }
13401
13746
  function printReviewer(acct, proj2) {
13402
- console.log(import_chalk30.default.green(`Reviewer account ${import_chalk30.default.bold(acct.username)} on tenant ${acct.tenant} \u2014 stored (encrypted) for the submission packet.`));
13747
+ console.log(import_chalk32.default.green(`Reviewer account ${import_chalk32.default.bold(acct.username)} on tenant ${acct.tenant} \u2014 stored (encrypted) for the submission packet.`));
13403
13748
  console.log();
13404
- console.log(import_chalk30.default.bold(" Password (shown once):"));
13405
- console.log(` ${import_chalk30.default.cyan(acct.username)} ${import_chalk30.default.bgWhite.black(` ${acct.password} `)}`);
13749
+ console.log(import_chalk32.default.bold(" Password (shown once):"));
13750
+ console.log(` ${import_chalk32.default.cyan(acct.username)} ${import_chalk32.default.bgWhite.black(` ${acct.password} `)}`);
13406
13751
  console.log();
13407
- console.log(import_chalk30.default.dim(` Seed realistic data through the ${B.thingShort} (billed per turn): ${B.cli} agent --seed-for ${proj2.projectName}`));
13752
+ console.log(import_chalk32.default.dim(` Seed realistic data through the ${B.thingShort} (billed per turn): ${B.cli} agent --seed-for ${proj2.projectName}`));
13408
13753
  }
13409
13754
  async function runConnectorReviewer(project, opts) {
13410
13755
  const caller = requireCaller();
@@ -13446,7 +13791,7 @@ async function interruptConnector(ctx) {
13446
13791
  const sum = summaryOf(r);
13447
13792
  if (!ctx.json) {
13448
13793
  console.log("");
13449
- console.log(import_chalk30.default.bold(`Saved.${sum ? ` ${sum}.` : ""}`) + ` Pick up any time: ${import_chalk30.default.cyan(`${B.cli} connector ${ctx.proj.projectId}`)} or ${import_chalk30.default.cyan(pageLinkOf(r, ctx.proj))}`);
13794
+ console.log(import_chalk32.default.bold(`Saved.${sum ? ` ${sum}.` : ""}`) + ` Pick up any time: ${import_chalk32.default.cyan(`${B.cli} connector ${ctx.proj.projectId}`)} or ${import_chalk32.default.cyan(pageLinkOf(r, ctx.proj))}`);
13450
13795
  }
13451
13796
  process.exit(0);
13452
13797
  }
@@ -13478,7 +13823,7 @@ async function runConnector(target2, opts) {
13478
13823
  const created = await createFromSpec(specSource, opts, say);
13479
13824
  projectName = created.name;
13480
13825
  version2 = created.version;
13481
- say(import_chalk30.default.green(` ${B.thing} ${import_chalk30.default.bold(created.name)} created.`));
13826
+ say(import_chalk32.default.green(` ${B.thing} ${import_chalk32.default.bold(created.name)} created.`));
13482
13827
  }
13483
13828
  const proj2 = await resolveProjectVia(caller, teamId, projectName, version2);
13484
13829
  const flagBody = directoryBodyFromFlags(opts);
@@ -13490,7 +13835,7 @@ async function runConnector(target2, opts) {
13490
13835
  process.stdout.write(JSON.stringify({ attested: Object.keys(flagBody.directory_attestations), headline: r2.rendered.headline, summary: r2.progress?.summary ?? null }) + "\n");
13491
13836
  return;
13492
13837
  }
13493
- say(import_chalk30.default.green(`Attested: ${Object.keys(flagBody.directory_attestations).join(", ")}.`) + import_chalk30.default.dim(` ${summaryOf(r2) ?? r2.rendered.headline}`));
13838
+ say(import_chalk32.default.green(`Attested: ${Object.keys(flagBody.directory_attestations).join(", ")}.`) + import_chalk32.default.dim(` ${summaryOf(r2) ?? r2.rendered.headline}`));
13494
13839
  return;
13495
13840
  }
13496
13841
  const explicit = compliantGiven(opts);
@@ -13516,36 +13861,36 @@ async function runConnector(target2, opts) {
13516
13861
  const dirsDiffer = explicit && !!stored && (stored.length !== platforms.length || stored.some((p) => !platforms.includes(p)));
13517
13862
  const needPatch = !modeOn || !!flagBody.directory_metadata || !!flagBody.directory_attestations || !!flagBody.openai_challenge_token || dirsDiffer;
13518
13863
  if (needPatch) {
13519
- const sp = json || modeOn ? null : (0, import_ora10.default)(`Turning directory-ready mode on for ${proj2.projectName}\u2026`).start();
13864
+ const sp = json || modeOn ? null : (0, import_ora12.default)(`Turning directory-ready mode on for ${proj2.projectName}\u2026`).start();
13520
13865
  const meta = { ...flagBody.directory_metadata ?? {}, ...!modeOn || dirsDiffer || !stored ? { directories: platforms } : {} };
13521
13866
  await patchProject(caller, proj2, { directory_ready: true, ...flagBody, directory_metadata: meta }, modeOn ? "Save the flags" : "Enable directory-ready mode");
13522
13867
  sp?.succeed(`Directory-ready mode is on for ${proj2.projectName} v${proj2.apiVersion}.`);
13523
- if (dirsDiffer) say(import_chalk30.default.dim(` directories: ${platforms.map((p) => p === "claude" ? "Claude" : "ChatGPT").join(" + ")} (was ${stored.map((p) => p === "claude" ? "Claude" : "ChatGPT").join(" + ")})`));
13868
+ if (dirsDiffer) say(import_chalk32.default.dim(` directories: ${platforms.map((p) => p === "claude" ? "Claude" : "ChatGPT").join(" + ")} (was ${stored.map((p) => p === "claude" ? "Claude" : "ChatGPT").join(" + ")})`));
13524
13869
  r = await fetchDirectoryReport(caller, proj2, reportOpts());
13525
13870
  }
13526
13871
  const link = pageLinkOf(r, proj2);
13527
13872
  const sum = summaryOf(r);
13528
13873
  if (sum) {
13529
- say(`${import_chalk30.default.bold("Finish this here or at")} ${import_chalk30.default.cyan(link)} ${import_chalk30.default.dim("\xB7")} ${import_chalk30.default.bold(sum)}`);
13874
+ say(`${import_chalk32.default.bold("Finish this here or at")} ${import_chalk32.default.cyan(link)} ${import_chalk32.default.dim("\xB7")} ${import_chalk32.default.bold(sum)}`);
13530
13875
  const done = doneLine(r);
13531
- if (done) say(import_chalk30.default.dim(` ${done}`));
13876
+ if (done) say(import_chalk32.default.dim(` ${done}`));
13532
13877
  } else {
13533
- say(import_chalk30.default.dim(` ${r.rendered.headline}`));
13878
+ say(import_chalk32.default.dim(` ${r.rendered.headline}`));
13534
13879
  }
13535
13880
  const framed = /* @__PURE__ */ new Set();
13536
13881
  const frame = (id) => {
13537
13882
  const st = stepOf(r, id);
13538
13883
  if (!st || framed.has(id)) return;
13539
13884
  framed.add(id);
13540
- say(import_chalk30.default.bold(`\u2500\u2500 ${st.n} ${st.title} (${openCount(st)} left) \u2500\u2500`));
13885
+ say(import_chalk32.default.bold(`\u2500\u2500 ${st.n} ${st.title} (${openCount(st)} left) \u2500\u2500`));
13541
13886
  };
13542
13887
  const closed = (id) => {
13543
13888
  const st = stepOf(r, id);
13544
- if (st && framed.has(id) && st.status === "done") say(import_chalk30.default.green(` \u2713 ${st.n} ${st.title}`));
13889
+ if (st && framed.has(id) && st.status === "done") say(import_chalk32.default.green(` \u2713 ${st.n} ${st.title}`));
13545
13890
  };
13546
13891
  const formHint = (id) => {
13547
13892
  const st = stepOf(r, id);
13548
- if (st && framed.has(id) && interactive2) say(import_chalk30.default.dim(` Prefer a form? ${pageLinkOf(r, proj2, st.web)} has the same fields.`));
13893
+ if (st && framed.has(id) && interactive2) say(import_chalk32.default.dim(` Prefer a form? ${pageLinkOf(r, proj2, st.web)} has the same fields.`));
13549
13894
  };
13550
13895
  const open = (id) => stepOpen(stepOf(r, id));
13551
13896
  const runnable = (id) => stepRunnable(stepOf(r, id));
@@ -13560,7 +13905,7 @@ async function runConnector(target2, opts) {
13560
13905
  if (isApiError(e, 404)) return { applied: [], skipped: [{ fix: "all", reason: "server has no auto-fixes yet" }] };
13561
13906
  throw e;
13562
13907
  });
13563
- for (const f2 of fixes.applied ?? []) say(import_chalk30.default.green(` \u2713 fixed: ${f2}`));
13908
+ for (const f2 of fixes.applied ?? []) say(import_chalk32.default.green(` \u2713 fixed: ${f2}`));
13564
13909
  if (fixes.applied?.length) r = await fetchDirectoryReport(caller, proj2, reportOpts());
13565
13910
  }
13566
13911
  let defaults = { prompts: [] };
@@ -13577,6 +13922,7 @@ async function runConnector(target2, opts) {
13577
13922
  let domain = { active: true };
13578
13923
  if (wantStep("address") && open("address")) {
13579
13924
  frame("address");
13925
+ r = await ensureHostedUpstream(caller, teamId, proj2, r, opts, interactive2, say, () => fetchDirectoryReport(caller, proj2, reportOpts()));
13580
13926
  const domainWasBlocking = r.report.results.some((x) => x.id === DOMAIN_RULE && !x.pass);
13581
13927
  domain = await ensureMcpDomain(caller, proj2, r, { ...opts, wait: 0 }, defaults, interactive2, say);
13582
13928
  if (domainWasBlocking && domain.active) r = await fetchDirectoryReport(caller, proj2, reportOpts());
@@ -13630,10 +13976,10 @@ async function runConnector(target2, opts) {
13630
13976
  }
13631
13977
  if (!tester) return { called: true, tools: [] };
13632
13978
  const t = tester;
13633
- say(import_chalk30.default.dim(` trying it through ${t.clients.map((c) => c === "claude" ? "Claude Code" : "Codex CLI").join(" and ")}\u2026`));
13979
+ say(import_chalk32.default.dim(` trying it through ${t.clients.map((c) => c === "claude" ? "Claude Code" : "Codex CLI").join(" and ")}\u2026`));
13634
13980
  const res = await t.test(p);
13635
13981
  if (res.tools.length) await patchProject(caller, proj2, { directory_metadata: { prompt_tools: { [p.trim()]: res.tools } } }, "Remember which tool the prompt called").catch(() => null);
13636
- for (const [client, rr] of Object.entries(res.byClient)) say(rr.called ? import_chalk30.default.green(` \u2713 ${client === "claude" ? "Claude" : "Codex"} called ${rr.tools.join(", ")}`) : import_chalk30.default.yellow(` \u2013 ${client === "claude" ? "Claude" : "Codex"} called no tool`));
13982
+ for (const [client, rr] of Object.entries(res.byClient)) say(rr.called ? import_chalk32.default.green(` \u2713 ${client === "claude" ? "Claude" : "Codex"} called ${rr.tools.join(", ")}`) : import_chalk32.default.yellow(` \u2013 ${client === "claude" ? "Claude" : "Codex"} called no tool`));
13637
13983
  return res;
13638
13984
  };
13639
13985
  const askSteps = ["listing", "attestations", "token"].filter((id) => wantStep(id) && runnable(id));
@@ -13687,11 +14033,11 @@ async function runConnector(target2, opts) {
13687
14033
  const { runConnectorExercise: runConnectorExercise2 } = await Promise.resolve().then(() => (init_connector_exercise(), connector_exercise_exports));
13688
14034
  const ran = await runConnectorExercise2(proj2.projectId, { team: opts.team ?? proj2.teamId, apiversion: opts.apiversion, json, yes: opts.yes, noEmail: opts.email === false, report: false, platforms: [...platforms], provenPromptNotes, seed: opts.seed });
13689
14035
  if (interactive2 && ran.failedPrompts.length) {
13690
- for (const [p, clients] of Object.entries(ran.failedByClient ?? {})) say(import_chalk30.default.yellow(` \u2013 "${p.slice(0, 60)}": no tool call in ${clients.map((c) => c === "claude" ? "Claude Code" : "Codex CLI").join(" and ")}`));
14036
+ for (const [p, clients] of Object.entries(ran.failedByClient ?? {})) say(import_chalk32.default.yellow(` \u2013 "${p.slice(0, 60)}": no tool call in ${clients.map((c) => c === "claude" ? "Claude Code" : "Codex CLI").join(" and ")}`));
13691
14037
  const { rewritten, prompts } = await rewriteFailedPrompts(r, ran.failedPrompts, saveAnswer, say);
13692
14038
  if (rewritten.length) {
13693
14039
  const { clientsFor: clientsFor2 } = await Promise.resolve().then(() => (init_connector_exercise(), connector_exercise_exports));
13694
- say(import_chalk30.default.dim(` Running the ${prompts.length} prompts through ${clientsFor2(platforms).map((c) => c === "claude" ? "Claude Code" : "Codex CLI").join(" and ")} again (the report reads the last run)\u2026`));
14040
+ say(import_chalk32.default.dim(` Running the ${prompts.length} prompts through ${clientsFor2(platforms).map((c) => c === "claude" ? "Claude Code" : "Codex CLI").join(" and ")} again (the report reads the last run)\u2026`));
13695
14041
  const again = await runConnectorExercise2(proj2.projectId, { team: opts.team ?? proj2.teamId, apiversion: opts.apiversion, json, noEmail: opts.email === false, report: false, platforms: [...platforms], promptsOnly: prompts, provenPromptNotes: ran.notes.filter((n) => n.kind === "negative") });
13696
14042
  ran.promptTools = { ...ran.promptTools, ...again.promptTools };
13697
14043
  ran.codexPromptTools = { ...ran.codexPromptTools, ...again.codexPromptTools };
@@ -13717,13 +14063,13 @@ async function runConnector(target2, opts) {
13717
14063
  process.exit(isReady(r, platforms) ? 0 : 1);
13718
14064
  }
13719
14065
  say("");
13720
- say(`${import_chalk30.default.bold(s2 ?? r.rendered.headline)} ${import_chalk30.default.dim(`\xB7 ${link}`)}`);
14066
+ say(`${import_chalk32.default.bold(s2 ?? r.rendered.headline)} ${import_chalk32.default.dim(`\xB7 ${link}`)}`);
13721
14067
  process.exit(isReady(r, platforms) ? 0 : 1);
13722
14068
  }
13723
14069
  const tokenOnly = readyExcept(r, platforms, [SNAPSHOT_RULE, TOKEN_RULE]) && r.report.results.some((x) => x.id === TOKEN_RULE && !x.pass);
13724
14070
  if (!readyExceptSnapshot(r, platforms) && !tokenOnly) {
13725
14071
  if (!domain.active && domain.hostname && !json) {
13726
- console.error(import_chalk30.default.yellow(`
14072
+ console.error(import_chalk32.default.yellow(`
13727
14073
  ${domain.hostname} is not active yet. Once the CNAME is in place, run again: ${B.cli} connector ${proj2.projectId}`));
13728
14074
  }
13729
14075
  exitWithReport(r, proj2, platforms, json, interactive2, opts.verbose);
@@ -13732,7 +14078,7 @@ async function runConnector(target2, opts) {
13732
14078
  let watching = false;
13733
14079
  if (opts.watch !== false) {
13734
14080
  watching = await producer(caller, { method: "POST", path: `${projectPath3(proj2)}/directory-watch`, body: { enabled: true }, summary: "Turn on the nightly re-check" }).then(() => true).catch((e) => {
13735
- say(import_chalk30.default.dim(` (nightly re-check not switched on: ${e.message})`));
14081
+ say(import_chalk32.default.dim(` (nightly re-check not switched on: ${e.message})`));
13736
14082
  return false;
13737
14083
  });
13738
14084
  }
@@ -13750,7 +14096,7 @@ async function runConnector(target2, opts) {
13750
14096
  const manifest = packet.json.chatgpt;
13751
14097
  if (manifest) {
13752
14098
  const written = await writePluginPackage2(dir, manifest);
13753
- if (written.problem) say(import_chalk30.default.yellow(` ${written.problem}`));
14099
+ if (written.problem) say(import_chalk32.default.yellow(` ${written.problem}`));
13754
14100
  zipPath = written.zipPath;
13755
14101
  if (written.seq) await patchProject(caller, proj2, { directory_metadata: { plugin_package_seq: written.seq } }, "Bump the plugin package version").catch(() => null);
13756
14102
  }
@@ -13764,28 +14110,28 @@ async function runConnector(target2, opts) {
13764
14110
  console.log();
13765
14111
  const card = scorecardText(r);
13766
14112
  if (opts.verbose && r.rendered.compliance) {
13767
- console.log(r.rendered.compliance.split("\n").map((l, i) => i === 0 ? import_chalk30.default.bold(l) : l.replace(/^(\s+)✓ /, (_m, sp) => `${sp}${import_chalk30.default.green("\u2713")} `).replace(/^(\s+)! /, (_m, sp) => `${sp}${import_chalk30.default.yellow("!")} `)).join("\n"));
14113
+ console.log(r.rendered.compliance.split("\n").map((l, i) => i === 0 ? import_chalk32.default.bold(l) : l.replace(/^(\s+)✓ /, (_m, sp) => `${sp}${import_chalk32.default.green("\u2713")} `).replace(/^(\s+)! /, (_m, sp) => `${sp}${import_chalk32.default.yellow("!")} `)).join("\n"));
13768
14114
  } else if (card) {
13769
14115
  console.log(card);
13770
14116
  } else if (r.rendered.compliance) {
13771
- console.log(r.rendered.compliance.split("\n").map((l, i) => i === 0 ? import_chalk30.default.bold(l) : l.replace(/^(\s+)✓ /, (_m, sp) => `${sp}${import_chalk30.default.green("\u2713")} `).replace(/^(\s+)! /, (_m, sp) => `${sp}${import_chalk30.default.yellow("!")} `)).join("\n"));
14117
+ console.log(r.rendered.compliance.split("\n").map((l, i) => i === 0 ? import_chalk32.default.bold(l) : l.replace(/^(\s+)✓ /, (_m, sp) => `${sp}${import_chalk32.default.green("\u2713")} `).replace(/^(\s+)! /, (_m, sp) => `${sp}${import_chalk32.default.yellow("!")} `)).join("\n"));
13772
14118
  } else {
13773
14119
  printReport(r, false);
13774
14120
  }
13775
14121
  console.log();
13776
- console.log(import_chalk30.default.green.bold(` ${r.rendered.headline}`));
13777
- console.log(` Submission packet: ${import_chalk30.default.cyan(mdPath)} and ${import_chalk30.default.cyan(jsonPath)}${zipPath ? `
13778
- OpenAI plugin package: ${import_chalk30.default.cyan(zipPath)}` : ""}`);
13779
- console.log(import_chalk30.default.dim(isOpenMode(r) ? " (open mode: no reviewer credentials in the packet; the connector takes no sign-in)" : " (the packet carries the reviewer credentials \u2014 keep it out of git)"));
14122
+ console.log(import_chalk32.default.green.bold(` ${r.rendered.headline}`));
14123
+ console.log(` Submission packet: ${import_chalk32.default.cyan(mdPath)} and ${import_chalk32.default.cyan(jsonPath)}${zipPath ? `
14124
+ OpenAI plugin package: ${import_chalk32.default.cyan(zipPath)}` : ""}`);
14125
+ console.log(import_chalk32.default.dim(isOpenMode(r) ? " (open mode: no reviewer credentials in the packet; the connector takes no sign-in)" : " (the packet carries the reviewer credentials \u2014 keep it out of git)"));
13780
14126
  printSubmitSteps(r, mdPath, platforms, watching);
13781
14127
  if (tokenOnly) {
13782
14128
  const tok = r.report.results.find((x) => x.id === TOKEN_RULE);
13783
- console.log(import_chalk30.default.yellow(` One thing left for ChatGPT: ${withProject(tok?.fix ?? "paste the OpenAI domain token", proj2.projectId)}`));
13784
- console.log(import_chalk30.default.dim(` Then tell us you submitted: ${B.cli} connector submitted ${proj2.projectId}`));
14129
+ console.log(import_chalk32.default.yellow(` One thing left for ChatGPT: ${withProject(tok?.fix ?? "paste the OpenAI domain token", proj2.projectId)}`));
14130
+ console.log(import_chalk32.default.dim(` Then tell us you submitted: ${B.cli} connector submitted ${proj2.projectId}`));
13785
14131
  } else {
13786
- console.log(import_chalk30.default.dim(` When you have submitted: ${B.cli} connector submitted ${proj2.projectId} \u2014 we re-check nightly and email you if anything drifts.`));
14132
+ console.log(import_chalk32.default.dim(` When you have submitted: ${B.cli} connector submitted ${proj2.projectId} \u2014 we re-check nightly and email you if anything drifts.`));
13787
14133
  }
13788
- console.log(import_chalk30.default.dim(` ${r.report.disclaimer}`));
14134
+ console.log(import_chalk32.default.dim(` ${r.report.disclaimer}`));
13789
14135
  if (!isReady(r, platforms)) process.exit(1);
13790
14136
  } catch (e) {
13791
14137
  if (interrupting) return;
@@ -13808,7 +14154,7 @@ async function waitForExternal(caller, proj2, r, platforms, domain, opts, intera
13808
14154
  const sleep2 = deps.sleep ?? ((ms2) => new Promise((res) => setTimeout(res, ms2)));
13809
14155
  const link = pageLinkOf(r, proj2, "#step-9");
13810
14156
  say("");
13811
- say(import_chalk30.default.bold(` Waiting for: ${[needDomain ? `your CNAME (${domain.hostname})` : null, needLogin ? "your Claude sign-in" : null].filter(Boolean).join(" \xB7 ")}`));
14157
+ say(import_chalk32.default.bold(` Waiting for: ${[needDomain ? `your CNAME (${domain.hostname})` : null, needLogin ? "your Claude sign-in" : null].filter(Boolean).join(" \xB7 ")}`));
13812
14158
  if (needLogin) {
13813
14159
  const url = r.report.project.publishedUrl ?? "";
13814
14160
  const name = r.target?.metadata?.serverName ?? proj2.projectId;
@@ -13816,19 +14162,19 @@ async function waitForExternal(caller, proj2, r, platforms, domain, opts, intera
13816
14162
  say(" One sign-in from a real Claude client is the last proof. In another terminal:");
13817
14163
  say(` claude mcp add --transport http ${alias} ${url}`);
13818
14164
  say(` claude then /mcp \u2192 ${alias} \u2192 sign in with the reviewer account`);
13819
- say(import_chalk30.default.dim(` or in claude.ai: Settings \u2192 Connectors \u2192 Add custom connector \u2192 ${url} (what a reviewer does).`));
13820
- say(import_chalk30.default.dim(` Afterwards: claude mcp remove ${alias}`));
14165
+ say(import_chalk32.default.dim(` or in claude.ai: Settings \u2192 Connectors \u2192 Add custom connector \u2192 ${url} (what a reviewer does).`));
14166
+ say(import_chalk32.default.dim(` Afterwards: claude mcp remove ${alias}`));
13821
14167
  const { default: inquirer3 } = await import("inquirer");
13822
14168
  const { go } = await inquirer3.prompt([{ type: "confirm", name: "go", message: "Sign in from Claude now, then press Enter to check (n skips; the step stays open):", default: true }]);
13823
14169
  if (!go) needLogin = false;
13824
14170
  if (!needDomain && !needLogin) return r;
13825
14171
  }
13826
- say(import_chalk30.default.dim(` Or leave now: run ${B.cli} connector ${proj2.projectId} again any time, or watch it at ${link}`));
14172
+ say(import_chalk32.default.dim(` Or leave now: run ${B.cli} connector ${proj2.projectId} again any time, or watch it at ${link}`));
13827
14173
  const base2 = `/projects/${encodeURIComponent(proj2.projectId)}/domains`;
13828
14174
  const started = now();
13829
14175
  const domainUntil = started + minutes * 6e4;
13830
14176
  const loginUntil = started + (deps.maxLoginMs ?? 10 * 6e4);
13831
- const sp = opts.json ? null : (0, import_ora10.default)("Checking every 15 seconds\u2026").start();
14177
+ const sp = opts.json ? null : (0, import_ora12.default)("Checking every 15 seconds\u2026").start();
13832
14178
  let cur = r;
13833
14179
  let status2 = "pending";
13834
14180
  let activated = false;
@@ -13839,13 +14185,13 @@ async function waitForExternal(caller, proj2, r, platforms, domain, opts, intera
13839
14185
  status2 = s?.status ?? status2;
13840
14186
  if (status2 === "active") {
13841
14187
  sp?.stop();
13842
- say(import_chalk30.default.green(` \u2713 ${domain.hostname} is active.`));
14188
+ say(import_chalk32.default.green(` \u2713 ${domain.hostname} is active.`));
13843
14189
  sp?.start();
13844
14190
  needDomain = false;
13845
14191
  activated = true;
13846
14192
  } else if (status2 === "suspended" || status2 === "missing" || now() >= domainUntil) {
13847
14193
  sp?.stop();
13848
- say(import_chalk30.default.yellow(` \u2013 ${domain.hostname} is not active yet (${status2}); run again once the CNAME is in place.`));
14194
+ say(import_chalk32.default.yellow(` \u2013 ${domain.hostname} is not active yet (${status2}); run again once the CNAME is in place.`));
13849
14195
  sp?.start();
13850
14196
  needDomain = false;
13851
14197
  }
@@ -13855,12 +14201,12 @@ async function waitForExternal(caller, proj2, r, platforms, domain, opts, intera
13855
14201
  const nowRule = cur.report.results.find((x) => x.id === "OAUTH_FLOW_COMPLETED");
13856
14202
  if (nowRule?.pass) {
13857
14203
  sp?.stop();
13858
- say(import_chalk30.default.green(` \u2713 ${nowRule.message ?? "a Claude client completed the sign-in"}`));
14204
+ say(import_chalk32.default.green(` \u2713 ${nowRule.message ?? "a Claude client completed the sign-in"}`));
13859
14205
  sp?.start();
13860
14206
  needLogin = false;
13861
14207
  } else if (now() >= loginUntil) {
13862
14208
  sp?.stop();
13863
- say(import_chalk30.default.yellow(" \u2013 no Claude sign-in seen in 10 minutes; run again after signing in."));
14209
+ say(import_chalk32.default.yellow(" \u2013 no Claude sign-in seen in 10 minutes; run again after signing in."));
13864
14210
  sp?.start();
13865
14211
  needLogin = false;
13866
14212
  }
@@ -13888,16 +14234,16 @@ async function runConnectorSubmitted(project, opts) {
13888
14234
  writeJsonLine({ project: proj2.projectId, submitted: r.progress?.submitted ?? submitted, summary: r.progress?.summary ?? null, line: step?.line ?? null });
13889
14235
  return;
13890
14236
  }
13891
- console.log(import_chalk30.default.green(` \u2713 ${opts.undo ? "forgotten" : "recorded"}: ${dirs.map((p) => p === "claude" ? "Claude" : "ChatGPT").join(" + ")}`));
14237
+ console.log(import_chalk32.default.green(` \u2713 ${opts.undo ? "forgotten" : "recorded"}: ${dirs.map((p) => p === "claude" ? "Claude" : "ChatGPT").join(" + ")}`));
13892
14238
  if (step) console.log(` ${step.line}`);
13893
- console.log(import_chalk30.default.dim(` ${summaryOf(r) ?? r.rendered.headline} \xB7 ${pageLinkOf(r, proj2)}`));
14239
+ console.log(import_chalk32.default.dim(` ${summaryOf(r) ?? r.rendered.headline} \xB7 ${pageLinkOf(r, proj2)}`));
13894
14240
  }
13895
14241
  async function rewriteFailedPrompts(r, failed, save, say) {
13896
14242
  const current = currentListingValue(r, "prompt");
13897
14243
  const list = Array.isArray(current) ? [...current] : [];
13898
14244
  const { default: inquirer3 } = await import("inquirer");
13899
14245
  const rewritten = [];
13900
- say(import_chalk30.default.yellow(` ${failed.length === 1 ? "This prompt" : `${failed.length} prompts`} produced no tool call; a prompt should name what the tool does${failed.length === 1 ? "" : ", one at a time"}:`));
14246
+ say(import_chalk32.default.yellow(` ${failed.length === 1 ? "This prompt" : `${failed.length} prompts`} produced no tool call; a prompt should name what the tool does${failed.length === 1 ? "" : ", one at a time"}:`));
13901
14247
  for (const old of failed) {
13902
14248
  const { value } = await inquirer3.prompt([{ type: "input", name: "value", message: `Rewrite "${old}" (Enter keeps it):`, default: old, validate: (v) => v.trim().length <= 300 ? true : `${v.trim().length} characters; 300 at most` }]);
13903
14249
  const next = (value ?? "").trim();
@@ -13910,7 +14256,7 @@ async function rewriteFailedPrompts(r, failed, save, say) {
13910
14256
  if (rewritten.length) {
13911
14257
  const why = await save({ prompt: list });
13912
14258
  if (why) {
13913
- say_(import_chalk30.default.yellow(` not saved: ${why}`));
14259
+ say_(import_chalk32.default.yellow(` not saved: ${why}`));
13914
14260
  return { rewritten: [], prompts: list };
13915
14261
  }
13916
14262
  }
@@ -13955,9 +14301,9 @@ async function offerDrafts(caller, proj2, r, ran, interactive2, say, platforms =
13955
14301
  try {
13956
14302
  await patchProject(caller, proj2, { directory_portal_answers: { chatgpt_test_cases: cases } }, "Save OpenAI's test cases");
13957
14303
  saved = true;
13958
- say(import_chalk30.default.green(` \u2713 OpenAI's positive test cases written from the Codex run: ${cases.positive.length}/5${cases.positive.length < 5 ? " (more prompts that call a tool are needed for five)" : ""}`));
14304
+ say(import_chalk32.default.green(` \u2713 OpenAI's positive test cases written from the Codex run: ${cases.positive.length}/5${cases.positive.length < 5 ? " (more prompts that call a tool are needed for five)" : ""}`));
13959
14305
  } catch (e) {
13960
- say(import_chalk30.default.yellow(` not saved: ${e instanceof Error ? e.message : String(e)}`));
14306
+ say(import_chalk32.default.yellow(` not saved: ${e instanceof Error ? e.message : String(e)}`));
13961
14307
  }
13962
14308
  }
13963
14309
  }
@@ -13965,11 +14311,11 @@ async function offerDrafts(caller, proj2, r, ran, interactive2, say, platforms =
13965
14311
  if (!drafts.length) return saved;
13966
14312
  const inquirer3 = interactive2 ? (await import("inquirer")).default : null;
13967
14313
  say("");
13968
- say(import_chalk30.default.bold(` Written from the run \u2014 the portal's ${drafts.map((d) => d.label.toLowerCase()).join(", ")}:`));
14314
+ say(import_chalk32.default.bold(` Written from the run \u2014 the portal's ${drafts.map((d) => d.label.toLowerCase()).join(", ")}:`));
13969
14315
  for (const d of drafts) {
13970
14316
  let text = d.draft;
13971
14317
  say("");
13972
- say(import_chalk30.default.bold(` ${d.label}`) + import_chalk30.default.dim(` (${d.draft.length} characters; the portal wants ${ANSWER_MIN2[d.key]}+)`));
14318
+ say(import_chalk32.default.bold(` ${d.label}`) + import_chalk32.default.dim(` (${d.draft.length} characters; the portal wants ${ANSWER_MIN2[d.key]}+)`));
13973
14319
  for (const line of d.draft.split("\n")) say(` ${line}`);
13974
14320
  if (inquirer3) {
13975
14321
  const { ok } = await inquirer3.prompt([{ type: "confirm", name: "ok", message: `Use this ${d.label.toLowerCase()}? (n = type your own)`, default: true }]);
@@ -13982,9 +14328,9 @@ async function offerDrafts(caller, proj2, r, ran, interactive2, say, platforms =
13982
14328
  try {
13983
14329
  await patchProject(caller, proj2, body, `Save the ${d.label.toLowerCase()}`);
13984
14330
  saved = true;
13985
- say(import_chalk30.default.green(` \u2713 ${d.label.toLowerCase()} saved`));
14331
+ say(import_chalk32.default.green(` \u2713 ${d.label.toLowerCase()} saved`));
13986
14332
  } catch (e) {
13987
- say(import_chalk30.default.yellow(` not saved: ${e instanceof Error ? e.message : String(e)}`));
14333
+ say(import_chalk32.default.yellow(` not saved: ${e instanceof Error ? e.message : String(e)}`));
13988
14334
  }
13989
14335
  }
13990
14336
  return saved;
@@ -14006,7 +14352,7 @@ function exitWithReport(r, proj2, platforms, json, interactive2 = false, verbose
14006
14352
  const blocking = r.report.results.filter((x) => !x.pass && x.severity === "block" && !x.unverified && x.platforms.some((p) => want.includes(p)));
14007
14353
  const real = blocking.filter((x) => x.id !== SNAPSHOT_RULE);
14008
14354
  const first = real.find((x) => x.tier !== "review") ?? real[0] ?? blocking[0];
14009
- console.error(import_chalk30.default.red(`
14355
+ console.error(import_chalk32.default.red(`
14010
14356
  Not ready: ${blocking.length} blocker${blocking.length === 1 ? "" : "s"} (${blocking.map((x) => x.id).join(", ")}).`));
14011
14357
  const name = proj2.projectId;
14012
14358
  if (!interactive2) {
@@ -14017,7 +14363,7 @@ Not ready: ${blocking.length} blocker${blocking.length === 1 ? "" : "s"} (${bloc
14017
14363
  if (answerish.length && answerish.every((x) => !x.platforms.includes("claude"))) console.error(` Next: ${withProject(answerish[0].fix ?? answerish[0].message ?? answerish[0].title, name)}`);
14018
14364
  else if (answerish.length) console.error(` Next: run \`${B.cli} connector ${name}${platforms.includes("chatgpt") ? ` --compliant ${platforms.length > 1 ? "all" : "chatgpt"}` : ""}\` in a terminal with the exercise on \u2014 it asks what only you can answer and writes the use cases, the reviewer instructions and the description from the run; or pass them: \`${B.cli} connector answers ${name} --use-cases \u2026 --data-handling own --health-data no --sponsored-content no\`.`);
14019
14365
  else if (first) console.error(` Next: ${withProject(first.fix ?? first.message ?? first.title, name)}`);
14020
- console.error(import_chalk30.default.dim(` Report page: ${pageLinkOf(r, proj2)}`));
14366
+ console.error(import_chalk32.default.dim(` Report page: ${pageLinkOf(r, proj2)}`));
14021
14367
  process.exit(1);
14022
14368
  }
14023
14369
  function flagsForRules(ids, platforms) {
@@ -14055,6 +14401,12 @@ function flagsForRules(ids, platforms) {
14055
14401
  case "REVIEWER_ACCOUNT_POPULATED":
14056
14402
  add("--seed");
14057
14403
  break;
14404
+ case HOSTED_RULE:
14405
+ add("--target-url <https://\u2026>");
14406
+ break;
14407
+ case PROTECTED_RULE:
14408
+ add('--upstream-header "<Name>: <value>" (or --upstream-open)');
14409
+ break;
14058
14410
  case "API_OWNERSHIP_DOMAIN":
14059
14411
  add('--data-handling own|proxied "<permission>"');
14060
14412
  break;
@@ -14125,7 +14477,7 @@ async function confirmOpenWorld(proj2, environment, interactive2, flag, openMode
14125
14477
  if (!unset.length) return false;
14126
14478
  let answer = flag ? /^(y|yes|true|1)$/i.test(flag.trim()) : null;
14127
14479
  if (answer === null && !interactive2) {
14128
- say(import_chalk30.default.dim(` openWorldHint not answered for ${unset.length} tool${unset.length === 1 ? "" : "s"} (pass --open-world yes|no)`));
14480
+ say(import_chalk32.default.dim(` openWorldHint not answered for ${unset.length} tool${unset.length === 1 ? "" : "s"} (pass --open-world yes|no)`));
14129
14481
  return false;
14130
14482
  }
14131
14483
  if (answer === null) {
@@ -14136,7 +14488,7 @@ async function confirmOpenWorld(proj2, environment, interactive2, flag, openMode
14136
14488
  cat.overrides = { ...cat.overrides ?? {} };
14137
14489
  for (const n of unset) cat.overrides[n] = { ...cat.overrides[n] ?? {}, openWorld: answer };
14138
14490
  await saveCatalogue2(t, cat);
14139
- say(import_chalk30.default.green(` \u2713 openWorldHint ${answer ? "true" : "false"} on ${unset.length === cat.tools.length ? "every tool" : unset.join(", ")}`));
14491
+ say(import_chalk32.default.green(` \u2713 openWorldHint ${answer ? "true" : "false"} on ${unset.length === cat.tools.length ? "every tool" : unset.join(", ")}`));
14140
14492
  return true;
14141
14493
  }
14142
14494
  async function fixToolDescriptions(proj2, environment, interactive2, say) {
@@ -14153,9 +14505,9 @@ async function fixToolDescriptions(proj2, environment, interactive2, say) {
14153
14505
  const dropped = tools.filter(isUtilityTool).map((x) => x.name);
14154
14506
  const todo = kept.filter(needsDescription);
14155
14507
  if (!dropped.length && !todo.length) return false;
14156
- if (dropped.length) say(import_chalk30.default.green(` \u2713 hidden from the MCP (utility endpoints, not tools): ${dropped.join(", ")}`));
14508
+ if (dropped.length) say(import_chalk32.default.green(` \u2713 hidden from the MCP (utility endpoints, not tools): ${dropped.join(", ")}`));
14157
14509
  if (todo.length) {
14158
- say(import_chalk30.default.dim(` ${todo.length} tool${todo.length === 1 ? "" : "s"} need a description (what it does and returns):`));
14510
+ say(import_chalk32.default.dim(` ${todo.length} tool${todo.length === 1 ? "" : "s"} need a description (what it does and returns):`));
14159
14511
  const inquirer3 = interactive2 ? (await import("inquirer")).default : null;
14160
14512
  for (const x of todo) {
14161
14513
  const def = derivedDescription(x);
@@ -14165,7 +14517,7 @@ async function fixToolDescriptions(proj2, environment, interactive2, say) {
14165
14517
  text = value?.trim() || def;
14166
14518
  }
14167
14519
  x.description = text;
14168
- say(import_chalk30.default.green(` \u2713 ${x.name}: ${text}`));
14520
+ say(import_chalk32.default.green(` \u2713 ${x.name}: ${text}`));
14169
14521
  }
14170
14522
  }
14171
14523
  cat.tools = kept;
@@ -14233,13 +14585,13 @@ function printSubmitSteps(r, mdPath, platforms = PLATFORMS, watching = false) {
14233
14585
  const chatgpt = platforms.includes("chatgpt");
14234
14586
  const where = [claude ? "Claude (Settings \u2192 Connectors)" : null, chatgpt ? "ChatGPT (chatgpt.com/plugins \u2192 Add custom MCP server)" : null].filter(Boolean).join(" and in ");
14235
14587
  const steps = [
14236
- `Test it yourself first: add ${import_chalk30.default.cyan(url)} as a custom connector in ${where}, ${open ? "no sign-in needed (open mode)" : "sign in with the reviewer account"}, run a tool.`,
14237
- ...claude ? [`Claude: ${import_chalk30.default.underline(PORTALS.claude)} \u2192 Submit new \u2192 MCP connector. Paste the listing, ${open ? "Authentication: None with the access instructions" : "the reviewer credentials"} and the test steps from ${import_chalk30.default.cyan(import_path7.default.basename(mdPath))}.`] : [],
14238
- ...chatgpt ? [`ChatGPT: ${import_chalk30.default.underline(PORTALS.chatgpt)} \u2192 upload ${import_chalk30.default.cyan(`connector-plugin-${r.report.project.id}.zip`)} \u2192 MCPs \u2192 Connect \u2192 Verify Domain \u2192 authorize \u2192 Scan Tools; paste the reviewer credentials under Review details; add the demo recording URL and the release notes; confirm the attestations. The MCP hostname is permanent for the OpenAI listing.`] : [],
14588
+ `Test it yourself first: add ${import_chalk32.default.cyan(url)} as a custom connector in ${where}, ${open ? "no sign-in needed (open mode)" : "sign in with the reviewer account"}, run a tool.`,
14589
+ ...claude ? [`Claude: ${import_chalk32.default.underline(PORTALS.claude)} \u2192 Submit new \u2192 MCP connector. Paste the listing, ${open ? "Authentication: None with the access instructions" : "the reviewer credentials"} and the test steps from ${import_chalk32.default.cyan(import_path7.default.basename(mdPath))}.`] : [],
14590
+ ...chatgpt ? [`ChatGPT: ${import_chalk32.default.underline(PORTALS.chatgpt)} \u2192 upload ${import_chalk32.default.cyan(`connector-plugin-${r.report.project.id}.zip`)} \u2192 MCPs \u2192 Connect \u2192 Verify Domain \u2192 authorize \u2192 Scan Tools; paste the reviewer credentials under Review details; add the demo recording URL and the release notes; confirm the attestations. The MCP hostname is permanent for the OpenAI listing.`] : [],
14239
14591
  watching ? open ? "A nightly re-check is on: it emails the team owner if the listing drifts or a new check is added." : "Keep the reviewer account alive. A nightly re-check is on: it emails the team owner if the listing drifts or a new check is added." : open ? "The nightly re-check is off (--no-watch); turn it on in the dashboard to be emailed when the listing drifts." : "Keep the reviewer account alive. The nightly re-check is off (--no-watch); turn it on in the dashboard to be emailed when the listing drifts."
14240
14592
  ];
14241
14593
  console.log();
14242
- console.log(import_chalk30.default.bold(" Submit (you do this part; the packet has every value to paste):"));
14594
+ console.log(import_chalk32.default.bold(" Submit (you do this part; the packet has every value to paste):"));
14243
14595
  steps.forEach((s, i) => console.log(` ${i + 1}. ${s}`));
14244
14596
  console.log();
14245
14597
  }
@@ -14252,7 +14604,7 @@ init_connector_docs();
14252
14604
  var import_fs12 = __toESM(require("fs"));
14253
14605
  var import_os4 = __toESM(require("os"));
14254
14606
  var import_path10 = __toESM(require("path"));
14255
- var import_chalk34 = __toESM(require("chalk"));
14607
+ var import_chalk36 = __toESM(require("chalk"));
14256
14608
  init_brand();
14257
14609
 
14258
14610
  // src/lib/brand-surface.ts
@@ -14911,7 +15263,8 @@ function shipMcpMarkdown() {
14911
15263
  8. **List it.** \`${run2} connector <name>\` (Claude; \`--compliant chatgpt\` or \`all\` for OpenAI's directory): the scorecard
14912
15264
  first, then every open step in order \u2014 the MCP hostname (one CNAME the user adds at their DNS provider; relay the exact
14913
15265
  record), the listing answers pre-filled from the spec, the reviewer account, the proof run \u2014 and the submission packet when
14914
- every check passes. Stop any time; \`${run2} connector <name> --status\` says what is left and links the page where the rest
15266
+ every check passes. It needs the hosted app, not a tunnel: have the production URL and any header the backend needs ready, and
15267
+ run the proof again after switching. Stop any time; \`${run2} connector <name> --status\` says what is left and links the page where the rest
14915
15268
  can be finished.
14916
15269
  The user submits the packet to Anthropic or OpenAI themselves.
14917
15270
 
@@ -15244,6 +15597,9 @@ and attestations. \`--compliant\` makes the ${Bb.thingShort} meet them to the le
15244
15597
  - Which directory: \`--compliant\` alone is Claude. \`--compliant chatgpt\` is OpenAI's, \`--compliant all\` is both.
15245
15598
  - From an OpenAPI URL: \`npx ${cli} create --compliant --target https://yourdomain.com/openapi.yaml --domain mcp.yourdomain.com\`.
15246
15599
  On an existing ${Bb.thingShort}: \`npx ${cli} connector <name> --compliant --domain mcp.yourdomain.com\`.
15600
+ - A listing needs the hosted app: \`dev\` is for building and trying it, and a tunnel cannot be submitted. Have the production URL
15601
+ and any header the backend needs ready (\`--target-url\`, \`--upstream-header\`); it asks when they are missing.
15602
+ - A proof run made on a tunnel does not count: run \`npx ${cli} connector exercise <name>\` again after switching to the hosted app.
15247
15603
  - It asks for the listing answers with every field pre-filled from the spec and cut to the portal's limits
15248
15604
  (Enter accepts), and waits for ONE CNAME (mcp.yourdomain.com \u2192 proxy.abz.run) \u2014 the user adds it at their DNS
15249
15605
  provider; relay the exact record it prints. For ChatGPT it also asks for the challenge token the OpenAI portal
@@ -15349,21 +15705,21 @@ async function runForPerson(found) {
15349
15705
  const P = B.product;
15350
15706
  const run2 = `npx ${B.cli}@latest`;
15351
15707
  console.log();
15352
- console.log(` ${import_chalk34.default.bold(pitchText().split(". ")[0] + ".")}`);
15708
+ console.log(` ${import_chalk36.default.bold(pitchText().split(". ")[0] + ".")}`);
15353
15709
  console.log(` ${pitchText().split(". ").slice(1).join(". ")}`);
15354
15710
  console.log();
15355
- console.log(import_chalk34.default.dim(B.cli === "mcpblaze" ? ` With an AI assistant? Tell it: "Help me get my app listed in Claude and ChatGPT using ${run2} skills"` : ` With an AI assistant? Tell it: "Tell me what ${B.cli} can do for me using ${run2} skills"`));
15711
+ console.log(import_chalk36.default.dim(B.cli === "mcpblaze" ? ` With an AI assistant? Tell it: "Help me get my app listed in Claude and ChatGPT using ${run2} skills"` : ` With an AI assistant? Tell it: "Tell me what ${B.cli} can do for me using ${run2} skills"`));
15356
15712
  console.log();
15357
15713
  const report = folderReport(found, { forPerson: true });
15358
15714
  for (const l of report.lines) console.log(` ${l.replace(/`/g, "")}`);
15359
15715
  const port = backendPort(found);
15360
15716
  if (B.cli === "mcpblaze" && report.ownApi && (found.specFile || found.specUrl)) {
15361
15717
  const spec = found.specFile ?? found.specUrl;
15362
- if (!await ask2(` ${import_chalk34.default.bold("?")} Make it a Claude connector now? (${run2} connector ${spec}) ${import_chalk34.default.dim("(Y/n)")} `)) {
15363
- console.log(` Any time: ${import_chalk34.default.cyan(`${run2} connector ${spec}`)}${found.listening ? ` \xB7 or just the MCP server: ${import_chalk34.default.cyan(`${run2} dev --port ${found.listening}`)}` : ""}`);
15718
+ if (!await ask2(` ${import_chalk36.default.bold("?")} Make it a Claude connector now? (${run2} connector ${spec}) ${import_chalk36.default.dim("(Y/n)")} `)) {
15719
+ console.log(` Any time: ${import_chalk36.default.cyan(`${run2} connector ${spec}`)}${found.listening ? ` \xB7 or just the MCP server: ${import_chalk36.default.cyan(`${run2} dev --port ${found.listening}`)}` : ""}`);
15364
15720
  return;
15365
15721
  }
15366
- console.log(import_chalk34.default.dim(` $ ${run2} connector ${spec}`));
15722
+ console.log(import_chalk36.default.dim(` $ ${run2} connector ${spec}`));
15367
15723
  const { spawnSync: spawnSync6 } = await import("child_process");
15368
15724
  const r = spawnSync6(process.execPath, [process.argv[1], "connector", spec], { stdio: "inherit" });
15369
15725
  process.exitCode = r.status ?? 0;
@@ -15371,11 +15727,11 @@ async function runForPerson(found) {
15371
15727
  }
15372
15728
  if (report.ownApi && found.listening) {
15373
15729
  const args = ["dev", "--port", String(found.listening), ...found.specFile ? ["--openapi", found.specFile] : []];
15374
- if (!await ask2(` ${import_chalk34.default.bold("?")} Put your API on port ${found.listening} behind ${P} now? ${import_chalk34.default.dim("(Y/n)")} `)) {
15375
- console.log(` Any time: ${import_chalk34.default.cyan(`${run2} ${args.join(" ")}`)}`);
15730
+ if (!await ask2(` ${import_chalk36.default.bold("?")} Put your API on port ${found.listening} behind ${P} now? ${import_chalk36.default.dim("(Y/n)")} `)) {
15731
+ console.log(` Any time: ${import_chalk36.default.cyan(`${run2} ${args.join(" ")}`)}`);
15376
15732
  return;
15377
15733
  }
15378
- console.log(import_chalk34.default.dim(` $ ${run2} ${args.join(" ")}`));
15734
+ console.log(import_chalk36.default.dim(` $ ${run2} ${args.join(" ")}`));
15379
15735
  const { spawnSync: spawnSync6 } = await import("child_process");
15380
15736
  const r = spawnSync6(process.execPath, [process.argv[1], ...args], { stdio: "inherit" });
15381
15737
  process.exitCode = r.status ?? 0;
@@ -15384,18 +15740,18 @@ async function runForPerson(found) {
15384
15740
  if (report.ownApi) {
15385
15741
  const args = ["dev", "--port", String(port ?? 3e3), ...found.specFile ? ["--openapi", found.specFile] : []];
15386
15742
  const startHint = found.start ? `, once you start it (${found.start})` : ", once it runs";
15387
- if (!await ask2(` ${import_chalk34.default.bold("?")} Put it behind ${P} now? It reaches your app on port ${port ?? 3e3}${startHint}. ${import_chalk34.default.dim("(Y/n)")} `)) {
15388
- console.log(` Any time: ${import_chalk34.default.cyan(`${run2} ${args.join(" ")}`)}`);
15743
+ if (!await ask2(` ${import_chalk36.default.bold("?")} Put it behind ${P} now? It reaches your app on port ${port ?? 3e3}${startHint}. ${import_chalk36.default.dim("(Y/n)")} `)) {
15744
+ console.log(` Any time: ${import_chalk36.default.cyan(`${run2} ${args.join(" ")}`)}`);
15389
15745
  return;
15390
15746
  }
15391
- console.log(import_chalk34.default.dim(` $ ${run2} ${args.join(" ")}`));
15747
+ console.log(import_chalk36.default.dim(` $ ${run2} ${args.join(" ")}`));
15392
15748
  const { spawnSync: spawnSync6 } = await import("child_process");
15393
15749
  const r = spawnSync6(process.execPath, [process.argv[1], ...args], { stdio: "inherit" });
15394
15750
  process.exitCode = r.status ?? 0;
15395
15751
  return;
15396
15752
  }
15397
- if (!await ask2(` ${import_chalk34.default.bold("?")} Create a demo app to try out ${P}? ${import_chalk34.default.dim("(Y/n)")} `)) {
15398
- console.log(` Your own app, when it runs: ${import_chalk34.default.cyan(`${run2} dev --port <port>`)}`);
15753
+ if (!await ask2(` ${import_chalk36.default.bold("?")} Create a demo app to try out ${P}? ${import_chalk36.default.dim("(Y/n)")} `)) {
15754
+ console.log(` Your own app, when it runs: ${import_chalk36.default.cyan(`${run2} dev --port <port>`)}`);
15399
15755
  return;
15400
15756
  }
15401
15757
  const { runDemo: runDemo2 } = await Promise.resolve().then(() => (init_demo(), demo_exports));
@@ -15430,28 +15786,28 @@ function installSkill(opts) {
15430
15786
  const rel = skillRelativePathFor();
15431
15787
  const target2 = import_path10.default.resolve(process.cwd(), rel);
15432
15788
  if (import_fs12.default.existsSync(target2) && !opts.force) {
15433
- console.error(import_chalk34.default.yellow(`${rel} already exists \u2014 re-run with --force to overwrite it.`));
15789
+ console.error(import_chalk36.default.yellow(`${rel} already exists \u2014 re-run with --force to overwrite it.`));
15434
15790
  process.exit(1);
15435
15791
  }
15436
15792
  import_fs12.default.mkdirSync(import_path10.default.dirname(target2), { recursive: true });
15437
15793
  import_fs12.default.writeFileSync(target2, md, "utf8");
15438
- console.log(`${import_chalk34.default.green("\u2713")} Installed the ${import_chalk34.default.bold(skillNameFor())} skill: ${import_chalk34.default.bold(target2)}`);
15439
- console.log(import_chalk34.default.dim(B.cli === "mcpblaze" ? ` Claude Code picks it up in this project. Say "make this an MCP server" or "list it in Claude" and it runs npx ${B.cli}@latest create / connector for you.` : ` Claude Code picks it up in this project. Say "ship this API" and it runs npx ${B.cli}@latest dev / create for you.`));
15794
+ console.log(`${import_chalk36.default.green("\u2713")} Installed the ${import_chalk36.default.bold(skillNameFor())} skill: ${import_chalk36.default.bold(target2)}`);
15795
+ console.log(import_chalk36.default.dim(B.cli === "mcpblaze" ? ` Claude Code picks it up in this project. Say "make this an MCP server" or "list it in Claude" and it runs npx ${B.cli}@latest create / connector for you.` : ` Claude Code picks it up in this project. Say "ship this API" and it runs npx ${B.cli}@latest dev / create for you.`));
15440
15796
  }
15441
15797
 
15442
15798
  // src/commands/integration.ts
15443
- var import_chalk35 = __toESM(require("chalk"));
15444
- var import_ora12 = __toESM(require("ora"));
15799
+ var import_chalk37 = __toESM(require("chalk"));
15800
+ var import_ora14 = __toESM(require("ora"));
15445
15801
  init_caller();
15446
15802
  init_api();
15447
15803
  init_brand();
15448
15804
  function file(f2, indent2 = " ") {
15449
- console.log(` ${import_chalk35.default.cyan(f2.file)}`);
15805
+ console.log(` ${import_chalk37.default.cyan(f2.file)}`);
15450
15806
  for (const line of f2.code.split("\n")) console.log(`${indent2}${line}`);
15451
15807
  console.log();
15452
15808
  }
15453
15809
  function bullets(lines, indent2 = " ") {
15454
- for (const l of lines) console.log(`${indent2}${import_chalk35.default.dim("\u2022")} ${l}`);
15810
+ for (const l of lines) console.log(`${indent2}${import_chalk37.default.dim("\u2022")} ${l}`);
15455
15811
  }
15456
15812
  async function runIntegration(name, opts = {}) {
15457
15813
  const stackRaw = (opts.stack ?? "nextjs").trim().toLowerCase();
@@ -15462,7 +15818,7 @@ async function runIntegration(name, opts = {}) {
15462
15818
  const project = name.trim().toLowerCase();
15463
15819
  const caller = requireCaller();
15464
15820
  if (opts.team && caller.mode === "anon") throw new Error("--team is not available in an anonymous workspace.");
15465
- const spinner = opts.json ? null : (0, import_ora12.default)(`Rendering the ${stack} kit for ${project}\u2026`).start();
15821
+ const spinner = opts.json ? null : (0, import_ora14.default)(`Rendering the ${stack} kit for ${project}\u2026`).start();
15466
15822
  let kit;
15467
15823
  try {
15468
15824
  kit = await producer(caller, integrationKitCall(project, stack));
@@ -15476,44 +15832,44 @@ async function runIntegration(name, opts = {}) {
15476
15832
  return;
15477
15833
  }
15478
15834
  console.log();
15479
- console.log(import_chalk35.default.bold(`Integration kit \u2014 ${kit.project} (${kit.stack})`));
15480
- console.log(import_chalk35.default.dim(` Edit only the frontend and the frontend-server. Your backend changes in one way: it trusts the ${B.product} identity headers.`));
15835
+ console.log(import_chalk37.default.bold(`Integration kit \u2014 ${kit.project} (${kit.stack})`));
15836
+ console.log(import_chalk37.default.dim(` Edit only the frontend and the frontend-server. Your backend changes in one way: it trusts the ${B.product} identity headers.`));
15481
15837
  console.log();
15482
- console.log(` ${import_chalk35.default.dim("Proxy: ")} ${import_chalk35.default.bold(kit.urls.proxy)}`);
15483
- console.log(` ${import_chalk35.default.dim("MCP: ")} ${kit.urls.mcp.join(import_chalk35.default.dim(" \xB7 "))}`);
15484
- console.log(` ${import_chalk35.default.dim("Portal: ")} ${kit.urls.portal}`);
15485
- console.log(` ${import_chalk35.default.dim("Spec: ")} ${kit.urls.openapi}`);
15838
+ console.log(` ${import_chalk37.default.dim("Proxy: ")} ${import_chalk37.default.bold(kit.urls.proxy)}`);
15839
+ console.log(` ${import_chalk37.default.dim("MCP: ")} ${kit.urls.mcp.join(import_chalk37.default.dim(" \xB7 "))}`);
15840
+ console.log(` ${import_chalk37.default.dim("Portal: ")} ${kit.urls.portal}`);
15841
+ console.log(` ${import_chalk37.default.dim("Spec: ")} ${kit.urls.openapi}`);
15486
15842
  const w = kit["1_frontend_widgets"];
15487
15843
  console.log();
15488
- console.log(import_chalk35.default.bold("1. Frontend \u2014 the widgets (keys + chat)"));
15489
- console.log(import_chalk35.default.dim(` ${w.note}`));
15844
+ console.log(import_chalk37.default.bold("1. Frontend \u2014 the widgets (keys + chat)"));
15845
+ console.log(import_chalk37.default.dim(` ${w.note}`));
15490
15846
  console.log();
15491
15847
  file(w.frontend);
15492
15848
  for (const r of w.server_routes) file(r);
15493
15849
  const c = kit["2_frontend_server_call_through"];
15494
- console.log(import_chalk35.default.bold("2. Frontend-server \u2014 call the proxy with the server key and say who is calling"));
15850
+ console.log(import_chalk37.default.bold("2. Frontend-server \u2014 call the proxy with the server key and say who is calling"));
15495
15851
  console.log();
15496
15852
  file(c);
15497
15853
  const t = kit["3_backend_trust_contract"];
15498
- console.log(import_chalk35.default.bold("3. Backend \u2014 trust the identity headers, and nothing else"));
15499
- for (const [h, why] of Object.entries(t.headers_you_receive)) console.log(` ${import_chalk35.default.cyan(h)} \u2014 ${why}`);
15854
+ console.log(import_chalk37.default.bold("3. Backend \u2014 trust the identity headers, and nothing else"));
15855
+ for (const [h, why] of Object.entries(t.headers_you_receive)) console.log(` ${import_chalk37.default.cyan(h)} \u2014 ${why}`);
15500
15856
  console.log();
15501
- console.log(` ${import_chalk35.default.dim("How to verify:")}`);
15857
+ console.log(` ${import_chalk37.default.dim("How to verify:")}`);
15502
15858
  bullets(t.how_to_verify);
15503
15859
  console.log();
15504
- console.log(` ${import_chalk35.default.dim("Never:")}`);
15860
+ console.log(` ${import_chalk37.default.dim("Never:")}`);
15505
15861
  bullets(t.what_not_to_do);
15506
15862
  console.log();
15507
- console.log(import_chalk35.default.bold("4. Env vars (server only)"));
15508
- for (const [k, v] of Object.entries(kit["4_env_vars"])) console.log(` ${import_chalk35.default.cyan(k)} ${import_chalk35.default.dim("=")} ${v}`);
15863
+ console.log(import_chalk37.default.bold("4. Env vars (server only)"));
15864
+ for (const [k, v] of Object.entries(kit["4_env_vars"])) console.log(` ${import_chalk37.default.cyan(k)} ${import_chalk37.default.dim("=")} ${v}`);
15509
15865
  const o = kit["5_what_stays_open"];
15510
15866
  console.log();
15511
- console.log(import_chalk35.default.bold("5. What stays open"));
15512
- console.log(` ${import_chalk35.default.dim("Protected by a rule:")} ${o.protected.length ? o.protected.join(", ") : import_chalk35.default.dim("nothing")}`);
15513
- console.log(` ${import_chalk35.default.dim("Open to any identified caller:")} ${o.open.length ? o.open.join(", ") : import_chalk35.default.dim("nothing")}`);
15514
- console.log(import_chalk35.default.dim(` ${o.note}`));
15867
+ console.log(import_chalk37.default.bold("5. What stays open"));
15868
+ console.log(` ${import_chalk37.default.dim("Protected by a rule:")} ${o.protected.length ? o.protected.join(", ") : import_chalk37.default.dim("nothing")}`);
15869
+ console.log(` ${import_chalk37.default.dim("Open to any identified caller:")} ${o.open.length ? o.open.join(", ") : import_chalk37.default.dim("nothing")}`);
15870
+ console.log(import_chalk37.default.dim(` ${o.note}`));
15515
15871
  console.log();
15516
- console.log(import_chalk35.default.dim(` Raw JSON: npx ${B.cli} integration ${kit.project} --stack ${kit.stack} --json`));
15872
+ console.log(import_chalk37.default.dim(` Raw JSON: npx ${B.cli} integration ${kit.project} --stack ${kit.stack} --json`));
15517
15873
  console.log();
15518
15874
  }
15519
15875
 
@@ -15521,14 +15877,14 @@ async function runIntegration(name, opts = {}) {
15521
15877
  init_claim();
15522
15878
 
15523
15879
  // src/commands/logout.ts
15524
- var import_chalk36 = __toESM(require("chalk"));
15880
+ var import_chalk38 = __toESM(require("chalk"));
15525
15881
  init_auth();
15526
15882
  init_consumer_auth();
15527
15883
  async function runLogout(opts = {}) {
15528
15884
  const creds = loadCredentials();
15529
15885
  const consumer = loadConsumer();
15530
15886
  if (!creds && !consumer) {
15531
- console.log(import_chalk36.default.yellow("You were not logged in."));
15887
+ console.log(import_chalk38.default.yellow("You were not logged in."));
15532
15888
  return;
15533
15889
  }
15534
15890
  let target2;
@@ -15555,16 +15911,16 @@ async function runLogout(opts = {}) {
15555
15911
  }
15556
15912
  if (target2 === "producer" || target2 === "all") {
15557
15913
  clearCredentials();
15558
- console.log(import_chalk36.default.green(`\u2714 Logged out of API Producer${creds?.githubHandle ? ` (${creds.githubHandle})` : ""}.`));
15914
+ console.log(import_chalk38.default.green(`\u2714 Logged out of API Producer${creds?.githubHandle ? ` (${creds.githubHandle})` : ""}.`));
15559
15915
  }
15560
15916
  if (target2 === "consumer" || target2 === "all") {
15561
15917
  clearConsumer();
15562
- console.log(import_chalk36.default.green(`\u2714 Logged out of API Consumer${consumer?.tenant ? ` (${consumer.tenant})` : ""}.`));
15918
+ console.log(import_chalk38.default.green(`\u2714 Logged out of API Consumer${consumer?.tenant ? ` (${consumer.tenant})` : ""}.`));
15563
15919
  }
15564
15920
  }
15565
15921
 
15566
15922
  // src/commands/flush.ts
15567
- var import_chalk37 = __toESM(require("chalk"));
15923
+ var import_chalk39 = __toESM(require("chalk"));
15568
15924
  var fs21 = __toESM(require("fs"));
15569
15925
  var path17 = __toESM(require("path"));
15570
15926
  init_auth();
@@ -15572,18 +15928,18 @@ init_external_mcp();
15572
15928
  async function runFlush(opts) {
15573
15929
  const { stopDemos: stopDemos2 } = await Promise.resolve().then(() => (init_demo(), demo_exports));
15574
15930
  const demos = await stopDemos2().catch(() => 0);
15575
- if (demos) console.log(import_chalk37.default.dim(` Stopped ${demos} running demo(s).`));
15931
+ if (demos) console.log(import_chalk39.default.dim(` Stopped ${demos} running demo(s).`));
15576
15932
  const dir = getApiblazeDir();
15577
15933
  const entries2 = fs21.existsSync(dir) ? fs21.readdirSync(dir) : [];
15578
15934
  if (!entries2.length) {
15579
- console.log(import_chalk37.default.dim("Nothing to flush \u2014 no local apiblaze config found."));
15935
+ console.log(import_chalk39.default.dim("Nothing to flush \u2014 no local apiblaze config found."));
15580
15936
  return;
15581
15937
  }
15582
- console.log(import_chalk37.default.yellow("This removes ALL local apiblaze state from this machine:"));
15583
- console.log(import_chalk37.default.dim(" \u2022 login credentials & anonymous-workspace keys"));
15584
- console.log(import_chalk37.default.dim(" \u2022 saved apichats \u2014 their DP API keys and transcripts"));
15585
- console.log(import_chalk37.default.dim(" \u2022 your BYO LLM key and any cached secrets"));
15586
- console.log(import_chalk37.default.dim(` (${entries2.length} item(s) in ${dir})`));
15938
+ console.log(import_chalk39.default.yellow("This removes ALL local apiblaze state from this machine:"));
15939
+ console.log(import_chalk39.default.dim(" \u2022 login credentials & anonymous-workspace keys"));
15940
+ console.log(import_chalk39.default.dim(" \u2022 saved apichats \u2014 their DP API keys and transcripts"));
15941
+ console.log(import_chalk39.default.dim(" \u2022 your BYO LLM key and any cached secrets"));
15942
+ console.log(import_chalk39.default.dim(` (${entries2.length} item(s) in ${dir})`));
15587
15943
  const footprint = apiblazeMcpFootprint();
15588
15944
  const mdFiles = ["claude", "codex"].map((k) => ({ k, file: agentInstructionFile(k) })).filter(({ file: file2 }) => {
15589
15945
  try {
@@ -15593,19 +15949,19 @@ async function runFlush(opts) {
15593
15949
  }
15594
15950
  });
15595
15951
  if (footprint.claude.length || footprint.codex.length) {
15596
- console.log(import_chalk37.default.dim(` \u2022 MCP servers installed in other tools: ${[...footprint.claude, ...footprint.codex].join(", ")}`));
15952
+ console.log(import_chalk39.default.dim(` \u2022 MCP servers installed in other tools: ${[...footprint.claude, ...footprint.codex].join(", ")}`));
15597
15953
  }
15598
15954
  if (mdFiles.length) {
15599
- console.log(import_chalk37.default.dim(` \u2022 the "use this MCP" blocks in ${mdFiles.map((m) => path17.basename(m.file)).join(" and ")} (here)`));
15955
+ console.log(import_chalk39.default.dim(` \u2022 the "use this MCP" blocks in ${mdFiles.map((m) => path17.basename(m.file)).join(" and ")} (here)`));
15600
15956
  }
15601
- console.log(import_chalk37.default.dim(" It does NOT delete server-side proxies/keys \u2014 those GC or are revoked separately."));
15957
+ console.log(import_chalk39.default.dim(" It does NOT delete server-side proxies/keys \u2014 those GC or are revoked separately."));
15602
15958
  if (!opts.yes) {
15603
15959
  const { default: inquirer3 } = await import("inquirer");
15604
15960
  const { ok } = await inquirer3.prompt([
15605
15961
  { type: "confirm", name: "ok", message: "Delete all local state?", default: false }
15606
15962
  ]);
15607
15963
  if (!ok) {
15608
- console.log(import_chalk37.default.dim("Cancelled \u2014 nothing removed."));
15964
+ console.log(import_chalk39.default.dim("Cancelled \u2014 nothing removed."));
15609
15965
  return;
15610
15966
  }
15611
15967
  }
@@ -15615,14 +15971,14 @@ async function runFlush(opts) {
15615
15971
  fs21.rmSync(path17.join(dir, e), { recursive: true, force: true });
15616
15972
  removed++;
15617
15973
  } catch (err) {
15618
- console.log(import_chalk37.default.red(` \u2717 could not remove ${e}: ${err instanceof Error ? err.message : "error"}`));
15974
+ console.log(import_chalk39.default.red(` \u2717 could not remove ${e}: ${err instanceof Error ? err.message : "error"}`));
15619
15975
  }
15620
15976
  }
15621
15977
  for (const name of footprint.claude) {
15622
- console.log(removeClaudeServer(name) ? ` ${import_chalk37.default.dim("\u2022")} removed MCP ${import_chalk37.default.bold(name)} from Claude CLI` : import_chalk37.default.yellow(` \u2717 could not remove MCP ${name} from Claude CLI`));
15978
+ console.log(removeClaudeServer(name) ? ` ${import_chalk39.default.dim("\u2022")} removed MCP ${import_chalk39.default.bold(name)} from Claude CLI` : import_chalk39.default.yellow(` \u2717 could not remove MCP ${name} from Claude CLI`));
15623
15979
  }
15624
15980
  for (const name of footprint.codex) {
15625
- console.log(removeCodexServer(name) ? ` ${import_chalk37.default.dim("\u2022")} removed MCP ${import_chalk37.default.bold(name)} from Codex` : import_chalk37.default.yellow(` \u2717 could not remove MCP ${name} from Codex`));
15981
+ console.log(removeCodexServer(name) ? ` ${import_chalk39.default.dim("\u2022")} removed MCP ${import_chalk39.default.bold(name)} from Codex` : import_chalk39.default.yellow(` \u2717 could not remove MCP ${name} from Codex`));
15626
15982
  }
15627
15983
  for (const { k, file: file2 } of mdFiles) {
15628
15984
  let text = "";
@@ -15634,17 +15990,17 @@ async function runFlush(opts) {
15634
15990
  const names = [...text.matchAll(/<!-- apiblaze:mcp:([^\s>]+) -->/g)].map((m) => m[1]);
15635
15991
  let cleared = 0;
15636
15992
  for (const n of new Set(names)) if (removeAgentInstruction(k, n)) cleared++;
15637
- if (cleared) console.log(` ${import_chalk37.default.dim("\u2022")} removed ${cleared} APIblaze block(s) from ${import_chalk37.default.bold(path17.basename(file2))}`);
15993
+ if (cleared) console.log(` ${import_chalk39.default.dim("\u2022")} removed ${cleared} APIblaze block(s) from ${import_chalk39.default.bold(path17.basename(file2))}`);
15638
15994
  }
15639
- console.log(`${import_chalk37.default.green("\u2714")} Flushed \u2014 removed ${removed} item(s). You're fully logged out and clean.`);
15640
- console.log(import_chalk37.default.dim(" Next `apiblaze create` starts a brand-new workspace with nothing carried over."));
15995
+ console.log(`${import_chalk39.default.green("\u2714")} Flushed \u2014 removed ${removed} item(s). You're fully logged out and clean.`);
15996
+ console.log(import_chalk39.default.dim(" Next `apiblaze create` starts a brand-new workspace with nothing carried over."));
15641
15997
  }
15642
15998
 
15643
15999
  // src/cli.ts
15644
16000
  init_demo();
15645
16001
 
15646
16002
  // src/commands/whoami.ts
15647
- var import_chalk38 = __toESM(require("chalk"));
16003
+ var import_chalk40 = __toESM(require("chalk"));
15648
16004
  init_auth();
15649
16005
  init_consumer_auth();
15650
16006
  init_anon_cred();
@@ -15668,54 +16024,54 @@ async function runWhoami(opts = {}) {
15668
16024
  }, null, 2));
15669
16025
  return;
15670
16026
  }
15671
- console.log(import_chalk38.default.bold("API Producer"));
16027
+ console.log(import_chalk40.default.bold("API Producer"));
15672
16028
  if (!creds) {
15673
- console.log(import_chalk38.default.dim(" Not logged in. Run `apiblaze login`."));
16029
+ console.log(import_chalk40.default.dim(" Not logged in. Run `apiblaze login`."));
15674
16030
  } else {
15675
16031
  const who = creds.githubHandle ?? creds.email ?? creds.apiblazeUserId ?? "unknown";
15676
- console.log(` ${import_chalk38.default.cyan("Signed in as")} ${import_chalk38.default.bold(who)}`);
16032
+ console.log(` ${import_chalk40.default.cyan("Signed in as")} ${import_chalk40.default.bold(who)}`);
15677
16033
  if (creds.email && creds.email !== who) console.log(` Email: ${creds.email}`);
15678
- if (creds.teamName || creds.teamId) console.log(` Team: ${import_chalk38.default.bold(creds.teamName ?? creds.teamId)}`);
15679
- if (creds.activeTenant) console.log(` Tenant scope: ${import_chalk38.default.bold(creds.activeTenant)} ${import_chalk38.default.dim("(clear: `apiblaze tenant use --clear`)")}`);
15680
- if (Date.now() >= creds.expiresAt) console.log(import_chalk38.default.yellow(" \u26A0 Session expired \u2014 run `apiblaze login`."));
16034
+ if (creds.teamName || creds.teamId) console.log(` Team: ${import_chalk40.default.bold(creds.teamName ?? creds.teamId)}`);
16035
+ if (creds.activeTenant) console.log(` Tenant scope: ${import_chalk40.default.bold(creds.activeTenant)} ${import_chalk40.default.dim("(clear: `apiblaze tenant use --clear`)")}`);
16036
+ if (Date.now() >= creds.expiresAt) console.log(import_chalk40.default.yellow(" \u26A0 Session expired \u2014 run `apiblaze login`."));
15681
16037
  }
15682
16038
  if (anon) {
15683
16039
  const masked = `${anon.cp_key.slice(0, 11)}\u2026${anon.cp_key.slice(-4)}`;
15684
- console.log(import_chalk38.default.bold("\nAnonymous workspace") + import_chalk38.default.dim(" (created without an account \u2014 unclaimed)"));
15685
- console.log(` Team: ${import_chalk38.default.bold(anon.team_id)}`);
15686
- console.log(` CP key: ${import_chalk38.default.bold(masked)} ${import_chalk38.default.dim("controls the proxies you created anonymously")}`);
16040
+ console.log(import_chalk40.default.bold("\nAnonymous workspace") + import_chalk40.default.dim(" (created without an account \u2014 unclaimed)"));
16041
+ console.log(` Team: ${import_chalk40.default.bold(anon.team_id)}`);
16042
+ console.log(` CP key: ${import_chalk40.default.bold(masked)} ${import_chalk40.default.dim("controls the proxies you created anonymously")}`);
15687
16043
  console.log(
15688
- import_chalk38.default.dim(` Keep it: ${import_chalk38.default.cyan("apiblaze login")} then ${import_chalk38.default.cyan("apiblaze claim")}`) + (anon.claim_code ? import_chalk38.default.dim(` \xB7 from another machine: ${import_chalk38.default.cyan(`apiblaze claim ${anon.claim_code}`)}`) : "")
16044
+ import_chalk40.default.dim(` Keep it: ${import_chalk40.default.cyan("apiblaze login")} then ${import_chalk40.default.cyan("apiblaze claim")}`) + (anon.claim_code ? import_chalk40.default.dim(` \xB7 from another machine: ${import_chalk40.default.cyan(`apiblaze claim ${anon.claim_code}`)}`) : "")
15689
16045
  );
15690
- if (creds) console.log(import_chalk38.default.dim(" (you're logged in \u2014 `apiblaze claim` folds this workspace into your account)"));
16046
+ if (creds) console.log(import_chalk40.default.dim(" (you're logged in \u2014 `apiblaze claim` folds this workspace into your account)"));
15691
16047
  }
15692
- console.log(import_chalk38.default.bold("\nAPI Consumer"));
16048
+ console.log(import_chalk40.default.bold("\nAPI Consumer"));
15693
16049
  if (!consumer) {
15694
- console.log(import_chalk38.default.dim(" Not logged in. Run `apiblaze consumer login`."));
16050
+ console.log(import_chalk40.default.dim(" Not logged in. Run `apiblaze consumer login`."));
15695
16051
  } else {
15696
- console.log(` ${import_chalk38.default.cyan("Signed in as")} ${import_chalk38.default.bold(consumer.email ?? consumer.tenant)}`);
15697
- console.log(` Tenant: ${import_chalk38.default.bold(consumer.tenant)}`);
15698
- if (Date.now() >= consumer.expiresAt) console.log(import_chalk38.default.yellow(" \u26A0 Token expired \u2014 it will refresh on next use, or re-run `apiblaze consumer login`."));
16052
+ console.log(` ${import_chalk40.default.cyan("Signed in as")} ${import_chalk40.default.bold(consumer.email ?? consumer.tenant)}`);
16053
+ console.log(` Tenant: ${import_chalk40.default.bold(consumer.tenant)}`);
16054
+ if (Date.now() >= consumer.expiresAt) console.log(import_chalk40.default.yellow(" \u26A0 Token expired \u2014 it will refresh on next use, or re-run `apiblaze consumer login`."));
15699
16055
  }
15700
16056
  }
15701
16057
 
15702
16058
  // src/commands/team.ts
15703
- var import_chalk39 = __toESM(require("chalk"));
15704
- var import_ora13 = __toESM(require("ora"));
16059
+ var import_chalk41 = __toESM(require("chalk"));
16060
+ var import_ora15 = __toESM(require("ora"));
15705
16061
  init_auth();
15706
16062
  init_api();
15707
16063
  init_admin();
15708
16064
  function fail5(message, hint) {
15709
- console.error(import_chalk39.default.red(`Error: ${message}`));
15710
- if (hint) console.error(import_chalk39.default.dim(hint));
16065
+ console.error(import_chalk41.default.red(`Error: ${message}`));
16066
+ if (hint) console.error(import_chalk41.default.dim(hint));
15711
16067
  process.exit(1);
15712
16068
  }
15713
16069
  function activate(creds, team) {
15714
16070
  const next = { ...creds, teamId: team.teamId, teamName: team.name };
15715
16071
  if (creds.teamId !== team.teamId) delete next.activeTenant;
15716
16072
  saveCredentials(next);
15717
- console.log(import_chalk39.default.green(`
15718
- \u2714 Active team: ${import_chalk39.default.bold(team.name)}`));
16073
+ console.log(import_chalk41.default.green(`
16074
+ \u2714 Active team: ${import_chalk41.default.bold(team.name)}`));
15719
16075
  }
15720
16076
  async function promptName(message) {
15721
16077
  const { default: inquirer3 } = await import("inquirer");
@@ -15723,14 +16079,14 @@ async function promptName(message) {
15723
16079
  const { name } = await inquirer3.prompt([{ type: "input", name: "name", message }]);
15724
16080
  const trimmed = (name ?? "").trim();
15725
16081
  if (trimmed.length >= 2) return trimmed;
15726
- console.log(import_chalk39.default.yellow(" Team name must be at least 2 characters.\n"));
16082
+ console.log(import_chalk41.default.yellow(" Team name must be at least 2 characters.\n"));
15727
16083
  }
15728
16084
  }
15729
16085
  async function createAndActivate(creds, name) {
15730
16086
  if (!creds.apiblazeUserId) {
15731
16087
  fail5("Your login is missing its user id.", "Run `apiblaze login` again, then retry.");
15732
16088
  }
15733
- const spinner = (0, import_ora13.default)(`Creating team "${name}"...`).start();
16089
+ const spinner = (0, import_ora15.default)(`Creating team "${name}"...`).start();
15734
16090
  let created;
15735
16091
  try {
15736
16092
  created = await admin({
@@ -15745,7 +16101,7 @@ async function createAndActivate(creds, name) {
15745
16101
  }
15746
16102
  spinner.stop();
15747
16103
  if (!created?.team_id) fail5("The server created no team id.");
15748
- console.log(`${import_chalk39.default.green("\u2714")} Team created: ${import_chalk39.default.bold(created.name ?? name)} ${import_chalk39.default.dim(`(${created.team_id})`)}`);
16104
+ console.log(`${import_chalk41.default.green("\u2714")} Team created: ${import_chalk41.default.bold(created.name ?? name)} ${import_chalk41.default.dim(`(${created.team_id})`)}`);
15749
16105
  activate(creds, { teamId: created.team_id, name: created.name ?? name });
15750
16106
  }
15751
16107
  async function runTeam(arg, opts = {}) {
@@ -15802,11 +16158,11 @@ async function runTeam(arg, opts = {}) {
15802
16158
  default: creds.teamId,
15803
16159
  choices: [
15804
16160
  ...teams.map((t) => ({
15805
- name: t.teamId === creds.teamId ? `${t.name} ${import_chalk39.default.dim("(current)")}` : t.name,
16161
+ name: t.teamId === creds.teamId ? `${t.name} ${import_chalk41.default.dim("(current)")}` : t.name,
15806
16162
  value: t.teamId
15807
16163
  })),
15808
16164
  new inquirer3.Separator(),
15809
- { name: import_chalk39.default.green("\uFF0B Create a new team"), value: CREATE }
16165
+ { name: import_chalk41.default.green("\uFF0B Create a new team"), value: CREATE }
15810
16166
  ]
15811
16167
  }]);
15812
16168
  if (picked === CREATE) {
@@ -15821,7 +16177,7 @@ async function runTeam(arg, opts = {}) {
15821
16177
  init_allow_oauth_registration();
15822
16178
 
15823
16179
  // src/commands/docs.ts
15824
- var import_chalk40 = __toESM(require("chalk"));
16180
+ var import_chalk42 = __toESM(require("chalk"));
15825
16181
  init_apichat();
15826
16182
  init_brand();
15827
16183
  var MCPBLAZE_DOCS_NOTE = 'The user is on MCPblaze: say "MCP server", never "proxy". The front door is create_mcp_server (an MCP server from an OpenAPI spec; it returns the connector URL and the scorecard page), get_readiness (where a listing stands and what is next) and, in the terminal, `npx mcpblaze connector <name>`. The details \u2014 the custom hostname, the listing fields, attestations, the reviewer account, the packet \u2014 are finished on the scorecard page, not here. Passing the checks means the MCP meets the requirements we can verify; the user submits, the directories decide.';
@@ -15834,32 +16190,32 @@ async function runDocsWeb() {
15834
16190
  const { openRegistrationAuthorization: openRegistrationAuthorization2 } = await Promise.resolve().then(() => (init_allow_oauth_registration(), allow_oauth_registration_exports));
15835
16191
  const creds = loadCredentials2();
15836
16192
  if (!creds?.teamId) {
15837
- console.error(import_chalk40.default.red("Error: Connecting a web chatbot needs an account."));
15838
- console.error(import_chalk40.default.dim("Run `apiblaze login` first (free)."));
16193
+ console.error(import_chalk42.default.red("Error: Connecting a web chatbot needs an account."));
16194
+ console.error(import_chalk42.default.dim("Run `apiblaze login` first (free)."));
15839
16195
  process.exit(1);
15840
16196
  }
15841
16197
  const tenant = opTenantForTeam3(creds.teamId);
15842
16198
  const url = B.cli === "mcpblaze" ? `https://externalauth-${tenant}.mcpblaze.com/1.0.0/prod` : `https://externalauth-${tenant}.mcp.apiblaze.com/1.0.0/prod`;
15843
- console.log(import_chalk40.default.bold(`
16199
+ console.log(import_chalk42.default.bold(`
15844
16200
  Your personal ${B.product} MCP URL \u2014 paste it into claude.ai or ChatGPT:
15845
16201
  `));
15846
- console.log(" " + import_chalk40.default.bgCyan.black.bold(` ${url} `));
15847
- console.log(import_chalk40.default.dim(`
16202
+ console.log(" " + import_chalk42.default.bgCyan.black.bold(` ${url} `));
16203
+ console.log(import_chalk42.default.dim(`
15848
16204
  It is scoped to your team (${creds.teamName ?? creds.teamId}) \u2014 nobody else's account is reachable through it.`));
15849
16205
  const ok = await openRegistrationAuthorization2(creds.teamId, tenant, 900);
15850
16206
  console.log(ok ? `
15851
- ${import_chalk40.default.green("\u2714")} Connection pre-authorized (single use, 15 min) \u2014 connect now and it won't ask you to approve the app.` : import_chalk40.default.yellow(`
16207
+ ${import_chalk42.default.green("\u2714")} Connection pre-authorized (single use, 15 min) \u2014 connect now and it won't ask you to approve the app.` : import_chalk42.default.yellow(`
15852
16208
  Could not pre-authorize the connection. If the sign-in says the app needs verifying, run:
15853
16209
  ${B.cli} allowoauthregistration ${B.cli === "mcpblaze" ? "--control-plane" : "--apiblaze"}`));
15854
- console.log(import_chalk40.default.dim("\n Re-run this command any time to authorize another client."));
16210
+ console.log(import_chalk42.default.dim("\n Re-run this command any time to authorize another client."));
15855
16211
  }
15856
16212
  async function runDocs(opts) {
15857
16213
  console.log("");
15858
- console.log(import_chalk40.default.bgYellow.black.bold(" This is not a docs search \u2014 the chatbot can CHANGE your account. "));
15859
- console.log(import_chalk40.default.yellow(` It connects ${import_chalk40.default.bold("Claude Code")} or ${import_chalk40.default.bold("Codex")} to the real ${B.product} ${B.cli === "mcpblaze" ? "MCP server" : "API"}, acting as you:`));
15860
- console.log(import_chalk40.default.yellow(B.cli === "mcpblaze" ? " it can create MCP servers, change their settings and delete them for real." : " it can create proxies, add logins, invite teammates and point domains for real."));
15861
- console.log(import_chalk40.default.yellow(" Destructive actions (deleting proxies, teams or products) are deliberately not exposed."));
15862
- console.log(import_chalk40.default.dim(' Read-only questions ("what proxies do I have?") are of course fine.'));
16214
+ console.log(import_chalk42.default.bgYellow.black.bold(" This is not a docs search \u2014 the chatbot can CHANGE your account. "));
16215
+ console.log(import_chalk42.default.yellow(` It connects ${import_chalk42.default.bold("Claude Code")} or ${import_chalk42.default.bold("Codex")} to the real ${B.product} ${B.cli === "mcpblaze" ? "MCP server" : "API"}, acting as you:`));
16216
+ console.log(import_chalk42.default.yellow(B.cli === "mcpblaze" ? " it can create MCP servers, change their settings and delete them for real." : " it can create proxies, add logins, invite teammates and point domains for real."));
16217
+ console.log(import_chalk42.default.yellow(" Destructive actions (deleting proxies, teams or products) are deliberately not exposed."));
16218
+ console.log(import_chalk42.default.dim(' Read-only questions ("what proxies do I have?") are of course fine.'));
15863
16219
  console.log("");
15864
16220
  if (!opts.yes && !opts.prompt && process.stdin.isTTY) {
15865
16221
  const { default: inquirer3 } = await import("inquirer");
@@ -15870,7 +16226,7 @@ async function runDocs(opts) {
15870
16226
  message: "Continue, knowing the chatbot can act on your account?"
15871
16227
  }]);
15872
16228
  if (!ok) {
15873
- console.log(import_chalk40.default.dim(`
16229
+ console.log(import_chalk42.default.dim(`
15874
16230
  Nothing connected. The written docs are at ${B.cli === "mcpblaze" ? "https://mcpblaze.com" : "https://www.apiblaze.com/docs"}`));
15875
16231
  return;
15876
16232
  }
@@ -15893,13 +16249,13 @@ async function runDocs(opts) {
15893
16249
  }
15894
16250
 
15895
16251
  // src/commands/authz.ts
15896
- var import_chalk42 = __toESM(require("chalk"));
16252
+ var import_chalk44 = __toESM(require("chalk"));
15897
16253
  init_auth();
15898
16254
  init_api();
15899
16255
  init_agent_chat();
15900
16256
 
15901
16257
  // src/lib/authz-apply.ts
15902
- var import_chalk41 = __toESM(require("chalk"));
16258
+ var import_chalk43 = __toESM(require("chalk"));
15903
16259
  init_api();
15904
16260
  async function gatherSampleIds(projectId, apiVersion, cap2 = 50) {
15905
16261
  try {
@@ -15924,10 +16280,10 @@ async function gatherSampleIds(projectId, apiVersion, cap2 = 50) {
15924
16280
  }
15925
16281
  function maybeWarnNoTraffic(total, projectArg) {
15926
16282
  if (total >= 3) return;
15927
- console.log(import_chalk41.default.yellow(total === 0 ? " \u26A0 No captured traffic for this API yet." : ` \u26A0 Only ${total} captured request(s) so far.`));
15928
- console.log(import_chalk41.default.dim(" The authorization agent designs much better models & rules from REAL requests"));
15929
- console.log(import_chalk41.default.dim(" (it sees who is allowed vs denied). Send some through your proxy first \u2014"));
15930
- console.log(import_chalk41.default.dim(` curl a few endpoints, or `) + import_chalk41.default.cyan("npx apiblaze dev") + import_chalk41.default.dim(` \u2014 then re-run.
16283
+ console.log(import_chalk43.default.yellow(total === 0 ? " \u26A0 No captured traffic for this API yet." : ` \u26A0 Only ${total} captured request(s) so far.`));
16284
+ console.log(import_chalk43.default.dim(" The authorization agent designs much better models & rules from REAL requests"));
16285
+ console.log(import_chalk43.default.dim(" (it sees who is allowed vs denied). Send some through your proxy first \u2014"));
16286
+ console.log(import_chalk43.default.dim(` curl a few endpoints, or `) + import_chalk43.default.cyan("npx apiblaze dev") + import_chalk43.default.dim(` \u2014 then re-run.
15931
16287
  `));
15932
16288
  }
15933
16289
  async function applyProposal(opts) {
@@ -15936,12 +16292,12 @@ async function applyProposal(opts) {
15936
16292
  {
15937
16293
  const m = await agentCall(`/projects/${projectId}/${apiVersion}/policies/model?tenantId=${encodeURIComponent(tenant)}`, "POST", proposal.model);
15938
16294
  if (m.status === 404) {
15939
- log4(import_chalk41.default.red(` Project ${projectId} ${apiVersion} not found on the authorization service \u2014 check \`apiblaze projects\`.
16295
+ log4(import_chalk43.default.red(` Project ${projectId} ${apiVersion} not found on the authorization service \u2014 check \`apiblaze projects\`.
15940
16296
  `));
15941
16297
  return { ok: 0, fail: 0, enabled: false, aborted: true };
15942
16298
  }
15943
16299
  if (m.status >= 400) {
15944
- log4(import_chalk41.default.red(` Model save failed (${m.status}): ${m.data?.error ?? ""}
16300
+ log4(import_chalk43.default.red(` Model save failed (${m.status}): ${m.data?.error ?? ""}
15945
16301
  `));
15946
16302
  return { ok: 0, fail: 0, enabled: false, aborted: true };
15947
16303
  }
@@ -15973,17 +16329,17 @@ async function applyProposal(opts) {
15973
16329
  }
15974
16330
  }
15975
16331
  if (fail7 > 0) {
15976
- log4(import_chalk41.default.red(` ${fail7} of ${proposal.routes.length} route rule(s) could not be saved:`));
15977
- for (const f2 of failed) log4(import_chalk41.default.red(` ${f2}`));
16332
+ log4(import_chalk43.default.red(` ${fail7} of ${proposal.routes.length} route rule(s) could not be saved:`));
16333
+ for (const f2 of failed) log4(import_chalk43.default.red(` ${f2}`));
15978
16334
  if (enable) {
15979
- log4(import_chalk41.default.red(" Enforcement NOT turned on \u2014 a route without a saved rule is left open by the gateway. Fix the rule(s) above and re-run with --enforce.\n"));
16335
+ log4(import_chalk43.default.red(" Enforcement NOT turned on \u2014 a route without a saved rule is left open by the gateway. Fix the rule(s) above and re-run with --enforce.\n"));
15980
16336
  }
15981
16337
  return { ok, fail: fail7, enabled: false, aborted: true, failed };
15982
16338
  }
15983
16339
  if (enable) {
15984
16340
  const e = await agentCall(`/projects/${projectId}/${apiVersion}`, "PATCH", { authorization: { enforce_authorization: true }, tenant });
15985
16341
  if (e.status >= 400) {
15986
- log4(import_chalk41.default.red(` Enforced ${ok} route(s) but turning on the project-level switch failed (${e.status}). Toggle "Enforce Authorization" on in the dashboard.
16342
+ log4(import_chalk43.default.red(` Enforced ${ok} route(s) but turning on the project-level switch failed (${e.status}). Toggle "Enforce Authorization" on in the dashboard.
15987
16343
  `));
15988
16344
  return { ok, fail: fail7, enabled: false, failed };
15989
16345
  }
@@ -16011,19 +16367,19 @@ async function runAuthz(projectArg, apiVersionArg) {
16011
16367
  const proposal = ctx.proposal;
16012
16368
  const r = await applyProposal({ projectId, apiVersion, tenant, proposal, enable, log: ctx.log });
16013
16369
  if (r.aborted) {
16014
- ctx.log(import_chalk42.default.red(enable ? ` Enforcement NOT on \u2014 ${r.fail || "the"} route rule(s) failed. Fix them and /enable again.
16370
+ ctx.log(import_chalk44.default.red(enable ? ` Enforcement NOT on \u2014 ${r.fail || "the"} route rule(s) failed. Fix them and /enable again.
16015
16371
  ` : ` Not published \u2014 ${r.fail || "the"} route rule(s) failed. Fix them and /publish again.
16016
16372
  `));
16017
16373
  return;
16018
16374
  }
16019
16375
  if (enable && r.enabled) {
16020
- ctx.log(import_chalk42.default.green(` \u2713 Enforcement ON \u2014 ${r.ok} route(s) + project switch on.`));
16021
- ctx.log(import_chalk42.default.dim(" Route config takes up to ~90 s to reach every edge. Undo any time: ") + import_chalk42.default.cyan(`apiblaze config ${projectArg} authorization.enforce_authorization false`));
16022
- ctx.log(import_chalk42.default.dim(" Done here? Type /exit to leave the chat (your rule stays on).\n"));
16376
+ ctx.log(import_chalk44.default.green(` \u2713 Enforcement ON \u2014 ${r.ok} route(s) + project switch on.`));
16377
+ ctx.log(import_chalk44.default.dim(" Route config takes up to ~90 s to reach every edge. Undo any time: ") + import_chalk44.default.cyan(`apiblaze config ${projectArg} authorization.enforce_authorization false`));
16378
+ ctx.log(import_chalk44.default.dim(" Done here? Type /exit to leave the chat (your rule stays on).\n"));
16023
16379
  } else if (enable) {
16024
- ctx.log(import_chalk42.default.red(" Enforcement NOT on \u2014 the routes are set but the project switch did not flip (see above).\n"));
16380
+ ctx.log(import_chalk44.default.red(" Enforcement NOT on \u2014 the routes are set but the project switch did not flip (see above).\n"));
16025
16381
  } else {
16026
- ctx.log(import_chalk42.default.green(` \u2713 Published (shadow): model + ${r.ok} route(s). Review, then /enable.
16382
+ ctx.log(import_chalk44.default.green(` \u2713 Published (shadow): model + ${r.ok} route(s). Review, then /enable.
16027
16383
  `));
16028
16384
  }
16029
16385
  }
@@ -16050,8 +16406,8 @@ async function runAuthz(projectArg, apiVersionArg) {
16050
16406
  }
16051
16407
 
16052
16408
  // src/commands/rule.ts
16053
- var import_chalk43 = __toESM(require("chalk"));
16054
- var import_ora14 = __toESM(require("ora"));
16409
+ var import_chalk45 = __toESM(require("chalk"));
16410
+ var import_ora16 = __toESM(require("ora"));
16055
16411
  init_auth();
16056
16412
  init_api();
16057
16413
  init_create();
@@ -16075,15 +16431,15 @@ async function runRule(projectArg, ruleText, opts) {
16075
16431
  if (opts.off) {
16076
16432
  const { status: status3, data: data2 } = await agentCall(`/projects/${projectId}/${apiVersion}`, "PATCH", { authorization: { enforce_authorization: false }, tenant });
16077
16433
  if (status3 >= 400) throw new Error(`Could not turn enforcement off (${status3}): ${data2?.error ?? ""}`);
16078
- console.log(import_chalk43.default.green(" \u2713 Enforcement OFF \u2014 the rules are kept (shadow mode)."));
16079
- console.log(import_chalk43.default.dim(" Turn it back on: ") + import_chalk43.default.cyan(`${B.cli} rule ${projectArg} --enforce`));
16434
+ console.log(import_chalk45.default.green(" \u2713 Enforcement OFF \u2014 the rules are kept (shadow mode)."));
16435
+ console.log(import_chalk45.default.dim(" Turn it back on: ") + import_chalk45.default.cyan(`${B.cli} rule ${projectArg} --enforce`));
16080
16436
  return;
16081
16437
  }
16082
16438
  const rule = (ruleText ?? "").trim();
16083
16439
  if (!rule) return proposeFromSpecBranch(ctx, opts);
16084
16440
  const { ids: sampleIds, total: sampleTotal } = await gatherSampleIds(projectId, apiVersion);
16085
16441
  maybeWarnNoTraffic(sampleTotal, projectArg);
16086
- const spinner = (0, import_ora14.default)(sampleIds.length ? `Designing the rule from ${sampleIds.length} traffic sample(s)\u2026` : "Designing the rule\u2026").start();
16442
+ const spinner = (0, import_ora16.default)(sampleIds.length ? `Designing the rule from ${sampleIds.length} traffic sample(s)\u2026` : "Designing the rule\u2026").start();
16087
16443
  const messages = [{
16088
16444
  role: "user",
16089
16445
  content: `Author this authorization rule and generate the COMPLETE proposal (OpenFGA model + per-route rules) NOW for every affected route. Do not ask clarifying questions; make reasonable assumptions and state them briefly. Rule: "${rule}"`
@@ -16100,18 +16456,18 @@ async function runRule(projectArg, ruleText, opts) {
16100
16456
  const proposal = data?.proposal;
16101
16457
  if (!proposal || !Array.isArray(proposal.routes) || proposal.routes.length === 0) {
16102
16458
  spinner.fail("The agent couldn\u2019t turn that into a rule in one shot.");
16103
- if (data?.reply) console.log(import_chalk43.default.dim("\n " + String(data.reply).slice(0, 500) + "\n"));
16104
- console.log(import_chalk43.default.dim(" Try an interactive session for anything nuanced: ") + import_chalk43.default.cyan(`${B.cli} agent authz ${projectArg}`));
16459
+ if (data?.reply) console.log(import_chalk45.default.dim("\n " + String(data.reply).slice(0, 500) + "\n"));
16460
+ console.log(import_chalk45.default.dim(" Try an interactive session for anything nuanced: ") + import_chalk45.default.cyan(`${B.cli} agent authz ${projectArg}`));
16105
16461
  return;
16106
16462
  }
16107
16463
  spinner.succeed(`Rule designed \u2014 ${proposal.routes.length} route(s) affected.`);
16108
- if (data?.reply) console.log(import_chalk43.default.dim(" " + String(data.reply).slice(0, 240)));
16464
+ if (data?.reply) console.log(import_chalk45.default.dim(" " + String(data.reply).slice(0, 240)));
16109
16465
  await shadowThenEnforce(ctx, proposal, opts.enforce ? "yes" : "no", `${B.cli} rule ${projectArg} "${rule}" --enforce`);
16110
16466
  }
16111
16467
  async function proposeFromSpecBranch(ctx, opts) {
16112
16468
  const { projectId, apiVersion, projectArg } = ctx;
16113
16469
  const interactive2 = !!process.stdin.isTTY;
16114
- const spinner = (0, import_ora14.default)("Reading the spec for things to protect\u2026").start();
16470
+ const spinner = (0, import_ora16.default)("Reading the spec for things to protect\u2026").start();
16115
16471
  const first = await agentCall(`/projects/${projectId}/${apiVersion}/authz/propose`, "POST", {});
16116
16472
  if (first.status >= 400) {
16117
16473
  spinner.fail(`Could not work out what to protect (${first.status}): ${first.data?.details ?? first.data?.error ?? ""}`);
@@ -16121,36 +16477,36 @@ async function proposeFromSpecBranch(ctx, opts) {
16121
16477
  const protectable = families.filter((f2) => !f2.skipped_reason);
16122
16478
  if (!protectable.length) {
16123
16479
  spinner.stop();
16124
- console.log(import_chalk43.default.dim(` Nothing to lock: the spec has no resource with a POST collection plus item routes${families.length ? ` (${families.length} candidate(s) not protectable)` : ""}.`));
16125
- console.log(import_chalk43.default.dim(" Describe the rule instead: ") + import_chalk43.default.cyan(`${B.cli} rule ${projectArg} "users see only their own rows"`));
16480
+ console.log(import_chalk45.default.dim(` Nothing to lock: the spec has no resource with a POST collection plus item routes${families.length ? ` (${families.length} candidate(s) not protectable)` : ""}.`));
16481
+ console.log(import_chalk45.default.dim(" Describe the rule instead: ") + import_chalk45.default.cyan(`${B.cli} rule ${projectArg} "users see only their own rows"`));
16126
16482
  return;
16127
16483
  }
16128
16484
  spinner.stop();
16129
16485
  const chosen = interactive2 ? await pickFamilies(families) : protectable.map((f2) => f2.key);
16130
16486
  if (!chosen.length) {
16131
- console.log(import_chalk43.default.dim(" Nothing selected \u2014 no rules written."));
16487
+ console.log(import_chalk45.default.dim(" Nothing selected \u2014 no rules written."));
16132
16488
  return;
16133
16489
  }
16134
16490
  let data = first.data;
16135
16491
  if (chosen.length !== protectable.length) {
16136
16492
  const second = await agentCall(`/projects/${projectId}/${apiVersion}/authz/propose`, "POST", { families: chosen });
16137
16493
  if (second.status >= 400) {
16138
- console.log(import_chalk43.default.red(` Could not build the rules for that selection (${second.status}): ${second.data?.error ?? ""}`));
16494
+ console.log(import_chalk45.default.red(` Could not build the rules for that selection (${second.status}): ${second.data?.error ?? ""}`));
16139
16495
  return;
16140
16496
  }
16141
16497
  data = second.data;
16142
16498
  }
16143
16499
  const proposal = data?.proposal;
16144
16500
  if (!proposal || !Array.isArray(proposal.routes) || !proposal.routes.length) {
16145
- console.log(import_chalk43.default.red(" The authorization service returned no routes for that selection."));
16501
+ console.log(import_chalk45.default.red(" The authorization service returned no routes for that selection."));
16146
16502
  return;
16147
16503
  }
16148
16504
  const sim = data?.simulation;
16149
16505
  if (sim?.blocked_without_backfill) {
16150
- console.log(import_chalk43.default.yellow(` \u26A0 ${sim.blocked_without_backfill} request(s) that succeed today would be denied once enforced \u2014`));
16151
- console.log(import_chalk43.default.yellow(" rows created before the rules have no recorded owner. Backfill them or accept it."));
16506
+ console.log(import_chalk45.default.yellow(` \u26A0 ${sim.blocked_without_backfill} request(s) that succeed today would be denied once enforced \u2014`));
16507
+ console.log(import_chalk45.default.yellow(" rows created before the rules have no recorded owner. Backfill them or accept it."));
16152
16508
  }
16153
- console.log(import_chalk43.default.green(` \u2713 ${chosen.map((k) => k.replace(/^\//, "")).join(" + ")} \u2014 ${proposal.routes.length} route rule(s).`));
16509
+ console.log(import_chalk45.default.green(` \u2713 ${chosen.map((k) => k.replace(/^\//, "")).join(" + ")} \u2014 ${proposal.routes.length} route rule(s).`));
16154
16510
  let enforce = opts.enforce ? "yes" : interactive2 ? "ask" : "no";
16155
16511
  await shadowThenEnforce(ctx, proposal, enforce, `${B.cli} rule ${projectArg} --enforce`);
16156
16512
  }
@@ -16158,37 +16514,37 @@ async function shadowThenEnforce(ctx, proposal, enforce, enforceCmd) {
16158
16514
  const { projectId, apiVersion, tenant, projectArg } = ctx;
16159
16515
  const pub = await applyProposal({ projectId, apiVersion, tenant, proposal, enable: false });
16160
16516
  if (pub.aborted) {
16161
- console.log(import_chalk43.default.red(` Nothing saved${pub.ok ? ` beyond ${pub.ok} route(s)` : ""} \u2014 fix the error above and re-run.`));
16517
+ console.log(import_chalk45.default.red(` Nothing saved${pub.ok ? ` beyond ${pub.ok} route(s)` : ""} \u2014 fix the error above and re-run.`));
16162
16518
  return;
16163
16519
  }
16164
- console.log(import_chalk43.default.green(` \u2713 Saved in shadow mode \u2014 model + ${pub.ok} route(s). Nothing is blocked yet.`));
16520
+ console.log(import_chalk45.default.green(` \u2713 Saved in shadow mode \u2014 model + ${pub.ok} route(s). Nothing is blocked yet.`));
16165
16521
  if (enforce === "ask") {
16166
16522
  const { default: inquirer3 } = await import("inquirer");
16167
16523
  const { on } = await inquirer3.prompt([{ type: "confirm", name: "on", message: "Turn enforcement on now?", default: true }]);
16168
16524
  enforce = on ? "yes" : "no";
16169
16525
  }
16170
16526
  if (enforce !== "yes") {
16171
- console.log(import_chalk43.default.dim(" Review it (shadow logs), then enforce: ") + import_chalk43.default.cyan(enforceCmd));
16527
+ console.log(import_chalk45.default.dim(" Review it (shadow logs), then enforce: ") + import_chalk45.default.cyan(enforceCmd));
16172
16528
  return;
16173
16529
  }
16174
16530
  const enf = await applyProposal({ projectId, apiVersion, tenant, proposal, enable: true });
16175
16531
  if (enf.aborted) {
16176
- console.log(import_chalk43.default.red(` Enforcement NOT on \u2014 ${enf.fail} route rule(s) failed (listed above). Rules stay in shadow mode.`));
16532
+ console.log(import_chalk45.default.red(` Enforcement NOT on \u2014 ${enf.fail} route rule(s) failed (listed above). Rules stay in shadow mode.`));
16177
16533
  return;
16178
16534
  }
16179
16535
  if (!enf.enabled) {
16180
- console.log(import_chalk43.default.red(" Enforcement NOT on \u2014 the routes are set but the project switch did not flip (see above)."));
16536
+ console.log(import_chalk45.default.red(" Enforcement NOT on \u2014 the routes are set but the project switch did not flip (see above)."));
16181
16537
  return;
16182
16538
  }
16183
- console.log(import_chalk43.default.green(` \u2713 Enforcement ON \u2014 ${enf.ok} route(s) + project switch on.`));
16184
- console.log(import_chalk43.default.dim(" Route config takes up to ~90 s to reach every edge."));
16185
- console.log(import_chalk43.default.dim(" Testing a locked route? Use the sign-in door, or send X-End-User-Id / a key minted with --for \u2014"));
16186
- console.log(import_chalk43.default.dim(" a bare key has no person to check."));
16187
- console.log(import_chalk43.default.dim(` Undo: `) + import_chalk43.default.cyan(B.cli === "mcpblaze" ? `${B.cli} rule ${projectArg} --off` : `${B.cli} config ${projectArg} authorization.enforce_authorization false`));
16539
+ console.log(import_chalk45.default.green(` \u2713 Enforcement ON \u2014 ${enf.ok} route(s) + project switch on.`));
16540
+ console.log(import_chalk45.default.dim(" Route config takes up to ~90 s to reach every edge."));
16541
+ console.log(import_chalk45.default.dim(" Testing a locked route? Use the sign-in door, or send X-End-User-Id / a key minted with --for \u2014"));
16542
+ console.log(import_chalk45.default.dim(" a bare key has no person to check."));
16543
+ console.log(import_chalk45.default.dim(` Undo: `) + import_chalk45.default.cyan(B.cli === "mcpblaze" ? `${B.cli} rule ${projectArg} --off` : `${B.cli} config ${projectArg} authorization.enforce_authorization false`));
16188
16544
  }
16189
16545
 
16190
16546
  // src/commands/openapi.ts
16191
- var import_chalk44 = __toESM(require("chalk"));
16547
+ var import_chalk46 = __toESM(require("chalk"));
16192
16548
  init_auth();
16193
16549
  init_api();
16194
16550
  init_agent_chat();
@@ -16200,10 +16556,10 @@ async function runOpenapi(projectArg, apiVersionArg) {
16200
16556
  if (!match) throw new Error(`Project "${projectArg}" not found in your active team. Run \`apiblaze projects\`.`);
16201
16557
  const projectId = match.projectId;
16202
16558
  const apiVersion = apiVersionArg || match.apiVersion;
16203
- console.log(import_chalk44.default.dim("Gathering captured traffic samples\u2026"));
16559
+ console.log(import_chalk46.default.dim("Gathering captured traffic samples\u2026"));
16204
16560
  const routesRes = await agentCall(`/projects/${projectId}/${apiVersion}/samples/routes`, "GET");
16205
16561
  if (routesRes.status >= 400) {
16206
- console.log(import_chalk44.default.red(`Could not list traffic (${routesRes.status}): ${routesRes.data?.error ?? ""}`));
16562
+ console.log(import_chalk46.default.red(`Could not list traffic (${routesRes.status}): ${routesRes.data?.error ?? ""}`));
16207
16563
  return;
16208
16564
  }
16209
16565
  const routes = routesRes.data?.routes ?? (Array.isArray(routesRes.data) ? routesRes.data : []);
@@ -16216,25 +16572,25 @@ async function runOpenapi(projectArg, apiVersionArg) {
16216
16572
  }
16217
16573
  const sampleIds = [...ids];
16218
16574
  if (sampleIds.length === 0) {
16219
- console.log(import_chalk44.default.yellow("No captured traffic samples found. Hit the dev environment of this proxy to capture some traces, then retry."));
16575
+ console.log(import_chalk46.default.yellow("No captured traffic samples found. Hit the dev environment of this proxy to capture some traces, then retry."));
16220
16576
  return;
16221
16577
  }
16222
16578
  async function publish(ctx) {
16223
16579
  const patch = ctx.proposal.patch;
16224
16580
  if (!Array.isArray(patch) || patch.length === 0) {
16225
- ctx.log(import_chalk44.default.green(" Nothing to publish \u2014 the spec already covers the observed traffic.\n"));
16581
+ ctx.log(import_chalk46.default.green(" Nothing to publish \u2014 the spec already covers the observed traffic.\n"));
16226
16582
  return;
16227
16583
  }
16228
16584
  const specSource = ctx.lastData?.spec_source ?? "unknown";
16229
16585
  const endpoint = specSource === "github" ? "open-pr" : "publish-openapi";
16230
16586
  const pub = await agentCall(`/projects/${projectId}/${apiVersion}/samples/${endpoint}`, "POST", { patch, sample_ids_used: sampleIds });
16231
16587
  if (pub.status >= 400) {
16232
- ctx.log(import_chalk44.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
16588
+ ctx.log(import_chalk46.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
16233
16589
  `));
16234
16590
  return;
16235
16591
  }
16236
16592
  const prUrl = pub.data?.pr_url;
16237
- ctx.log(import_chalk44.default.green(prUrl ? ` \u2713 Pull request opened: ${prUrl}
16593
+ ctx.log(import_chalk46.default.green(prUrl ? ` \u2713 Pull request opened: ${prUrl}
16238
16594
  ` : " \u2713 Published updated OpenAPI spec.\n"));
16239
16595
  }
16240
16596
  await runAgentChatRepl({
@@ -16258,13 +16614,13 @@ async function runOpenapi(projectArg, apiVersionArg) {
16258
16614
  init_mcp();
16259
16615
 
16260
16616
  // src/commands/delete.ts
16261
- var import_chalk46 = __toESM(require("chalk"));
16262
- var import_ora15 = __toESM(require("ora"));
16617
+ var import_chalk48 = __toESM(require("chalk"));
16618
+ var import_ora17 = __toESM(require("ora"));
16263
16619
  init_admin();
16264
16620
  init_resolve();
16265
16621
 
16266
16622
  // src/lib/job.ts
16267
- var import_chalk45 = __toESM(require("chalk"));
16623
+ var import_chalk47 = __toESM(require("chalk"));
16268
16624
  init_admin();
16269
16625
  var POLL_MS = 3e3;
16270
16626
  var MAX_WAIT_MS = 30 * 6e4;
@@ -16298,7 +16654,7 @@ async function pollJob(jobId, opts = {}) {
16298
16654
  const started = Date.now();
16299
16655
  const path20 = jobPath(jobId, opts.teamId);
16300
16656
  let lastPhase = "";
16301
- if (!opts.quiet) process.stdout.write(import_chalk45.default.dim(opts.label ?? "Deleting"));
16657
+ if (!opts.quiet) process.stdout.write(import_chalk47.default.dim(opts.label ?? "Deleting"));
16302
16658
  for (; ; ) {
16303
16659
  if (Date.now() - started > MAX_WAIT_MS) {
16304
16660
  if (!opts.quiet) process.stdout.write("\n");
@@ -16312,11 +16668,11 @@ async function pollJob(jobId, opts = {}) {
16312
16668
  if (!opts.quiet) {
16313
16669
  const phase = describeJob(job);
16314
16670
  if (phase !== lastPhase) {
16315
- process.stdout.write(import_chalk45.default.dim(`
16671
+ process.stdout.write(import_chalk47.default.dim(`
16316
16672
  ${phase}`));
16317
16673
  lastPhase = phase;
16318
16674
  }
16319
- process.stdout.write(import_chalk45.default.dim("."));
16675
+ process.stdout.write(import_chalk47.default.dim("."));
16320
16676
  }
16321
16677
  if (job.status === "done" || job.status === "failed") {
16322
16678
  if (!opts.quiet) process.stdout.write("\n");
@@ -16329,7 +16685,7 @@ async function settleDelete(accepted, opts) {
16329
16685
  if (!jobId) return null;
16330
16686
  if (opts.noWait) {
16331
16687
  if (!opts.json) {
16332
- console.log(import_chalk45.default.dim(`Queued as job ${jobId}. Check it with: apiblaze job ${jobId}${opts.teamId ? ` --team ${opts.teamId}` : ""}`));
16688
+ console.log(import_chalk47.default.dim(`Queued as job ${jobId}. Check it with: apiblaze job ${jobId}${opts.teamId ? ` --team ${opts.teamId}` : ""}`));
16333
16689
  }
16334
16690
  return null;
16335
16691
  }
@@ -16350,7 +16706,7 @@ async function settleDelete(accepted, opts) {
16350
16706
  async function runDelete(project, version2, opts) {
16351
16707
  const { teamId } = await resolveTeam(opts.team);
16352
16708
  const proj2 = await resolveProject(teamId, project, version2);
16353
- const spinner = (0, import_ora15.default)("Checking delete impact...").start();
16709
+ const spinner = (0, import_ora17.default)("Checking delete impact...").start();
16354
16710
  let impact;
16355
16711
  try {
16356
16712
  impact = await admin({
@@ -16369,10 +16725,10 @@ async function runDelete(project, version2, opts) {
16369
16725
  return;
16370
16726
  }
16371
16727
  } else {
16372
- console.log(`${import_chalk46.default.red.bold("Delete")} ${import_chalk46.default.bold(proj2.projectName)} ${import_chalk46.default.dim("v" + proj2.apiVersion)} ${import_chalk46.default.dim("(" + proj2.projectId + ")")}`);
16728
+ console.log(`${import_chalk48.default.red.bold("Delete")} ${import_chalk48.default.bold(proj2.projectName)} ${import_chalk48.default.dim("v" + proj2.apiVersion)} ${import_chalk48.default.dim("(" + proj2.projectId + ")")}`);
16373
16729
  if (impact && typeof impact === "object") {
16374
16730
  const counts = impact.counts ?? impact.impact ?? impact;
16375
- console.log(import_chalk46.default.dim(" This removes (cascade): ") + import_chalk46.default.yellow(JSON.stringify(counts)));
16731
+ console.log(import_chalk48.default.dim(" This removes (cascade): ") + import_chalk48.default.yellow(JSON.stringify(counts)));
16376
16732
  }
16377
16733
  if (!opts.yes) {
16378
16734
  const { default: inquirer3 } = await import("inquirer");
@@ -16380,12 +16736,12 @@ async function runDelete(project, version2, opts) {
16380
16736
  { type: "confirm", name: "confirm", message: `Permanently delete ${proj2.projectName} v${proj2.apiVersion}? This cannot be undone.`, default: false }
16381
16737
  ]);
16382
16738
  if (!confirm3) {
16383
- console.log(import_chalk46.default.dim("Aborted."));
16739
+ console.log(import_chalk48.default.dim("Aborted."));
16384
16740
  return;
16385
16741
  }
16386
16742
  }
16387
16743
  }
16388
- const s2 = (0, import_ora15.default)("Deleting...").start();
16744
+ const s2 = (0, import_ora17.default)("Deleting...").start();
16389
16745
  let accepted;
16390
16746
  try {
16391
16747
  accepted = await admin({
@@ -16406,7 +16762,7 @@ async function runDelete(project, version2, opts) {
16406
16762
  });
16407
16763
  if (!opts.json) {
16408
16764
  if (job || accepted?.job_id == null) {
16409
- console.log(import_chalk46.default.green(`\u2714 Deleted ${proj2.projectName} v${proj2.apiVersion}.`));
16765
+ console.log(import_chalk48.default.green(`\u2714 Deleted ${proj2.projectName} v${proj2.apiVersion}.`));
16410
16766
  }
16411
16767
  } else {
16412
16768
  console.log(JSON.stringify({
@@ -16419,7 +16775,7 @@ async function runDelete(project, version2, opts) {
16419
16775
  }
16420
16776
 
16421
16777
  // src/commands/job.ts
16422
- var import_chalk47 = __toESM(require("chalk"));
16778
+ var import_chalk49 = __toESM(require("chalk"));
16423
16779
  init_admin();
16424
16780
  init_resolve();
16425
16781
  async function runJobStatus(jobId, opts) {
@@ -16435,24 +16791,24 @@ async function runJobStatus(jobId, opts) {
16435
16791
  if (job.status === "failed") process.exitCode = 1;
16436
16792
  return;
16437
16793
  }
16438
- const colour = job.status === "done" ? import_chalk47.default.green : job.status === "failed" ? import_chalk47.default.red : import_chalk47.default.yellow;
16439
- console.log(`${import_chalk47.default.bold(job.job_id)} ${import_chalk47.default.dim(`(${job.kind})`)} ${colour.bold(job.status)}`);
16794
+ const colour = job.status === "done" ? import_chalk49.default.green : job.status === "failed" ? import_chalk49.default.red : import_chalk49.default.yellow;
16795
+ console.log(`${import_chalk49.default.bold(job.job_id)} ${import_chalk49.default.dim(`(${job.kind})`)} ${colour.bold(job.status)}`);
16440
16796
  if (job.status === "queued" || job.status === "running") {
16441
- console.log(import_chalk47.default.dim(` ${describeJob(job)}`));
16797
+ console.log(import_chalk49.default.dim(` ${describeJob(job)}`));
16442
16798
  }
16443
16799
  const counts = [];
16444
16800
  if (job.progress?.proxies) counts.push(`${job.progress.proxies} prox`);
16445
16801
  if (job.progress?.tenants) counts.push(`${job.progress.tenants} tenant(s)`);
16446
- if (counts.length) console.log(import_chalk47.default.dim(` removed: ${counts.join(", ")}`));
16447
- if (job.attempts > 1) console.log(import_chalk47.default.dim(` attempts: ${job.attempts}`));
16448
- if (job.error) console.log(import_chalk47.default.red(` ${job.error}`));
16802
+ if (counts.length) console.log(import_chalk49.default.dim(` removed: ${counts.join(", ")}`));
16803
+ if (job.attempts > 1) console.log(import_chalk49.default.dim(` attempts: ${job.attempts}`));
16804
+ if (job.error) console.log(import_chalk49.default.red(` ${job.error}`));
16449
16805
  const parked = job.progress?.failed_units ?? [];
16450
- if (parked.length) console.log(import_chalk47.default.red(` left behind: ${parked.slice(0, 10).join(", ")}`));
16806
+ if (parked.length) console.log(import_chalk49.default.red(` left behind: ${parked.slice(0, 10).join(", ")}`));
16451
16807
  if (job.status === "failed") process.exitCode = 1;
16452
16808
  }
16453
16809
 
16454
16810
  // src/commands/export.ts
16455
- var import_chalk48 = __toESM(require("chalk"));
16811
+ var import_chalk50 = __toESM(require("chalk"));
16456
16812
  var import_fs13 = require("fs");
16457
16813
  init_admin();
16458
16814
  init_auth();
@@ -16471,7 +16827,7 @@ async function runExport(projectArg, versionArg, opts) {
16471
16827
  if (opts.noConsumers) q.set("include_consumers", "0");
16472
16828
  if (opts.keys) q.set("keys", opts.keys);
16473
16829
  const qs = q.toString() ? `?${q.toString()}` : "";
16474
- console.log(import_chalk48.default.dim(`Queuing ${target2} export of ${projectId}@${version2}\u2026`));
16830
+ console.log(import_chalk50.default.dim(`Queuing ${target2} export of ${projectId}@${version2}\u2026`));
16475
16831
  const job = await admin({
16476
16832
  path: `/projects/${projectId}/${version2}/export/${target2}${qs}`,
16477
16833
  method: "GET",
@@ -16481,11 +16837,11 @@ async function runExport(projectArg, versionArg, opts) {
16481
16837
  const statusPath = `/projects/${projectId}/${version2}/export/jobs/${job.job_id}`;
16482
16838
  let status2 = "queued";
16483
16839
  const started = Date.now();
16484
- process.stdout.write(import_chalk48.default.dim("Building bundle"));
16840
+ process.stdout.write(import_chalk50.default.dim("Building bundle"));
16485
16841
  while (status2 !== "ready" && status2 !== "failed") {
16486
16842
  if (Date.now() - started > 10 * 6e4) throw new Error("Export timed out after 10 minutes.");
16487
16843
  await new Promise((r) => setTimeout(r, 3e3));
16488
- process.stdout.write(import_chalk48.default.dim("."));
16844
+ process.stdout.write(import_chalk50.default.dim("."));
16489
16845
  const st = await admin({ path: statusPath, method: "GET", summary: "poll export" });
16490
16846
  status2 = st?.status ?? "queued";
16491
16847
  if (status2 === "failed") {
@@ -16503,15 +16859,15 @@ async function runExport(projectArg, versionArg, opts) {
16503
16859
  if (!res.ok) throw new Error(`Download failed (${res.status}): ${await res.text().catch(() => "")}`);
16504
16860
  const buf = Buffer.from(await res.arrayBuffer());
16505
16861
  (0, import_fs13.writeFileSync)(outFile, buf);
16506
- console.log(import_chalk48.default.green(`\u2713 Saved ${outFile} (${(buf.length / 1024).toFixed(0)} KB)`));
16507
- if (job.decryption_key) console.log(import_chalk48.default.yellow(`Decryption key (shown once): ${job.decryption_key}`));
16508
- console.log(import_chalk48.default.dim("Read MIGRATION-REPORT.json inside the zip for the full fidelity ledger."));
16509
- if (target2 === "kong") console.log(import_chalk48.default.dim("Kong: unzip, then `cd kong && docker compose up` (see kong/README.md)."));
16862
+ console.log(import_chalk50.default.green(`\u2713 Saved ${outFile} (${(buf.length / 1024).toFixed(0)} KB)`));
16863
+ if (job.decryption_key) console.log(import_chalk50.default.yellow(`Decryption key (shown once): ${job.decryption_key}`));
16864
+ console.log(import_chalk50.default.dim("Read MIGRATION-REPORT.json inside the zip for the full fidelity ledger."));
16865
+ if (target2 === "kong") console.log(import_chalk50.default.dim("Kong: unzip, then `cd kong && docker compose up` (see kong/README.md)."));
16510
16866
  }
16511
16867
 
16512
16868
  // src/commands/recipe-search.ts
16513
- var import_chalk49 = __toESM(require("chalk"));
16514
- var import_ora16 = __toESM(require("ora"));
16869
+ var import_chalk51 = __toESM(require("chalk"));
16870
+ var import_ora18 = __toESM(require("ora"));
16515
16871
  init_caller();
16516
16872
 
16517
16873
  // src/lib/recipes.ts
@@ -16697,7 +17053,7 @@ function upstreamHosts(recipe) {
16697
17053
 
16698
17054
  // src/commands/recipe-search.ts
16699
17055
  async function runRecipeSearch(query, opts) {
16700
- const spinner = !opts.json ? (0, import_ora16.default)("Searching recipes...").start() : null;
17056
+ const spinner = !opts.json ? (0, import_ora18.default)("Searching recipes...").start() : null;
16701
17057
  let hits;
16702
17058
  try {
16703
17059
  hits = await searchRecipes(query ?? "", opts.limit ? Number(opts.limit) : void 0);
@@ -16711,20 +17067,20 @@ async function runRecipeSearch(query, opts) {
16711
17067
  return;
16712
17068
  }
16713
17069
  if (!hits.length) {
16714
- console.log(import_chalk49.default.yellow(query ? `No public recipes match "${query}".` : "No public recipes yet."));
16715
- console.log(import_chalk49.default.dim(" Publish one with: apiblaze publish <proxy> --as @yourhandle/name"));
17070
+ console.log(import_chalk51.default.yellow(query ? `No public recipes match "${query}".` : "No public recipes yet."));
17071
+ console.log(import_chalk51.default.dim(" Publish one with: apiblaze publish <proxy> --as @yourhandle/name"));
16716
17072
  return;
16717
17073
  }
16718
17074
  console.log();
16719
17075
  for (const h of hits) {
16720
- const pin = h.latest_revision ? import_chalk49.default.dim(`@${h.latest_revision}`) : "";
16721
- const installs = h.install_count ? import_chalk49.default.dim(` ${h.install_count} install${h.install_count === 1 ? "" : "s"}`) : "";
16722
- console.log(` ${import_chalk49.default.bold(h.name)}${pin}${h.display_name ? import_chalk49.default.dim(` \u2014 ${h.display_name}`) : ""}${installs}`);
16723
- if (h.summary) console.log(` ${import_chalk49.default.dim(h.summary)}`);
17076
+ const pin = h.latest_revision ? import_chalk51.default.dim(`@${h.latest_revision}`) : "";
17077
+ const installs = h.install_count ? import_chalk51.default.dim(` ${h.install_count} install${h.install_count === 1 ? "" : "s"}`) : "";
17078
+ console.log(` ${import_chalk51.default.bold(h.name)}${pin}${h.display_name ? import_chalk51.default.dim(` \u2014 ${h.display_name}`) : ""}${installs}`);
17079
+ if (h.summary) console.log(` ${import_chalk51.default.dim(h.summary)}`);
16724
17080
  }
16725
17081
  console.log();
16726
- console.log(import_chalk49.default.dim(` Install one with: ${import_chalk49.default.cyan(`npx apiblaze install ${hits[0].name}`)}`));
16727
- console.log(import_chalk49.default.dim(` Read one first: ${import_chalk49.default.cyan(`npx apiblaze show ${hits[0].name}`)}`));
17082
+ console.log(import_chalk51.default.dim(` Install one with: ${import_chalk51.default.cyan(`npx apiblaze install ${hits[0].name}`)}`));
17083
+ console.log(import_chalk51.default.dim(` Read one first: ${import_chalk51.default.cyan(`npx apiblaze show ${hits[0].name}`)}`));
16728
17084
  console.log();
16729
17085
  }
16730
17086
  async function runRecipeShow(nameArg, opts) {
@@ -16732,7 +17088,7 @@ async function runRecipeShow(nameArg, opts) {
16732
17088
  const wantsSection = !!(opts.transforms || opts.settings || opts.auth || opts.openapi);
16733
17089
  const caller = resolveCaller();
16734
17090
  const head = ref.revision === void 0 ? await getRecipeHead(ref).catch(() => null) : null;
16735
- const spinner = !opts.json ? (0, import_ora16.default)(`Reading ${ref.name}...`).start() : null;
17091
+ const spinner = !opts.json ? (0, import_ora18.default)(`Reading ${ref.name}...`).start() : null;
16736
17092
  let recipe;
16737
17093
  try {
16738
17094
  recipe = await fetchRecipeFile(ref, caller);
@@ -16750,8 +17106,8 @@ async function runRecipeShow(nameArg, opts) {
16750
17106
  return;
16751
17107
  }
16752
17108
  console.log();
16753
- console.log(`${import_chalk49.default.bold(`${recipe.name}@${recipe.revision}`)}${import_chalk49.default.dim(` \u2014 by ${ref.handle}`)}`);
16754
- if (recipe.display_name) console.log(` ${import_chalk49.default.bold(recipe.display_name)}`);
17109
+ console.log(`${import_chalk51.default.bold(`${recipe.name}@${recipe.revision}`)}${import_chalk51.default.dim(` \u2014 by ${ref.handle}`)}`);
17110
+ if (recipe.display_name) console.log(` ${import_chalk51.default.bold(recipe.display_name)}`);
16755
17111
  if (recipe.summary) console.log(` ${recipe.summary}`);
16756
17112
  const meta = [
16757
17113
  head?.install_count !== void 0 ? `${head.install_count} install${head.install_count === 1 ? "" : "s"}` : null,
@@ -16759,7 +17115,7 @@ async function runRecipeShow(nameArg, opts) {
16759
17115
  recipe.published_at ? `published ${recipe.published_at.slice(0, 10)}` : null,
16760
17116
  `api version ${recipe.api_version}`
16761
17117
  ].filter(Boolean).join(" \xB7 ");
16762
- console.log(import_chalk49.default.dim(` ${meta}`));
17118
+ console.log(import_chalk51.default.dim(` ${meta}`));
16763
17119
  console.log();
16764
17120
  if (wantsSection) {
16765
17121
  if (opts.settings) printSection("settings", recipe.settings);
@@ -16773,34 +17129,34 @@ async function runRecipeShow(nameArg, opts) {
16773
17129
  const rules = recipe.transformations?.rules?.length ?? 0;
16774
17130
  const tables = recipe.transformations?.mapping_tables?.length ?? 0;
16775
17131
  const keyTypes = recipe.auth?.key_types?.length ?? 0;
16776
- if (hosts.length) console.log(` ${import_chalk49.default.dim("sends requests to")} ${hosts.join(", ")}`);
16777
- console.log(` ${import_chalk49.default.dim("creates ")} ${describeCreates(keyTypes, routes, !!recipe.settings.mcp_enabled)}`);
16778
- console.log(` ${import_chalk49.default.dim("asks you for ")} ${recipe.questions.length} value${recipe.questions.length === 1 ? "" : "s"}`);
17132
+ if (hosts.length) console.log(` ${import_chalk51.default.dim("sends requests to")} ${hosts.join(", ")}`);
17133
+ console.log(` ${import_chalk51.default.dim("creates ")} ${describeCreates(keyTypes, routes, !!recipe.settings.mcp_enabled)}`);
17134
+ console.log(` ${import_chalk51.default.dim("asks you for ")} ${recipe.questions.length} value${recipe.questions.length === 1 ? "" : "s"}`);
16779
17135
  if (rules || tables) {
16780
- console.log(` ${import_chalk49.default.dim("transforms ")} ${rules} rule${rules === 1 ? "" : "s"}${tables ? `, ${tables} mapping table${tables === 1 ? "" : "s"}` : ""}`);
17136
+ console.log(` ${import_chalk51.default.dim("transforms ")} ${rules} rule${rules === 1 ? "" : "s"}${tables ? `, ${tables} mapping table${tables === 1 ? "" : "s"}` : ""}`);
16781
17137
  }
16782
17138
  if (recipe.settings.publish_openapi === true) {
16783
- console.log(` ${import_chalk49.default.dim("makes public ")} this API's spec`);
17139
+ console.log(` ${import_chalk51.default.dim("makes public ")} this API's spec`);
16784
17140
  }
16785
17141
  if (recipe.questions.length) {
16786
17142
  console.log();
16787
- console.log(import_chalk49.default.bold(" It will ask you for"));
17143
+ console.log(import_chalk51.default.bold(" It will ask you for"));
16788
17144
  for (const q of recipe.questions) {
16789
- console.log(` ${q.prompt}${q.secret ? import_chalk49.default.dim(" (hidden while you type)") : ""}`);
16790
- if (q.example) console.log(import_chalk49.default.dim(` e.g. ${q.example}`));
17145
+ console.log(` ${q.prompt}${q.secret ? import_chalk51.default.dim(" (hidden while you type)") : ""}`);
17146
+ if (q.example) console.log(import_chalk51.default.dim(` e.g. ${q.example}`));
16791
17147
  }
16792
17148
  }
16793
17149
  if (recipe.requires_confirmation?.length) {
16794
17150
  console.log();
16795
- console.log(import_chalk49.default.yellow(" Needs your explicit consent at install time"));
17151
+ console.log(import_chalk51.default.yellow(" Needs your explicit consent at install time"));
16796
17152
  for (const c of recipe.requires_confirmation) {
16797
- console.log(` ${import_chalk49.default.bold(c.kind)} ${c.value}`);
16798
- console.log(import_chalk49.default.dim(` ${c.why}`));
17153
+ console.log(` ${import_chalk51.default.bold(c.kind)} ${c.value}`);
17154
+ console.log(import_chalk51.default.dim(` ${c.why}`));
16799
17155
  }
16800
17156
  }
16801
17157
  console.log();
16802
- console.log(import_chalk49.default.dim(` Install: ${import_chalk49.default.cyan(`npx apiblaze install ${recipe.name}`)}`));
16803
- console.log(import_chalk49.default.dim(" Sections: --settings --auth --transforms --openapi"));
17158
+ console.log(import_chalk51.default.dim(` Install: ${import_chalk51.default.cyan(`npx apiblaze install ${recipe.name}`)}`));
17159
+ console.log(import_chalk51.default.dim(" Sections: --settings --auth --transforms --openapi"));
16804
17160
  console.log();
16805
17161
  }
16806
17162
  function describeCreates(keyTypes, routes, mcp, includeProxy = true) {
@@ -16810,45 +17166,45 @@ function describeCreates(keyTypes, routes, mcp, includeProxy = true) {
16810
17166
  return parts.length ? parts.join(", ") : "nothing else";
16811
17167
  }
16812
17168
  function printSection(title, value) {
16813
- console.log(import_chalk49.default.bold(` ${title}`));
17169
+ console.log(import_chalk51.default.bold(` ${title}`));
16814
17170
  console.log(indent(JSON.stringify(value ?? null, null, 2), " "));
16815
17171
  console.log();
16816
17172
  }
16817
17173
  function printAuth(recipe) {
16818
17174
  const a = recipe.auth ?? { app_client: null, provider: null, key_types: [] };
16819
- console.log(import_chalk49.default.bold(" auth"));
17175
+ console.log(import_chalk51.default.bold(" auth"));
16820
17176
  if (a.provider) {
16821
- console.log(` ${import_chalk49.default.dim("provider ")} ${a.provider.type ?? "(unknown)"}`);
16822
- if (a.provider.scopes) console.log(` ${import_chalk49.default.dim("scopes ")} ${a.provider.scopes}`);
16823
- if (a.provider.target_server_token) console.log(` ${import_chalk49.default.dim("sends to API")} ${a.provider.target_server_token}`);
16824
- console.log(a.provider.managed === true ? import_chalk49.default.dim(" (APIblaze's own GitHub app \u2014 installers get the same zero-config door, nothing to create)") : import_chalk49.default.dim(" (no credentials travel in a recipe \u2014 install asks for your own OAuth app)"));
17177
+ console.log(` ${import_chalk51.default.dim("provider ")} ${a.provider.type ?? "(unknown)"}`);
17178
+ if (a.provider.scopes) console.log(` ${import_chalk51.default.dim("scopes ")} ${a.provider.scopes}`);
17179
+ if (a.provider.target_server_token) console.log(` ${import_chalk51.default.dim("sends to API")} ${a.provider.target_server_token}`);
17180
+ console.log(a.provider.managed === true ? import_chalk51.default.dim(" (APIblaze's own GitHub app \u2014 installers get the same zero-config door, nothing to create)") : import_chalk51.default.dim(" (no credentials travel in a recipe \u2014 install asks for your own OAuth app)"));
16825
17181
  } else {
16826
- console.log(import_chalk49.default.dim(" no login provider \u2014 consumers call it with an API key"));
17182
+ console.log(import_chalk51.default.dim(" no login provider \u2014 consumers call it with an API key"));
16827
17183
  }
16828
17184
  if (a.app_client) {
16829
- console.log(` ${import_chalk49.default.dim("login app ")} ${a.app_client.name ?? "(unnamed)"}`);
17185
+ console.log(` ${import_chalk51.default.dim("login app ")} ${a.app_client.name ?? "(unnamed)"}`);
16830
17186
  }
16831
17187
  if (a.key_types?.length) {
16832
- console.log(` ${import_chalk49.default.dim("key types ")} ${a.key_types.map((k) => String(k.name)).join(", ")}`);
17188
+ console.log(` ${import_chalk51.default.dim("key types ")} ${a.key_types.map((k) => String(k.name)).join(", ")}`);
16833
17189
  }
16834
17190
  console.log();
16835
17191
  }
16836
17192
  function printTransforms(recipe) {
16837
17193
  const rules = recipe.transformations?.rules ?? [];
16838
17194
  const tables = recipe.transformations?.mapping_tables ?? [];
16839
- console.log(import_chalk49.default.bold(` transforms (${rules.length})`));
17195
+ console.log(import_chalk51.default.bold(` transforms (${rules.length})`));
16840
17196
  for (const r of rules) {
16841
- const off = r.enabled === false ? import_chalk49.default.dim(" (disabled)") : "";
16842
- console.log(` ${import_chalk49.default.bold(String(r.name ?? "(unnamed)"))} ${import_chalk49.default.dim(String(r.phase ?? "request"))}${off}`);
17197
+ const off = r.enabled === false ? import_chalk51.default.dim(" (disabled)") : "";
17198
+ console.log(` ${import_chalk51.default.bold(String(r.name ?? "(unnamed)"))} ${import_chalk51.default.dim(String(r.phase ?? "request"))}${off}`);
16843
17199
  console.log(indent(JSON.stringify(r.action ?? null, null, 2), " "));
16844
17200
  if (r.condition) console.log(indent(`when ${JSON.stringify(r.condition)}`, " "));
16845
17201
  }
16846
17202
  if (tables.length) {
16847
17203
  console.log();
16848
- console.log(import_chalk49.default.bold(` mapping tables (${tables.length})`));
17204
+ console.log(import_chalk51.default.bold(` mapping tables (${tables.length})`));
16849
17205
  for (const t of tables) {
16850
17206
  const entries2 = Array.isArray(t.entries) ? t.entries.length : 0;
16851
- console.log(` ${import_chalk49.default.bold(String(t.name ?? "(unnamed)"))} ${import_chalk49.default.dim(`${entries2} entr${entries2 === 1 ? "y" : "ies"}`)}`);
17207
+ console.log(` ${import_chalk51.default.bold(String(t.name ?? "(unnamed)"))} ${import_chalk51.default.dim(`${entries2} entr${entries2 === 1 ? "y" : "ies"}`)}`);
16852
17208
  }
16853
17209
  }
16854
17210
  console.log();
@@ -16858,7 +17214,7 @@ function indent(text, pad) {
16858
17214
  }
16859
17215
 
16860
17216
  // src/commands/recipe-install.ts
16861
- var import_chalk50 = __toESM(require("chalk"));
17217
+ var import_chalk52 = __toESM(require("chalk"));
16862
17218
  init_types();
16863
17219
  init_caller();
16864
17220
  init_api();
@@ -16875,7 +17231,7 @@ async function runRecipeInstall(nameArg, opts) {
16875
17231
  const chosenTeamId = picked.chosen ? picked.teamId : void 0;
16876
17232
  const teamName = picked.teamName;
16877
17233
  console.log();
16878
- console.log(`${import_chalk50.default.bold(pinned)}${import_chalk50.default.dim(` \u2014 by ${ref.handle}`)}`);
17234
+ console.log(`${import_chalk52.default.bold(pinned)}${import_chalk52.default.dim(` \u2014 by ${ref.handle}`)}`);
16879
17235
  if (recipe.summary) console.log(` ${recipe.summary}`);
16880
17236
  console.log();
16881
17237
  let project;
@@ -16899,7 +17255,7 @@ async function runRecipeInstall(nameArg, opts) {
16899
17255
  reuseTenant = chosenTenant.existing;
16900
17256
  printSummary(recipe, project, tenant, reuseTenant);
16901
17257
  if (!assumeYes && !await confirmYesNo(" continue?", interactive2)) {
16902
- console.log(import_chalk50.default.yellow(" Cancelled \u2014 nothing was created."));
17258
+ console.log(import_chalk52.default.yellow(" Cancelled \u2014 nothing was created."));
16903
17259
  return;
16904
17260
  }
16905
17261
  }
@@ -16918,18 +17274,18 @@ async function runRecipeInstall(nameArg, opts) {
16918
17274
  process.stdout.write(` ${step.label.padEnd(33)}`);
16919
17275
  try {
16920
17276
  const note = await step.run();
16921
- console.log(`${import_chalk50.default.green("\u2713")}${note ? ` ${import_chalk50.default.dim(note)}` : ""}`);
17277
+ console.log(`${import_chalk52.default.green("\u2713")}${note ? ` ${import_chalk52.default.dim(note)}` : ""}`);
16922
17278
  } catch (err) {
16923
- console.log(`${import_chalk50.default.red("\u2717")} ${import_chalk50.default.red(describeError(err))}`);
17279
+ console.log(`${import_chalk52.default.red("\u2717")} ${import_chalk52.default.red(describeError(err))}`);
16924
17280
  console.log();
16925
17281
  if (step.n === 1) {
16926
- console.log(import_chalk50.default.red(`stopped at step 1 of ${steps.length}. Nothing was created.`));
17282
+ console.log(import_chalk52.default.red(`stopped at step 1 of ${steps.length}. Nothing was created.`));
16927
17283
  console.log("run the same command again once the problem above is fixed:");
16928
- console.log(import_chalk50.default.cyan(` npx apiblaze install ${nameArg}`));
17284
+ console.log(import_chalk52.default.cyan(` npx apiblaze install ${nameArg}`));
16929
17285
  } else {
16930
- console.log(import_chalk50.default.red(`stopped at step ${step.n} of ${steps.length}. ${project} exists but is not finished.`));
17286
+ console.log(import_chalk52.default.red(`stopped at step ${step.n} of ${steps.length}. ${project} exists but is not finished.`));
16931
17287
  console.log("continue with:");
16932
- console.log(import_chalk50.default.cyan(` npx apiblaze install ${nameArg} --into ${project}`));
17288
+ console.log(import_chalk52.default.cyan(` npx apiblaze install ${nameArg} --into ${project}`));
16933
17289
  }
16934
17290
  console.log();
16935
17291
  process.exit(1);
@@ -16939,9 +17295,9 @@ async function runRecipeInstall(nameArg, opts) {
16939
17295
  const urls = installUrls(ctx);
16940
17296
  console.log();
16941
17297
  console.log(`done in ${secs}s.`);
16942
- console.log(` ${import_chalk50.default.dim("proxy ")} ${import_chalk50.default.bold(urls.proxy_url)}`);
16943
- if (recipe.settings.mcp_enabled === true) console.log(` ${import_chalk50.default.dim("mcp ")} ${import_chalk50.default.bold(urls.mcp_url)}`);
16944
- if (recipe.settings.enable_portal === true) console.log(` ${import_chalk50.default.dim("portal")} ${import_chalk50.default.bold(urls.portal_url)}`);
17298
+ console.log(` ${import_chalk52.default.dim("proxy ")} ${import_chalk52.default.bold(urls.proxy_url)}`);
17299
+ if (recipe.settings.mcp_enabled === true) console.log(` ${import_chalk52.default.dim("mcp ")} ${import_chalk52.default.bold(urls.mcp_url)}`);
17300
+ if (recipe.settings.enable_portal === true) console.log(` ${import_chalk52.default.dim("portal")} ${import_chalk52.default.bold(urls.portal_url)}`);
16945
17301
  console.log();
16946
17302
  }
16947
17303
  function buildSteps(inp) {
@@ -17243,7 +17599,7 @@ async function nameIsFree(name, teamId) {
17243
17599
  async function chooseProxyName(slug, asOpt, teamId, interactive2) {
17244
17600
  if (asOpt !== void 0) {
17245
17601
  const name = normalizeName3(asOpt);
17246
- if (name !== asOpt) console.log(import_chalk50.default.yellow(` Using "${name}" \u2014 names are lowercase letters and digits only.`));
17602
+ if (name !== asOpt) console.log(import_chalk52.default.yellow(` Using "${name}" \u2014 names are lowercase letters and digits only.`));
17247
17603
  if (name.length < 3) throw new Error("A proxy name must be at least 3 characters (lowercase letters and digits only).");
17248
17604
  const free = await nameIsFree(name, teamId);
17249
17605
  if (free === false) throw new Error(`"${name}" is already taken. Pick another with --as.`);
@@ -17260,7 +17616,7 @@ async function chooseProxyName(slug, asOpt, teamId, interactive2) {
17260
17616
  }
17261
17617
  if (!interactive2) return suggested;
17262
17618
  const { default: inquirer3 } = await import("inquirer");
17263
- console.log(` ${import_chalk50.default.dim("proxy")} ${slug} \u2192 ${import_chalk50.default.bold(suggested)} ${import_chalk50.default.dim("[enter to accept, or type a name]")}`);
17619
+ console.log(` ${import_chalk52.default.dim("proxy")} ${slug} \u2192 ${import_chalk52.default.bold(suggested)} ${import_chalk52.default.dim("[enter to accept, or type a name]")}`);
17264
17620
  for (; ; ) {
17265
17621
  const { raw } = await inquirer3.prompt([{
17266
17622
  type: "input",
@@ -17271,20 +17627,20 @@ async function chooseProxyName(slug, asOpt, teamId, interactive2) {
17271
17627
  }]);
17272
17628
  const name = normalizeName3(raw);
17273
17629
  if (name !== String(raw).trim()) {
17274
- console.log(import_chalk50.default.yellow(` \u2192 using ${import_chalk50.default.bold(name)} (lowercase letters and digits only)`));
17630
+ console.log(import_chalk52.default.yellow(` \u2192 using ${import_chalk52.default.bold(name)} (lowercase letters and digits only)`));
17275
17631
  }
17276
17632
  if (name.length < 3) {
17277
- console.log(import_chalk50.default.yellow(" Name must be at least 3 characters.\n"));
17633
+ console.log(import_chalk52.default.yellow(" Name must be at least 3 characters.\n"));
17278
17634
  continue;
17279
17635
  }
17280
17636
  const free = await nameIsFree(name, teamId);
17281
17637
  if (free === false) {
17282
- console.log(import_chalk50.default.yellow(` "${name}" is taken. Try another.
17638
+ console.log(import_chalk52.default.yellow(` "${name}" is taken. Try another.
17283
17639
  `));
17284
17640
  continue;
17285
17641
  }
17286
- if (free === null) console.log(import_chalk50.default.dim(" (could not verify availability; continuing)"));
17287
- console.log(` ${import_chalk50.default.cyan("\u2192")} ${import_chalk50.default.bold(`https://${name}.abz.run`)}`);
17642
+ if (free === null) console.log(import_chalk52.default.dim(" (could not verify availability; continuing)"));
17643
+ console.log(` ${import_chalk52.default.cyan("\u2192")} ${import_chalk52.default.bold(`https://${name}.abz.run`)}`);
17288
17644
  return name;
17289
17645
  }
17290
17646
  }
@@ -17302,20 +17658,20 @@ function printSummary(recipe, project, tenant, reuseTenant = false) {
17302
17658
  const keyTypes = recipe.auth?.key_types?.length ?? 0;
17303
17659
  const questions = reuseTenant ? 0 : recipe.questions?.length ?? 0;
17304
17660
  const row = (label3, value, note) => {
17305
- console.log(` ${import_chalk50.default.dim(label3.padEnd(21))}${value}${note ? import_chalk50.default.dim(` ${note}`) : ""}`);
17661
+ console.log(` ${import_chalk52.default.dim(label3.padEnd(21))}${value}${note ? import_chalk52.default.dim(` ${note}`) : ""}`);
17306
17662
  };
17307
17663
  console.log();
17308
- console.log(import_chalk50.default.bold(" This will:"));
17664
+ console.log(import_chalk52.default.bold(" This will:"));
17309
17665
  console.log();
17310
- row("create a proxy", import_chalk50.default.bold(project), `at https://${project}.abz.run`);
17311
- row("for its users", import_chalk50.default.bold(tenant), reuseTenant ? "(one you already have)" : "(a new tenant)");
17666
+ row("create a proxy", import_chalk52.default.bold(project), `at https://${project}.abz.run`);
17667
+ row("for its users", import_chalk52.default.bold(tenant), reuseTenant ? "(one you already have)" : "(a new tenant)");
17312
17668
  if (hosts.length) row("sending requests to", hosts.join(", "));
17313
17669
  row("and set up", describeCreates(keyTypes, routes, recipe.settings.mcp_enabled === true, false));
17314
17670
  row("asking you for", questions ? `${questions} value${questions === 1 ? "" : "s"}` : "nothing");
17315
17671
  if (reuseTenant) {
17316
17672
  console.log();
17317
- console.log(import_chalk50.default.dim(` ${tenant} is used exactly as it is \u2014 its existing login stays, and this`));
17318
- console.log(import_chalk50.default.dim(" recipe's own login setup is not applied."));
17673
+ console.log(import_chalk52.default.dim(` ${tenant} is used exactly as it is \u2014 its existing login stays, and this`));
17674
+ console.log(import_chalk52.default.dim(" recipe's own login setup is not applied."));
17319
17675
  }
17320
17676
  console.log();
17321
17677
  }
@@ -17324,11 +17680,11 @@ function declineAll(items) {
17324
17680
  const upstreams = items.filter((i) => i.kind === "upstream");
17325
17681
  console.log();
17326
17682
  for (const u of upstreams) {
17327
- console.log(import_chalk50.default.yellow(` --yes: this proxy sends every request to ${import_chalk50.default.bold(u.value)}.`));
17683
+ console.log(import_chalk52.default.yellow(` --yes: this proxy sends every request to ${import_chalk52.default.bold(u.value)}.`));
17328
17684
  }
17329
17685
  if (skippable.length) {
17330
- console.log(import_chalk50.default.yellow(` --yes: installing without ${skippable.length} setting${skippable.length === 1 ? "" : "s"} that need consent.`));
17331
- for (const i of skippable) console.log(import_chalk50.default.dim(` skipped ${i.kind} ${i.value}`));
17686
+ console.log(import_chalk52.default.yellow(` --yes: installing without ${skippable.length} setting${skippable.length === 1 ? "" : "s"} that need consent.`));
17687
+ for (const i of skippable) console.log(import_chalk52.default.dim(` skipped ${i.kind} ${i.value}`));
17332
17688
  }
17333
17689
  return new Set(skippable.map(declineKey));
17334
17690
  }
@@ -17349,14 +17705,14 @@ async function askConsent(items, interactive2, reinstalling) {
17349
17705
  const count = items.length;
17350
17706
  const word = ["", "it", "both", "all three", "all four", "all five", "all six"][count] ?? `all ${count}`;
17351
17707
  console.log();
17352
- console.log(import_chalk50.default.yellow(reinstalling ? "\u26A0 This recipe changes who can reach your proxy, what it trusts, and what it can cost." : "\u26A0 The proxy this creates will be reachable by others, trust an upstream host, and can cost you money:"));
17708
+ console.log(import_chalk52.default.yellow(reinstalling ? "\u26A0 This recipe changes who can reach your proxy, what it trusts, and what it can cost." : "\u26A0 The proxy this creates will be reachable by others, trust an upstream host, and can cost you money:"));
17353
17709
  console.log();
17354
17710
  for (const item of items) {
17355
- console.log(` ${import_chalk50.default.bold(item.kind.padEnd(16))} ${item.value}`);
17356
- for (const line of wrapText(item.why, 62)) console.log(` ${" ".repeat(16)} ${import_chalk50.default.dim(line)}`);
17711
+ console.log(` ${import_chalk52.default.bold(item.kind.padEnd(16))} ${item.value}`);
17712
+ for (const line of wrapText(item.why, 62)) console.log(` ${" ".repeat(16)} ${import_chalk52.default.dim(line)}`);
17357
17713
  }
17358
17714
  console.log();
17359
- console.log(`Type "${import_chalk50.default.bold("yes")}" to accept ${word}.`);
17715
+ console.log(`Type "${import_chalk52.default.bold("yes")}" to accept ${word}.`);
17360
17716
  console.log("Press enter to install the recipe without them.");
17361
17717
  let typed = "";
17362
17718
  if (interactive2) {
@@ -17368,7 +17724,7 @@ async function askConsent(items, interactive2, reinstalling) {
17368
17724
  for (const item of items) {
17369
17725
  declined.add(declineKey(item));
17370
17726
  }
17371
- console.log(import_chalk50.default.dim(` Installing without ${count} setting${count === 1 ? "" : "s"} \u2014 everything else is applied.`));
17727
+ console.log(import_chalk52.default.dim(` Installing without ${count} setting${count === 1 ? "" : "s"} \u2014 everything else is applied.`));
17372
17728
  return declined;
17373
17729
  }
17374
17730
  async function askQuestions(questions, ctx, interactive2) {
@@ -17381,13 +17737,13 @@ async function askQuestions(questions, ctx, interactive2) {
17381
17737
  const BOX = 64;
17382
17738
  const title = "\u2500\u2500 from the publisher ";
17383
17739
  console.log();
17384
- console.log(` ${import_chalk50.default.dim(title + "\u2500".repeat(BOX - title.length))}`);
17385
- for (const line of fillContext(q.before, ctx).split("\n")) console.log(` ${import_chalk50.default.dim("\u2502")} ${line}`);
17386
- console.log(` ${import_chalk50.default.dim("\u2500".repeat(BOX))}`);
17740
+ console.log(` ${import_chalk52.default.dim(title + "\u2500".repeat(BOX - title.length))}`);
17741
+ for (const line of fillContext(q.before, ctx).split("\n")) console.log(` ${import_chalk52.default.dim("\u2502")} ${line}`);
17742
+ console.log(` ${import_chalk52.default.dim("\u2500".repeat(BOX))}`);
17387
17743
  }
17388
17744
  if (fromEnv !== void 0 && fromEnv !== "") {
17389
17745
  answers[q.id] = fromEnv;
17390
- console.log(` ${q.prompt}: ${import_chalk50.default.dim(`(from ${envName})`)}`);
17746
+ console.log(` ${q.prompt}: ${import_chalk52.default.dim(`(from ${envName})`)}`);
17391
17747
  continue;
17392
17748
  }
17393
17749
  if (!interactive2) {
@@ -17397,7 +17753,7 @@ async function askQuestions(questions, ctx, interactive2) {
17397
17753
  );
17398
17754
  }
17399
17755
  const { default: inquirer3 } = await import("inquirer");
17400
- if (q.example && !q.secret) console.log(import_chalk50.default.dim(` e.g. ${q.example}`));
17756
+ if (q.example && !q.secret) console.log(import_chalk52.default.dim(` e.g. ${q.example}`));
17401
17757
  const { value } = await inquirer3.prompt([{
17402
17758
  // `secret: true` masks the input — the Google client secret is typed once,
17403
17759
  // goes to provider creation, and is never echoed or stored.
@@ -17431,30 +17787,30 @@ async function confirmReinstall(recipe, project, tenant, interactive2) {
17431
17787
  const tables = recipe.transformations?.mapping_tables?.length ?? 0;
17432
17788
  const routes = countRoutes(recipe.openapi);
17433
17789
  const keyTypes = recipe.auth?.key_types?.length ?? 0;
17434
- console.log(`This installs ${import_chalk50.default.bold(`${recipe.name}@${recipe.revision}`)} over ${import_chalk50.default.bold(project)}.`);
17790
+ console.log(`This installs ${import_chalk52.default.bold(`${recipe.name}@${recipe.revision}`)} over ${import_chalk52.default.bold(project)}.`);
17435
17791
  console.log();
17436
- console.log(` ${import_chalk50.default.dim("settings ".padEnd(16))}replaced`);
17792
+ console.log(` ${import_chalk52.default.dim("settings ".padEnd(16))}replaced`);
17437
17793
  if (rules || tables) {
17438
- console.log(` ${import_chalk50.default.dim("transforms".padEnd(16))}${rules} rule${rules === 1 ? "" : "s"}${tables ? ` and ${tables} mapping table${tables === 1 ? "" : "s"}` : ""} replaced \u2014 your edits to them are lost`);
17794
+ console.log(` ${import_chalk52.default.dim("transforms".padEnd(16))}${rules} rule${rules === 1 ? "" : "s"}${tables ? ` and ${tables} mapping table${tables === 1 ? "" : "s"}` : ""} replaced \u2014 your edits to them are lost`);
17439
17795
  }
17440
17796
  if (routes) {
17441
- console.log(` ${import_chalk50.default.dim("api spec ".padEnd(16))}replaced, ${routes} routes regenerated${recipe.settings.mcp_enabled === true ? ", MCP rebuilt" : ""}`);
17797
+ console.log(` ${import_chalk52.default.dim("api spec ".padEnd(16))}replaced, ${routes} routes regenerated${recipe.settings.mcp_enabled === true ? ", MCP rebuilt" : ""}`);
17442
17798
  }
17443
17799
  if (keyTypes) {
17444
- console.log(` ${import_chalk50.default.dim("key types ".padEnd(16))}${keyTypes} added if missing; existing types left alone`);
17800
+ console.log(` ${import_chalk52.default.dim("key types ".padEnd(16))}${keyTypes} added if missing; existing types left alone`);
17445
17801
  }
17446
17802
  console.log();
17447
- console.log(` ${import_chalk50.default.dim("unchanged ".padEnd(16))}your API keys, your proxy URL, your users,`);
17803
+ console.log(` ${import_chalk52.default.dim("unchanged ".padEnd(16))}your API keys, your proxy URL, your users,`);
17448
17804
  console.log(` ${" ".repeat(16)}and any tenant other than ${tenant}`);
17449
17805
  console.log();
17450
- console.log(import_chalk50.default.yellow("This cannot be undone."));
17806
+ console.log(import_chalk52.default.yellow("This cannot be undone."));
17451
17807
  if (!interactive2) {
17452
17808
  throw new Error("Reinstall needs a typed confirmation and there is no terminal to ask on.");
17453
17809
  }
17454
17810
  const { default: inquirer3 } = await import("inquirer");
17455
17811
  const { typed } = await inquirer3.prompt([{ type: "input", name: "typed", message: `Type the proxy name (${project}) to continue:` }]);
17456
17812
  if (String(typed ?? "").trim() !== project) {
17457
- console.log(import_chalk50.default.yellow("Cancelled \u2014 nothing was changed."));
17813
+ console.log(import_chalk52.default.yellow("Cancelled \u2014 nothing was changed."));
17458
17814
  process.exit(0);
17459
17815
  }
17460
17816
  }
@@ -17462,7 +17818,7 @@ function requireCallerForInstall() {
17462
17818
  try {
17463
17819
  return requireCaller();
17464
17820
  } catch {
17465
- console.error(import_chalk50.default.red(
17821
+ console.error(import_chalk52.default.red(
17466
17822
  "Installing writes a proxy into an account, so it needs a credential.\n Run `apiblaze login`, or `apiblaze create` first (an anonymous workspace works too)."
17467
17823
  ));
17468
17824
  process.exit(1);
@@ -17498,7 +17854,7 @@ async function chooseTeam(caller, optTeam, interactive2) {
17498
17854
  message: " which team should own this proxy?",
17499
17855
  default: active.teamId,
17500
17856
  choices: teams.map((t) => ({
17501
- name: t.teamId === active.teamId ? `${t.name} ${import_chalk50.default.dim("(active)")}` : t.name,
17857
+ name: t.teamId === active.teamId ? `${t.name} ${import_chalk52.default.dim("(active)")}` : t.name,
17502
17858
  value: t.teamId
17503
17859
  }))
17504
17860
  }]);
@@ -17526,10 +17882,10 @@ async function chooseTenant(caller, project, teamId, optTenant, interactive2) {
17526
17882
  message: " where should this proxy's users live?",
17527
17883
  default: "__new__",
17528
17884
  choices: [
17529
- { name: `create ${fresh} ${import_chalk50.default.dim("(a fresh tenant, set up by the recipe)")}`, value: "__new__" },
17530
- new inquirer3.Separator(import_chalk50.default.dim(" \u2014 or reuse one you already have \u2014")),
17885
+ { name: `create ${fresh} ${import_chalk52.default.dim("(a fresh tenant, set up by the recipe)")}`, value: "__new__" },
17886
+ new inquirer3.Separator(import_chalk52.default.dim(" \u2014 or reuse one you already have \u2014")),
17531
17887
  ...owned.map((t2) => ({
17532
- name: `${t2} ${import_chalk50.default.dim("(existing \u2014 its own login is kept)")}`,
17888
+ name: `${t2} ${import_chalk52.default.dim("(existing \u2014 its own login is kept)")}`,
17533
17889
  value: t2
17534
17890
  }))
17535
17891
  ]
@@ -17559,8 +17915,8 @@ async function teamTenants(caller, teamId) {
17559
17915
  }
17560
17916
 
17561
17917
  // src/commands/recipe-publish.ts
17562
- var import_chalk51 = __toESM(require("chalk"));
17563
- var import_ora17 = __toESM(require("ora"));
17918
+ var import_chalk53 = __toESM(require("chalk"));
17919
+ var import_ora19 = __toESM(require("ora"));
17564
17920
  init_caller();
17565
17921
  init_auth();
17566
17922
  async function runRecipePublish(projectArg, opts) {
@@ -17569,22 +17925,22 @@ async function runRecipePublish(projectArg, opts) {
17569
17925
  try {
17570
17926
  resolved = resolveRecipeName(opts.as, creds?.githubHandle, normalizeName3(projectArg));
17571
17927
  } catch (err) {
17572
- console.error(import_chalk51.default.red(err instanceof Error ? err.message : String(err)));
17928
+ console.error(import_chalk53.default.red(err instanceof Error ? err.message : String(err)));
17573
17929
  process.exitCode = 1;
17574
17930
  return;
17575
17931
  }
17576
17932
  const ref = resolved.ref;
17577
17933
  if (resolved.derivedHandle) {
17578
- console.log(import_chalk51.default.dim(` publishing as ${import_chalk51.default.bold(ref.name)}`));
17934
+ console.log(import_chalk53.default.dim(` publishing as ${import_chalk53.default.bold(ref.name)}`));
17579
17935
  if (resolved.normalizedFrom) {
17580
- console.log(import_chalk51.default.dim(` (your GitHub login is ${resolved.normalizedFrom}; apiblaze names are letters and digits only)`));
17936
+ console.log(import_chalk53.default.dim(` (your GitHub login is ${resolved.normalizedFrom}; apiblaze names are letters and digits only)`));
17581
17937
  }
17582
17938
  }
17583
17939
  const interactive2 = !!process.stdin.isTTY && !opts.json;
17584
17940
  const caller = requireCaller();
17585
17941
  const { teamId } = await resolveActingTeam(caller, opts.team);
17586
17942
  const proj2 = await resolveProjectVia(caller, teamId, projectArg, opts.apiversion);
17587
- const spinner = !opts.json ? (0, import_ora17.default)(`Reading ${proj2.projectId} v${proj2.apiVersion}...`).start() : null;
17943
+ const spinner = !opts.json ? (0, import_ora19.default)(`Reading ${proj2.projectId} v${proj2.apiVersion}...`).start() : null;
17588
17944
  let prep;
17589
17945
  try {
17590
17946
  prep = await prepare(caller, proj2.projectId, proj2.apiVersion, ref.name, opts.tenant);
@@ -17596,7 +17952,7 @@ async function runRecipePublish(projectArg, opts) {
17596
17952
  let tenant = opts.tenant;
17597
17953
  if (!prep.tenant_used && prep.tenants.length > 1) {
17598
17954
  if (!interactive2) {
17599
- console.error(import_chalk51.default.red(
17955
+ console.error(import_chalk53.default.red(
17600
17956
  `${proj2.projectId} has ${prep.tenants.length} tenants (${prep.tenants.join(", ")}). Pass --tenant <slug> to say which auth setup the recipe carries.`
17601
17957
  ));
17602
17958
  process.exit(1);
@@ -17612,7 +17968,7 @@ async function runRecipePublish(projectArg, opts) {
17612
17968
  prep = await prepare(caller, proj2.projectId, proj2.apiVersion, ref.name, tenant);
17613
17969
  }
17614
17970
  if (!prep.name_available) {
17615
- console.error(import_chalk51.default.red(`${ref.name} belongs to another team, so you cannot publish a revision of it.`));
17971
+ console.error(import_chalk53.default.red(`${ref.name} belongs to another team, so you cannot publish a revision of it.`));
17616
17972
  process.exit(1);
17617
17973
  }
17618
17974
  if (prep.envelope_violations.length) {
@@ -17622,13 +17978,13 @@ async function runRecipePublish(projectArg, opts) {
17622
17978
  if (prep.dropped.length) {
17623
17979
  console.log();
17624
17980
  console.log(`${prep.dropped.length} setting${prep.dropped.length === 1 ? " was" : "s were"} not included, because they are not on the publish list:`);
17625
- for (const d of prep.dropped) console.log(import_chalk51.default.dim(` ${d}`));
17981
+ for (const d of prep.dropped) console.log(import_chalk53.default.dim(` ${d}`));
17626
17982
  if (prep.hidden_tables_excluded) {
17627
- console.log(import_chalk51.default.dim(` (${prep.hidden_tables_excluded} hidden mapping table${prep.hidden_tables_excluded === 1 ? "" : "s"} excluded \u2014 those values belong to your consumers.)`));
17983
+ console.log(import_chalk53.default.dim(` (${prep.hidden_tables_excluded} hidden mapping table${prep.hidden_tables_excluded === 1 ? "" : "s"} excluded \u2014 those values belong to your consumers.)`));
17628
17984
  }
17629
17985
  console.log();
17630
17986
  if (!opts.yes && !await confirm2(" continue without them?", interactive2)) {
17631
- console.log(import_chalk51.default.yellow("Cancelled."));
17987
+ console.log(import_chalk53.default.yellow("Cancelled."));
17632
17988
  return;
17633
17989
  }
17634
17990
  }
@@ -17641,12 +17997,12 @@ async function runRecipePublish(projectArg, opts) {
17641
17997
  console.log();
17642
17998
  for (const f2 of prep.findings) printFinding(f2);
17643
17999
  console.log();
17644
- console.error(import_chalk51.default.red("--yes cannot accept scanner findings. Fix the value in the proxy, or publish interactively and decide."));
18000
+ console.error(import_chalk53.default.red("--yes cannot accept scanner findings. Fix the value in the proxy, or publish interactively and decide."));
17645
18001
  process.exit(1);
17646
18002
  }
17647
18003
  if (!interactive2) {
17648
18004
  for (const f2 of prep.findings) printFinding(f2);
17649
- console.error(import_chalk51.default.red("\nThese need a decision and there is no terminal to ask on."));
18005
+ console.error(import_chalk53.default.red("\nThese need a decision and there is no terminal to ask on."));
17650
18006
  process.exit(1);
17651
18007
  }
17652
18008
  const { default: inquirer3 } = await import("inquirer");
@@ -17667,10 +18023,10 @@ async function runRecipePublish(projectArg, opts) {
17667
18023
  if (verdict === "ask") promotions.push(await askPromotion(f2.path));
17668
18024
  }
17669
18025
  }
17670
- console.log(import_chalk51.default.dim(`we cannot judge the other ${prep.unjudged_count} values. run \`apiblaze show ${ref.name}\` after publishing to read the whole recipe.`));
18026
+ console.log(import_chalk53.default.dim(`we cannot judge the other ${prep.unjudged_count} values. run \`apiblaze show ${ref.name}\` after publishing to read the whole recipe.`));
17671
18027
  const totalQuestions = prep.question_ids.length + promotions.length;
17672
18028
  if (totalQuestions > 5) {
17673
- console.log(import_chalk51.default.yellow(`
18029
+ console.log(import_chalk53.default.yellow(`
17674
18030
  \u26A0 installers will have to supply ${totalQuestions} values before this works.`));
17675
18031
  }
17676
18032
  const visibility = opts.private ? "private" : "public";
@@ -17678,15 +18034,15 @@ async function runRecipePublish(projectArg, opts) {
17678
18034
  if (visibility === "public" && prep.spec_will_become_public) {
17679
18035
  console.log();
17680
18036
  console.log("Publishing publicly also makes this API's spec readable at");
17681
- console.log(` ${import_chalk51.default.bold(`https://${proj2.projectId}.abz.run/${proj2.apiVersion}/openapi.json`)}`);
18037
+ console.log(` ${import_chalk53.default.bold(`https://${proj2.projectId}.abz.run/${proj2.apiVersion}/openapi.json`)}`);
17682
18038
  console.log("It is currently private.");
17683
18039
  confirmSpecPublic = opts.yes ? true : await confirm2("Continue?", interactive2);
17684
18040
  if (!confirmSpecPublic) {
17685
- console.log(import_chalk51.default.yellow("Cancelled \u2014 nothing was published."));
18041
+ console.log(import_chalk53.default.yellow("Cancelled \u2014 nothing was published."));
17686
18042
  return;
17687
18043
  }
17688
18044
  }
17689
- const spin2 = !opts.json ? (0, import_ora17.default)(`Publishing ${ref.name}...`).start() : null;
18045
+ const spin2 = !opts.json ? (0, import_ora19.default)(`Publishing ${ref.name}...`).start() : null;
17690
18046
  let out;
17691
18047
  try {
17692
18048
  out = await producer(caller, {
@@ -17708,7 +18064,7 @@ async function runRecipePublish(projectArg, opts) {
17708
18064
  },
17709
18065
  summary: `Publish ${proj2.projectId} as ${ref.name} (${visibility})`
17710
18066
  });
17711
- spin2?.succeed(`Published ${import_chalk51.default.bold(`${out.name}@${out.revision}`)} (${out.visibility}).`);
18067
+ spin2?.succeed(`Published ${import_chalk53.default.bold(`${out.name}@${out.revision}`)} (${out.visibility}).`);
17712
18068
  } catch (err) {
17713
18069
  spin2?.fail("Publish failed.");
17714
18070
  throw err;
@@ -17717,15 +18073,15 @@ async function runRecipePublish(projectArg, opts) {
17717
18073
  console.log(JSON.stringify(out));
17718
18074
  return;
17719
18075
  }
17720
- console.log(` ${import_chalk51.default.dim("size ")} ${(out.size_bytes / 1024).toFixed(1)} KB`);
17721
- console.log(` ${import_chalk51.default.dim("checksum")} ${out.sha256.slice(0, 16)}\u2026`);
18076
+ console.log(` ${import_chalk53.default.dim("size ")} ${(out.size_bytes / 1024).toFixed(1)} KB`);
18077
+ console.log(` ${import_chalk53.default.dim("checksum")} ${out.sha256.slice(0, 16)}\u2026`);
17722
18078
  console.log();
17723
18079
  if (out.visibility === "public") {
17724
- console.log(import_chalk51.default.dim(` Anyone can now run: ${import_chalk51.default.cyan(`npx apiblaze install ${out.name}`)}`));
18080
+ console.log(import_chalk53.default.dim(` Anyone can now run: ${import_chalk53.default.cyan(`npx apiblaze install ${out.name}`)}`));
17725
18081
  } else {
17726
- console.log(import_chalk51.default.dim(" Private \u2014 only members of this team can see or install it."));
18082
+ console.log(import_chalk53.default.dim(" Private \u2014 only members of this team can see or install it."));
17727
18083
  }
17728
- console.log(import_chalk51.default.dim(` Pull it back with: ${import_chalk51.default.cyan(`npx apiblaze withdraw ${out.name}@${out.revision}`)}`));
18084
+ console.log(import_chalk53.default.dim(` Pull it back with: ${import_chalk53.default.cyan(`npx apiblaze withdraw ${out.name}@${out.revision}`)}`));
17729
18085
  console.log();
17730
18086
  }
17731
18087
  async function prepare(caller, projectId, apiVersion, name, tenant) {
@@ -17738,23 +18094,23 @@ async function prepare(caller, projectId, apiVersion, name, tenant) {
17738
18094
  }
17739
18095
  function printFinding(f2) {
17740
18096
  const preview = (f2.preview ?? "").replace(/\s+/g, " ").trim();
17741
- console.log(` ${import_chalk51.default.bold(f2.path)}`);
17742
- console.log(` ${import_chalk51.default.yellow(preview.padEnd(38))}${import_chalk51.default.dim(f2.why)}`);
18097
+ console.log(` ${import_chalk53.default.bold(f2.path)}`);
18098
+ console.log(` ${import_chalk53.default.yellow(preview.padEnd(38))}${import_chalk53.default.dim(f2.why)}`);
17743
18099
  }
17744
18100
  function printEnvelopeViolations(violations) {
17745
18101
  console.log();
17746
- console.error(import_chalk51.default.red("This proxy has transform rules a recipe cannot carry."));
18102
+ console.error(import_chalk53.default.red("This proxy has transform rules a recipe cannot carry."));
17747
18103
  console.log();
17748
18104
  for (const v of violations) {
17749
- console.log(` ${import_chalk51.default.bold(v.rule)} ${import_chalk51.default.dim(`(${v.kind}s ${v.field})`)}`);
18105
+ console.log(` ${import_chalk53.default.bold(v.rule)} ${import_chalk53.default.dim(`(${v.kind}s ${v.field})`)}`);
17750
18106
  console.log(` ${v.why}`);
17751
18107
  }
17752
18108
  console.log();
17753
18109
  console.log("A recipe runs in a stranger's account, after apiblaze has attached their end user's");
17754
18110
  console.log("real third-party token, so two rules are absolute:");
17755
- console.log(` ${import_chalk51.default.dim("\u2022")} a rule may never READ Authorization, Cookie, or the third-party token headers \u2014`);
18111
+ console.log(` ${import_chalk53.default.dim("\u2022")} a rule may never READ Authorization, Cookie, or the third-party token headers \u2014`);
17756
18112
  console.log(" those hold a live credential that works at the provider without apiblaze;");
17757
- console.log(` ${import_chalk51.default.dim("\u2022")} a rule may never WRITE an identity header (x-end-user-id and friends) \u2014`);
18113
+ console.log(` ${import_chalk53.default.dim("\u2022")} a rule may never WRITE an identity header (x-end-user-id and friends) \u2014`);
17758
18114
  console.log(" those tell the installer's own backend who is calling.");
17759
18115
  console.log();
17760
18116
  console.log("Writing Authorization from a question or a fixed value is fine \u2014 that is the");
@@ -17772,7 +18128,7 @@ async function askPromotion(path20) {
17772
18128
  { type: "input", name: "id", message: " id:", default: suggestedId }
17773
18129
  ]);
17774
18130
  const id = String(answers.id || suggestedId).toLowerCase().replace(/[^a-z0-9_]/g, "_");
17775
- console.log(import_chalk51.default.dim(` \u2192 replaced with {{${id}}}`));
18131
+ console.log(import_chalk53.default.dim(` \u2192 replaced with {{${id}}}`));
17776
18132
  return {
17777
18133
  path: path20,
17778
18134
  id,
@@ -17791,7 +18147,7 @@ async function confirm2(message, interactive2) {
17791
18147
  async function runRecipeWithdraw(nameArg, opts) {
17792
18148
  const ref = parseRecipeRef(nameArg);
17793
18149
  if (ref.revision === void 0) {
17794
- console.error(import_chalk51.default.red(`Name the revision to withdraw, e.g. ${nameArg}@3. Revisions are withdrawn one at a time.`));
18150
+ console.error(import_chalk53.default.red(`Name the revision to withdraw, e.g. ${nameArg}@3. Revisions are withdrawn one at a time.`));
17795
18151
  process.exit(1);
17796
18152
  }
17797
18153
  const interactive2 = !!process.stdin.isTTY && !opts.json;
@@ -17811,14 +18167,14 @@ async function runRecipeWithdraw(nameArg, opts) {
17811
18167
  const { default: inquirer3 } = await import("inquirer");
17812
18168
  const { typed } = await inquirer3.prompt([{ type: "input", name: "typed", message: `type the recipe name to confirm (${ref.name}):` }]);
17813
18169
  if (String(typed ?? "").trim() !== ref.name) {
17814
- console.log(import_chalk51.default.yellow("Cancelled \u2014 nothing was withdrawn."));
18170
+ console.log(import_chalk53.default.yellow("Cancelled \u2014 nothing was withdrawn."));
17815
18171
  return;
17816
18172
  }
17817
18173
  } else {
17818
- console.error(import_chalk51.default.red("Withdrawing needs a typed confirmation and there is no terminal to ask on."));
18174
+ console.error(import_chalk53.default.red("Withdrawing needs a typed confirmation and there is no terminal to ask on."));
17819
18175
  process.exit(1);
17820
18176
  }
17821
- const spinner = !opts.json ? (0, import_ora17.default)("Withdrawing...").start() : null;
18177
+ const spinner = !opts.json ? (0, import_ora19.default)("Withdrawing...").start() : null;
17822
18178
  let out;
17823
18179
  try {
17824
18180
  out = await producer(caller, {
@@ -17847,7 +18203,7 @@ async function runRecipeWithdraw(nameArg, opts) {
17847
18203
  init_logs();
17848
18204
 
17849
18205
  // src/commands/consumer-logs.ts
17850
- var import_chalk52 = __toESM(require("chalk"));
18206
+ var import_chalk54 = __toESM(require("chalk"));
17851
18207
  init_auth();
17852
18208
  init_consumer_auth();
17853
18209
  init_log_view();
@@ -17855,9 +18211,9 @@ var CONSUMER_LOGS_BASE = process.env.APIBLAZE_CONSUMER_LOGS_BASE || "https://log
17855
18211
  function requireConsumer() {
17856
18212
  const c = loadConsumer();
17857
18213
  if (!c) {
17858
- console.error(import_chalk52.default.red("Not logged in as an API Consumer. Run `apiblaze consumer login` first."));
18214
+ console.error(import_chalk54.default.red("Not logged in as an API Consumer. Run `apiblaze consumer login` first."));
17859
18215
  if (loadCredentials()) {
17860
- console.error(import_chalk52.default.dim("You're signed in as an API Producer \u2014 for a proxy's full logs run `apiblaze logs <project>`."));
18216
+ console.error(import_chalk54.default.dim("You're signed in as an API Producer \u2014 for a proxy's full logs run `apiblaze logs <project>`."));
17861
18217
  }
17862
18218
  process.exit(1);
17863
18219
  }
@@ -17888,7 +18244,7 @@ async function consumerLogsFetch(session, suffix, init) {
17888
18244
  return data;
17889
18245
  }
17890
18246
  function otherPlaneHint2() {
17891
- if (loadCredentials()) console.log(import_chalk52.default.dim(" \u2039producer view: apiblaze logs <project>\u203A"));
18247
+ if (loadCredentials()) console.log(import_chalk54.default.dim(" \u2039producer view: apiblaze logs <project>\u203A"));
17892
18248
  }
17893
18249
  function fetchWindow2(session, project) {
17894
18250
  return (params) => {
@@ -17904,8 +18260,8 @@ function fetchWindow2(session, project) {
17904
18260
  async function runConsumerLogsTail(opts) {
17905
18261
  const session = requireConsumer();
17906
18262
  if (!opts.json) {
17907
- console.log(import_chalk52.default.bold("API Consumer logs") + import_chalk52.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
17908
- console.log(import_chalk52.default.dim("cost and upstream details are producer-only and are not sent"));
18263
+ console.log(import_chalk54.default.bold("API Consumer logs") + import_chalk54.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
18264
+ console.log(import_chalk54.default.dim("cost and upstream details are producer-only and are not sent"));
17909
18265
  otherPlaneHint2();
17910
18266
  }
17911
18267
  await runTailSession({
@@ -17923,8 +18279,8 @@ async function runConsumerLogsTail(opts) {
17923
18279
  async function runConsumerLogsList(opts) {
17924
18280
  const session = requireConsumer();
17925
18281
  if (!opts.json) {
17926
- console.log(import_chalk52.default.bold("API Consumer logs") + import_chalk52.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
17927
- console.log(import_chalk52.default.dim("cost and upstream details are producer-only and are not sent"));
18282
+ console.log(import_chalk54.default.bold("API Consumer logs") + import_chalk54.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
18283
+ console.log(import_chalk54.default.dim("cost and upstream details are producer-only and are not sent"));
17928
18284
  otherPlaneHint2();
17929
18285
  console.log("");
17930
18286
  }
@@ -17937,71 +18293,12 @@ async function runConsumerLogsList(opts) {
17937
18293
  });
17938
18294
  }
17939
18295
 
17940
- // src/commands/config.ts
17941
- var import_chalk53 = __toESM(require("chalk"));
17942
- var import_ora18 = __toESM(require("ora"));
17943
- init_caller();
17944
- init_paging();
17945
- async function patchConfig(project, opts, body, summary) {
17946
- const caller = requireCaller();
17947
- const { teamId } = await resolveActingTeam(caller, opts.team);
17948
- const proj2 = await resolveProjectVia(caller, teamId, project, opts.apiversion);
17949
- const spinner = (0, import_ora18.default)(summary + "...").start();
17950
- try {
17951
- const out = await producer(caller, {
17952
- method: "PATCH",
17953
- path: `/projects/${proj2.projectId}/${proj2.apiVersion}`,
17954
- body,
17955
- summary
17956
- });
17957
- spinner.succeed(`${summary} \u2014 ${proj2.projectName} v${proj2.apiVersion}.`);
17958
- if (opts.json) console.log(JSON.stringify(out ?? { ok: true }));
17959
- } catch (err) {
17960
- spinner.fail(summary + " failed.");
17961
- throw err;
17962
- }
17963
- }
17964
- async function runTargetSet(project, opts) {
17965
- if (!opts.url) {
17966
- console.error(import_chalk53.default.red("--url is required."));
17967
- process.exit(1);
17968
- }
17969
- if (!opts.env) {
17970
- await patchConfig(project, opts, { target_url: opts.url }, `Set target \u2192 ${opts.url}`);
17971
- return;
17972
- }
17973
- const caller = requireCaller();
17974
- const { teamId } = await resolveActingTeam(caller, opts.team);
17975
- const proj2 = await resolveProjectVia(caller, teamId, project, opts.apiversion);
17976
- const listing = await pageAll(
17977
- (cursor) => producer(caller, {
17978
- method: "GET",
17979
- path: withPage(`/projects?team_id=${encodeURIComponent(teamId)}`, cursor),
17980
- summary: `Read environments for ${proj2.projectName}`
17981
- }),
17982
- (b) => b?.projects
17983
- );
17984
- const row = listing.items.find((r) => r.project_id === proj2.projectId && r.api_version === proj2.apiVersion);
17985
- const current = row?.config?.environments;
17986
- const existing = current && typeof current === "object" && !Array.isArray(current) ? current : {};
17987
- const prev = existing[opts.env];
17988
- const environments = {
17989
- ...existing,
17990
- [opts.env]: { ...prev && typeof prev === "object" ? prev : {}, target: opts.url }
17991
- };
17992
- await patchConfig(project, opts, { environments }, `Set target for env ${opts.env} \u2192 ${opts.url}`);
17993
- }
17994
- async function runRename(project, opts) {
17995
- if (!opts.displayName) {
17996
- console.error(import_chalk53.default.red("--display-name is required."));
17997
- process.exit(1);
17998
- }
17999
- await patchConfig(project, opts, { display_name: opts.displayName }, `Rename \u2192 "${opts.displayName}"`);
18000
- }
18296
+ // src/cli.ts
18297
+ init_config();
18001
18298
 
18002
18299
  // src/commands/limits.ts
18003
- var import_chalk54 = __toESM(require("chalk"));
18004
- var import_ora19 = __toESM(require("ora"));
18300
+ var import_chalk55 = __toESM(require("chalk"));
18301
+ var import_ora20 = __toESM(require("ora"));
18005
18302
  init_caller();
18006
18303
  init_admin();
18007
18304
  init_resolve();
@@ -18099,18 +18396,18 @@ function renderLimits(r, name) {
18099
18396
  const cred = l.credentialQuota ? `${l.credentialQuota.limit.toLocaleString()} per key (${l.credentialQuota.period})` : "(none)";
18100
18397
  const cap2 = typeof l.spendCapUnits === "number" ? usd(Math.round(l.spendCapUnits / LEDGER_UNITS_PER_CENT)) + " / month" : "(none)";
18101
18398
  const lines = [
18102
- `${import_chalk54.default.bold(name)}${r.api_version ? import_chalk54.default.dim(` v${r.api_version}`) : ""}${r.anonymous ? import_chalk54.default.dim(" (anonymous workspace)") : ""}`,
18399
+ `${import_chalk55.default.bold(name)}${r.api_version ? import_chalk55.default.dim(` v${r.api_version}`) : ""}${r.anonymous ? import_chalk55.default.dim(" (anonymous workspace)") : ""}`,
18103
18400
  // Standard is the only mode; a stored `strict` (pre-2026-09-29 config) is
18104
18401
  // served as standard by the API, and named as such here.
18105
- ` ${"mode".padEnd(18)} standard${l.mode === "strict" ? " (legacy strict setting)" : ""}${import_chalk54.default.dim(" per consumer key, approximate per location")}`,
18106
- ` ${"rate limit".padEnd(18)} ${ladder(l.consumerRps, t.consumerRps)}${import_chalk54.default.dim(" per consumer key")}`,
18107
- ` ${"end-user rate".padEnd(18)} ${ladder(l.endUserRps, t.endUserRps)}${import_chalk54.default.dim(" per X-End-User-Id")}`,
18108
- ` ${"ceiling".padEnd(18)} ${ladder(l.ceilingRps, t.ceilingRps)}${import_chalk54.default.dim(` whole proxy \xB7 read-only${typeof r.self_serve_ceiling_rps === "number" ? `, self-serve up to ${r.self_serve_ceiling_rps}/s` : ""}`)}`,
18109
- ` ${"quota".padEnd(18)} ${quota}${import_chalk54.default.dim(" fixed UTC windows")}`,
18402
+ ` ${"mode".padEnd(18)} standard${l.mode === "strict" ? " (legacy strict setting)" : ""}${import_chalk55.default.dim(" per consumer key, approximate per location")}`,
18403
+ ` ${"rate limit".padEnd(18)} ${ladder(l.consumerRps, t.consumerRps)}${import_chalk55.default.dim(" per consumer key")}`,
18404
+ ` ${"end-user rate".padEnd(18)} ${ladder(l.endUserRps, t.endUserRps)}${import_chalk55.default.dim(" per X-End-User-Id")}`,
18405
+ ` ${"ceiling".padEnd(18)} ${ladder(l.ceilingRps, t.ceilingRps)}${import_chalk55.default.dim(` whole proxy \xB7 read-only${typeof r.self_serve_ceiling_rps === "number" ? `, self-serve up to ${r.self_serve_ceiling_rps}/s` : ""}`)}`,
18406
+ ` ${"quota".padEnd(18)} ${quota}${import_chalk55.default.dim(" fixed UTC windows")}`,
18110
18407
  ` ${"spend cap".padEnd(18)} ${cap2}`,
18111
18408
  ` ${"credential quota".padEnd(18)} ${cred}`
18112
18409
  ];
18113
- if (typeof l.configVersion === "number") lines.push(import_chalk54.default.dim(` config version ${l.configVersion} \xB7 edits bind within 30 s, no reset on edit`));
18410
+ if (typeof l.configVersion === "number") lines.push(import_chalk55.default.dim(` config version ${l.configVersion} \xB7 edits bind within 30 s, no reset on edit`));
18114
18411
  return lines;
18115
18412
  }
18116
18413
  async function resolve2(project, opts) {
@@ -18129,7 +18426,7 @@ async function runLimitsGet(project, opts) {
18129
18426
  if (opts.json) return void console.log(JSON.stringify(r, null, 2));
18130
18427
  console.log("");
18131
18428
  for (const l of renderLimits(r, proj2.projectName)) console.log(l);
18132
- console.log(import_chalk54.default.dim(`
18429
+ console.log(import_chalk55.default.dim(`
18133
18430
  Change: ${B.cli} limits set ${proj2.projectName} --rate <n> [--end-user-rate <n>] [--quota <n> --period daily|weekly|monthly] [--spend-cap <usd>]
18134
18431
  `));
18135
18432
  }
@@ -18139,7 +18436,7 @@ async function runLimitsSet(project, opts) {
18139
18436
  const needsCurrent = opts.quota !== void 0 && opts.period === void 0 || opts.period !== void 0 && opts.quota === void 0 || opts.credentialQuota !== void 0;
18140
18437
  const current = needsCurrent ? (await getLimits(caller, proj2).catch(() => null))?.limits ?? null : null;
18141
18438
  const body = buildLimitsPatch(opts, current);
18142
- const spinner = (0, import_ora19.default)(`Update limits for ${proj2.projectName}...`).start();
18439
+ const spinner = (0, import_ora20.default)(`Update limits for ${proj2.projectName}...`).start();
18143
18440
  let r;
18144
18441
  try {
18145
18442
  r = await producer(caller, { method: "PUT", path: limitsPath(proj2), body, summary: `Set limits ${JSON.stringify(body)}` });
@@ -18155,9 +18452,9 @@ async function runLimitsSet(project, opts) {
18155
18452
  console.log(JSON.stringify({ error: inner.error ?? b.error, details: inner.details ?? b.details, max_self_serve_rps: inner.max_self_serve_rps ?? b.max_self_serve_rps, request_ceiling: hint, command: cmd }));
18156
18453
  process.exit(1);
18157
18454
  }
18158
- console.log(import_chalk54.default.yellow(` ${inner.details ?? b.details ?? inner.error ?? b.error ?? "That ceiling needs approval."}`));
18159
- if (typeof (inner.max_self_serve_rps ?? b.max_self_serve_rps) === "number") console.log(import_chalk54.default.dim(` Self-serve ceiling: ${inner.max_self_serve_rps ?? b.max_self_serve_rps}/s. Above that an operator approves.`));
18160
- console.log(` Request it: ${import_chalk54.default.cyan(cmd)}`);
18455
+ console.log(import_chalk55.default.yellow(` ${inner.details ?? b.details ?? inner.error ?? b.error ?? "That ceiling needs approval."}`));
18456
+ if (typeof (inner.max_self_serve_rps ?? b.max_self_serve_rps) === "number") console.log(import_chalk55.default.dim(` Self-serve ceiling: ${inner.max_self_serve_rps ?? b.max_self_serve_rps}/s. Above that an operator approves.`));
18457
+ console.log(` Request it: ${import_chalk55.default.cyan(cmd)}`);
18161
18458
  process.exit(1);
18162
18459
  }
18163
18460
  }
@@ -18167,7 +18464,7 @@ async function runLimitsSet(project, opts) {
18167
18464
  if (opts.json) return void console.log(JSON.stringify(r, null, 2));
18168
18465
  for (const l of renderLimits(r, proj2.projectName)) console.log(l);
18169
18466
  if (resolveCaller()?.mode === "anon") {
18170
- console.log(import_chalk54.default.dim(" Anonymous workspace: rates are capped at the anonymous ceiling until you claim it (`apiblaze login`, then `apiblaze claim`)."));
18467
+ console.log(import_chalk55.default.dim(" Anonymous workspace: rates are capped at the anonymous ceiling until you claim it (`apiblaze login`, then `apiblaze claim`)."));
18171
18468
  }
18172
18469
  console.log("");
18173
18470
  }
@@ -18176,7 +18473,7 @@ async function runLimitsRequestMax(project, opts) {
18176
18473
  if (rps === void 0) throw new UsageError("--rps <n> is required: the ceiling you are asking for, in requests per second.");
18177
18474
  const { caller, proj: proj2 } = await resolve2(project, opts);
18178
18475
  const body = { requested_rps: rps, ...opts.useCase ? { use_case: opts.useCase } : {} };
18179
- const spinner = (0, import_ora19.default)(`Request a ${rps}/s ceiling for ${proj2.projectName}...`).start();
18476
+ const spinner = (0, import_ora20.default)(`Request a ${rps}/s ceiling for ${proj2.projectName}...`).start();
18180
18477
  let r;
18181
18478
  try {
18182
18479
  r = await producer(caller, { method: "POST", path: `${limitsPath(proj2)}/ceiling-request`, body, summary: `Request ceiling ${rps}/s` });
@@ -18186,8 +18483,8 @@ async function runLimitsRequestMax(project, opts) {
18186
18483
  }
18187
18484
  spinner.succeed(`Requested: ${ladder(rps)} for ${proj2.projectName}.`);
18188
18485
  if (opts.json) return void console.log(JSON.stringify(r ?? { accepted: true, requested_rps: rps }, null, 2));
18189
- console.log(import_chalk54.default.dim(" Up to 1,000/s is granted instantly to a proven wallet; above that an operator approves (1k / 10k / 100k presets)."));
18190
- console.log(import_chalk54.default.dim(` Check: ${B.cli} limits get ${proj2.projectName}
18486
+ console.log(import_chalk55.default.dim(" Up to 1,000/s is granted instantly to a proven wallet; above that an operator approves (1k / 10k / 100k presets)."));
18487
+ console.log(import_chalk55.default.dim(` Check: ${B.cli} limits get ${proj2.projectName}
18191
18488
  `));
18192
18489
  }
18193
18490
  function renderTeamQuota(q, teamLabel2, now = Date.now()) {
@@ -18202,9 +18499,9 @@ function renderTeamQuota(q, teamLabel2, now = Date.now()) {
18202
18499
  resets = Number.isFinite(ms2) && ms2 > now ? `${q.resets_at.replace("T", " ").slice(0, 16)} UTC (in ${humanIn(ms2 - now)})` : q.resets_at;
18203
18500
  }
18204
18501
  return [
18205
- `${import_chalk54.default.bold(teamLabel2)} \u2014 team quota${q.quotaPeriod ? ` (${q.quotaPeriod})` : ""}`,
18502
+ `${import_chalk55.default.bold(teamLabel2)} \u2014 team quota${q.quotaPeriod ? ` (${q.quotaPeriod})` : ""}`,
18206
18503
  ` ${"used".padEnd(12)} ${used.toLocaleString()}`,
18207
- ` ${"in use".padEnd(12)} ${inUse.toLocaleString()}${import_chalk54.default.dim(" pre-granted to live requests")}`,
18504
+ ` ${"in use".padEnd(12)} ${inUse.toLocaleString()}${import_chalk55.default.dim(" pre-granted to live requests")}`,
18208
18505
  ` ${"limit".padEnd(12)} ${limit === null ? "(none)" : limit.toLocaleString()}${bar}`,
18209
18506
  ` ${"resets".padEnd(12)} ${resets}`,
18210
18507
  ` ${"spend cap".padEnd(12)} ${usd(q.spend_cap_cents)}${typeof q.spend_cap_cents === "number" ? " / month" : ""}`
@@ -18225,7 +18522,7 @@ async function runLimitsUsage(project, opts) {
18225
18522
  const read = () => admin({ method: "GET", path: `/teams/${encodeURIComponent(teamId)}/quota`, summary: `Team quota for ${teamId}` });
18226
18523
  const render = (q) => {
18227
18524
  const lines = renderTeamQuota(q, teamName ?? teamId);
18228
- lines.push(import_chalk54.default.dim(` ${proj2.projectName}: per-project quota usage is not exposed by the API yet \u2014 this is the team-wide meter that also gates ${proj2.projectName}.`));
18525
+ lines.push(import_chalk55.default.dim(` ${proj2.projectName}: per-project quota usage is not exposed by the API yet \u2014 this is the team-wide meter that also gates ${proj2.projectName}.`));
18229
18526
  return lines;
18230
18527
  };
18231
18528
  if (!opts.watch) {
@@ -18242,7 +18539,7 @@ async function runLimitsUsage(project, opts) {
18242
18539
  else {
18243
18540
  process.stdout.write("\x1B[2J\x1B[H");
18244
18541
  for (const l of render(q)) console.log(l);
18245
- console.log(import_chalk54.default.dim(`
18542
+ console.log(import_chalk55.default.dim(`
18246
18543
  ${(/* @__PURE__ */ new Date()).toISOString()} \xB7 every 5 s \xB7 Ctrl-C to stop`));
18247
18544
  }
18248
18545
  await new Promise((r) => setTimeout(r, 5e3));
@@ -18251,13 +18548,13 @@ async function runLimitsUsage(project, opts) {
18251
18548
  async function runThrottleAlias(project, opts) {
18252
18549
  const mapped = throttleToLimitsOpts(opts);
18253
18550
  const flags = Object.entries(mapped).map(([k, v]) => `--${k.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase())} ${v}`).join(" ");
18254
- console.error(import_chalk54.default.yellow(` \`${B.cli} throttle\` is deprecated and will be removed next release \u2014 use: ${B.cli} limits set ${project}${flags ? " " + flags : ""}`));
18551
+ console.error(import_chalk55.default.yellow(` \`${B.cli} throttle\` is deprecated and will be removed next release \u2014 use: ${B.cli} limits set ${project}${flags ? " " + flags : ""}`));
18255
18552
  await runLimitsSet(project, { ...opts, ...mapped });
18256
18553
  }
18257
18554
 
18258
18555
  // src/commands/billing.ts
18259
- var import_chalk55 = __toESM(require("chalk"));
18260
- var import_ora20 = __toESM(require("ora"));
18556
+ var import_chalk56 = __toESM(require("chalk"));
18557
+ var import_ora21 = __toESM(require("ora"));
18261
18558
  init_admin();
18262
18559
  init_resolve();
18263
18560
  init_brand();
@@ -18276,34 +18573,34 @@ var STATUS_WORDS = {
18276
18573
  unavailable: "unavailable (the wallet root could not be reached)"
18277
18574
  };
18278
18575
  function statusColour(status2) {
18279
- if (status2 === "covered" || status2 === "free") return import_chalk55.default.green;
18280
- if (status2 === "low" || status2 === "grace" || status2 === "unavailable") return import_chalk55.default.yellow;
18281
- return import_chalk55.default.red;
18576
+ if (status2 === "covered" || status2 === "free") return import_chalk56.default.green;
18577
+ if (status2 === "low" || status2 === "grace" || status2 === "unavailable") return import_chalk56.default.yellow;
18578
+ return import_chalk56.default.red;
18282
18579
  }
18283
18580
  function renderBalance(c, teamLabel2) {
18284
18581
  const owner = typeof c.balance === "number" || typeof c.available_cents === "number";
18285
18582
  const status2 = String(c.status ?? "unavailable");
18286
- const lines = [`${import_chalk55.default.bold(teamLabel2)} \u2014 wallet${c.billing_account_id ? import_chalk55.default.dim(` ${c.billing_account_id}`) : ""}`];
18287
- lines.push(` ${"status".padEnd(14)} ${statusColour(status2)(STATUS_WORDS[status2] ?? status2)}${c.frozen && c.frozen_reason ? import_chalk55.default.dim(` (${c.frozen_reason})`) : ""}`);
18583
+ const lines = [`${import_chalk56.default.bold(teamLabel2)} \u2014 wallet${c.billing_account_id ? import_chalk56.default.dim(` ${c.billing_account_id}`) : ""}`];
18584
+ lines.push(` ${"status".padEnd(14)} ${statusColour(status2)(STATUS_WORDS[status2] ?? status2)}${c.frozen && c.frozen_reason ? import_chalk56.default.dim(` (${c.frozen_reason})`) : ""}`);
18288
18585
  if (!owner) {
18289
- lines.push(import_chalk55.default.dim(" This team runs on another owner's wallet: only its status is visible to you."));
18586
+ lines.push(import_chalk56.default.dim(" This team runs on another owner's wallet: only its status is visible to you."));
18290
18587
  return lines;
18291
18588
  }
18292
18589
  const available = c.available_cents ?? c.balance ?? 0;
18293
- lines.push(` ${"available".padEnd(14)} ${import_chalk55.default.bold(money(available))}`);
18294
- lines.push(` ${"in use".padEnd(14)} ${money(c.in_use_cents ?? 0)}${import_chalk55.default.dim(" pre-paid to live requests; returns as they finish")}`);
18590
+ lines.push(` ${"available".padEnd(14)} ${import_chalk56.default.bold(money(available))}`);
18591
+ lines.push(` ${"in use".padEnd(14)} ${money(c.in_use_cents ?? 0)}${import_chalk56.default.dim(" pre-paid to live requests; returns as they finish")}`);
18295
18592
  if (typeof c.grace_limit_cents === "number" || typeof c.grace_used_cents === "number") {
18296
18593
  const used = c.grace_used_cents ?? 0;
18297
- lines.push(` ${"grace".padEnd(14)} ${used > 0 ? import_chalk55.default.yellow(`${money(used)} owed`) : money(0)} of ${money(c.grace_limit_cents ?? 0)}${import_chalk55.default.dim(" a debt, repaid from the next top-up")}`);
18594
+ lines.push(` ${"grace".padEnd(14)} ${used > 0 ? import_chalk56.default.yellow(`${money(used)} owed`) : money(0)} of ${money(c.grace_limit_cents ?? 0)}${import_chalk56.default.dim(" a debt, repaid from the next top-up")}`);
18298
18595
  }
18299
18596
  if (typeof c.free_requests_remaining === "number" || typeof c.free_turns_remaining === "number") {
18300
18597
  lines.push(` ${"free tier".padEnd(14)} ${c.free_requests_remaining ?? 0} requests \xB7 ${c.free_turns_remaining ?? 0} chat turns left`);
18301
18598
  }
18302
18599
  const ar = c.auto_rebuy;
18303
- lines.push(` ${"auto-rebuy".padEnd(14)} ${ar?.enabled ? import_chalk55.default.green(`on \u2014 add ${money(ar.amount_cents)} when available drops under ${money(ar.threshold_cents)}`) : import_chalk55.default.dim("off")}`);
18304
- lines.push(` ${"last top-up".padEnd(14)} ${c.last_topup ? `${money(c.last_topup.cents)} on ${c.last_topup.at.replace("T", " ").slice(0, 16)} UTC` : import_chalk55.default.dim("never")}`);
18600
+ lines.push(` ${"auto-rebuy".padEnd(14)} ${ar?.enabled ? import_chalk56.default.green(`on \u2014 add ${money(ar.amount_cents)} when available drops under ${money(ar.threshold_cents)}`) : import_chalk56.default.dim("off")}`);
18601
+ lines.push(` ${"last top-up".padEnd(14)} ${c.last_topup ? `${money(c.last_topup.cents)} on ${c.last_topup.at.replace("T", " ").slice(0, 16)} UTC` : import_chalk56.default.dim("never")}`);
18305
18602
  if (c.terms && c.terms !== "prepaid") lines.push(` ${"terms".padEnd(14)} ${c.terms}`);
18306
- if (c.closed) lines.push(import_chalk55.default.red(" This wallet is closed."));
18603
+ if (c.closed) lines.push(import_chalk56.default.red(" This wallet is closed."));
18307
18604
  return lines;
18308
18605
  }
18309
18606
  async function readCredits(teamId) {
@@ -18317,7 +18614,7 @@ async function runBillingBalance(opts) {
18317
18614
  for (const l of renderBalance(c, teamName ?? teamId)) console.log(l);
18318
18615
  const status2 = String(c.status);
18319
18616
  if (typeof c.balance === "number" && (status2 === "low" || status2 === "out" || status2 === "grace" || status2 === "frozen")) {
18320
- console.log(import_chalk55.default.dim(`
18617
+ console.log(import_chalk56.default.dim(`
18321
18618
  Top up: ${B.cli} billing topup <usd>`));
18322
18619
  }
18323
18620
  console.log("");
@@ -18337,18 +18634,18 @@ async function runBillingTopup(amount, opts) {
18337
18634
  return;
18338
18635
  }
18339
18636
  if (c && typeof c.balance !== "number") {
18340
- console.log(import_chalk55.default.yellow(`
18637
+ console.log(import_chalk56.default.yellow(`
18341
18638
  ${teamName ?? teamId} runs on another owner's wallet \u2014 only that owner can top it up.`));
18342
- console.log(import_chalk55.default.dim(` Ask them, or fund your own: ${url}
18639
+ console.log(import_chalk56.default.dim(` Ask them, or fund your own: ${url}
18343
18640
  `));
18344
18641
  return;
18345
18642
  }
18346
18643
  console.log(`
18347
- Top up ${import_chalk55.default.bold(`$${usd2.toFixed(2)}`)} for ${import_chalk55.default.bold(teamName ?? teamId)} in the dashboard (card checkout needs your browser session):`);
18348
- console.log(` ${import_chalk55.default.cyan(url)}`);
18349
- console.log(import_chalk55.default.dim(` Enter $${usd2.toFixed(2)} in the wallet panel; the balance updates within seconds of Stripe confirming.`));
18350
- if (c?.auto_rebuy?.enabled) console.log(import_chalk55.default.dim(` Auto-rebuy is on (${money(c.auto_rebuy.amount_cents)} under ${money(c.auto_rebuy.threshold_cents)}).`));
18351
- else console.log(import_chalk55.default.dim(` Never run dry: ${B.cli} billing rebuy on --amount 50 --threshold 10`));
18644
+ Top up ${import_chalk56.default.bold(`$${usd2.toFixed(2)}`)} for ${import_chalk56.default.bold(teamName ?? teamId)} in the dashboard (card checkout needs your browser session):`);
18645
+ console.log(` ${import_chalk56.default.cyan(url)}`);
18646
+ console.log(import_chalk56.default.dim(` Enter $${usd2.toFixed(2)} in the wallet panel; the balance updates within seconds of Stripe confirming.`));
18647
+ if (c?.auto_rebuy?.enabled) console.log(import_chalk56.default.dim(` Auto-rebuy is on (${money(c.auto_rebuy.amount_cents)} under ${money(c.auto_rebuy.threshold_cents)}).`));
18648
+ else console.log(import_chalk56.default.dim(` Never run dry: ${B.cli} billing rebuy on --amount 50 --threshold 10`));
18352
18649
  if (opts.open) {
18353
18650
  const { spawn: spawn5 } = await import("child_process");
18354
18651
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
@@ -18370,15 +18667,15 @@ function usageToCsv(rows) {
18370
18667
  }
18371
18668
  function renderUsageTable(r, hourly) {
18372
18669
  const rows = r.rows ?? [];
18373
- if (!rows.length) return [import_chalk55.default.dim(" No usage in that window.")];
18670
+ if (!rows.length) return [import_chalk56.default.dim(" No usage in that window.")];
18374
18671
  const w = hourly ? 16 : 10;
18375
- const lines = [import_chalk55.default.dim(` ${"bucket".padEnd(w)} ${"project".padEnd(24)} ${"requests".padStart(10)} ${"free".padStart(8)} ${"cost".padStart(10)}`)];
18672
+ const lines = [import_chalk56.default.dim(` ${"bucket".padEnd(w)} ${"project".padEnd(24)} ${"requests".padStart(10)} ${"free".padStart(8)} ${"cost".padStart(10)}`)];
18376
18673
  for (const row of rows) {
18377
18674
  const bucket = hourly ? row.bucket.replace("T", " ").slice(0, 16) : row.bucket.slice(0, 10);
18378
- lines.push(` ${bucket.padEnd(w)} ${(row.project_id || "(no project)").slice(0, 24).padEnd(24)} ${row.requests.toLocaleString().padStart(10)} ${(row.free_used ?? 0).toLocaleString().padStart(8)} ${money(row.cost_cents).padStart(10)}${row.exact === false ? import_chalk55.default.dim(" ~") : ""}`);
18675
+ lines.push(` ${bucket.padEnd(w)} ${(row.project_id || "(no project)").slice(0, 24).padEnd(24)} ${row.requests.toLocaleString().padStart(10)} ${(row.free_used ?? 0).toLocaleString().padStart(8)} ${money(row.cost_cents).padStart(10)}${row.exact === false ? import_chalk56.default.dim(" ~") : ""}`);
18379
18676
  }
18380
18677
  const t = r.totals ?? { requests: rows.reduce((a, x) => a + x.requests, 0), cost_cents: rows.reduce((a, x) => a + x.cost_cents, 0), free_used: rows.reduce((a, x) => a + (x.free_used ?? 0), 0) };
18381
- lines.push(import_chalk55.default.bold(` ${"total".padEnd(w)} ${"".padEnd(24)} ${Number(t.requests ?? 0).toLocaleString().padStart(10)} ${Number(t.free_used ?? 0).toLocaleString().padStart(8)} ${money(t.cost_cents ?? 0).padStart(10)}`));
18678
+ lines.push(import_chalk56.default.bold(` ${"total".padEnd(w)} ${"".padEnd(24)} ${Number(t.requests ?? 0).toLocaleString().padStart(10)} ${Number(t.free_used ?? 0).toLocaleString().padStart(8)} ${money(t.cost_cents ?? 0).padStart(10)}`));
18382
18679
  return lines;
18383
18680
  }
18384
18681
  var HISTORY_PAGE_MAX = 500;
@@ -18422,33 +18719,33 @@ async function readTeamLedger(teamId, q) {
18422
18719
  return out;
18423
18720
  }
18424
18721
  function renderLedgerLine(l) {
18425
- const tag = l.pending ? import_chalk55.default.yellow("pending ") : " ".repeat(8);
18426
- const amt = (l.amount_cents < 0 ? import_chalk55.default.red : l.amount_cents > 0 ? import_chalk55.default.green : import_chalk55.default.dim)(signedMoney(l.amount_cents).padStart(12));
18722
+ const tag = l.pending ? import_chalk56.default.yellow("pending ") : " ".repeat(8);
18723
+ const amt = (l.amount_cents < 0 ? import_chalk56.default.red : l.amount_cents > 0 ? import_chalk56.default.green : import_chalk56.default.dim)(signedMoney(l.amount_cents).padStart(12));
18427
18724
  if (l.class === "flow") {
18428
18725
  const reqs = `${(l.requests ?? 0).toLocaleString()} request${l.requests === 1 ? "" : "s"}`;
18429
- return ` ${tag}${utc(l.ts_from).slice(0, 10).padEnd(16)} ${`${l.label} UTC`.slice(0, 26).padEnd(26)} ${reqs.padStart(16)} ${amt}${l.project_id ? import_chalk55.default.dim(` ${l.project_id}`) : ""}`;
18726
+ return ` ${tag}${utc(l.ts_from).slice(0, 10).padEnd(16)} ${`${l.label} UTC`.slice(0, 26).padEnd(26)} ${reqs.padStart(16)} ${amt}${l.project_id ? import_chalk56.default.dim(` ${l.project_id}`) : ""}`;
18430
18727
  }
18431
- const bal = typeof l.balance_after_cents === "number" ? `${import_chalk55.default.dim("balance")} ${money(l.balance_after_cents)}` : "";
18728
+ const bal = typeof l.balance_after_cents === "number" ? `${import_chalk56.default.dim("balance")} ${money(l.balance_after_cents)}` : "";
18432
18729
  const extra = [l.label && l.label !== l.kind ? l.label : null, l.project_id].filter(Boolean).join(" \xB7 ");
18433
- return ` ${tag}${utc(l.ts).padEnd(16)} ${String(l.kind).slice(0, 26).padEnd(26)} ${"".padStart(16)} ${amt}${bal ? ` ${bal}` : ""}${extra ? import_chalk55.default.dim(` ${extra}`) : ""}`;
18730
+ return ` ${tag}${utc(l.ts).padEnd(16)} ${String(l.kind).slice(0, 26).padEnd(26)} ${"".padStart(16)} ${amt}${bal ? ` ${bal}` : ""}${extra ? import_chalk56.default.dim(` ${extra}`) : ""}`;
18434
18731
  }
18435
18732
  function renderLedger(r, limit) {
18436
18733
  const lines = [];
18437
- lines.push(import_chalk55.default.bold(` Ledger \u2014 newest first${r.window_days ? `, last ${r.window_days} day${r.window_days === 1 ? "" : "s"}` : ""}`) + import_chalk55.default.dim(" (events one line each; usage in 5-minute blocks, UTC)"));
18438
- if (!r.pending_sync_available) lines.push(import_chalk55.default.yellow(" Pending lines unavailable right now \u2014 the last few minutes of charges may not be listed yet."));
18734
+ lines.push(import_chalk56.default.bold(` Ledger \u2014 newest first${r.window_days ? `, last ${r.window_days} day${r.window_days === 1 ? "" : "s"}` : ""}`) + import_chalk56.default.dim(" (events one line each; usage in 5-minute blocks, UTC)"));
18735
+ if (!r.pending_sync_available) lines.push(import_chalk56.default.yellow(" Pending lines unavailable right now \u2014 the last few minutes of charges may not be listed yet."));
18439
18736
  if (r.pending_sync.length) {
18440
- lines.push(import_chalk55.default.yellow(" Pending sync \u2014 made by the wallet, not in the ledger yet:"));
18737
+ lines.push(import_chalk56.default.yellow(" Pending sync \u2014 made by the wallet, not in the ledger yet:"));
18441
18738
  for (const l of r.pending_sync) lines.push(renderLedgerLine({ ...l, pending: true }));
18442
18739
  }
18443
18740
  if (!r.history_available) {
18444
- lines.push(import_chalk55.default.yellow(" The ledger could not be read right now \u2014 history unknown (not empty). Try again shortly."));
18741
+ lines.push(import_chalk56.default.yellow(" The ledger could not be read right now \u2014 history unknown (not empty). Try again shortly."));
18445
18742
  } else if (!r.history.length && !r.pending_sync.length) {
18446
- lines.push(import_chalk55.default.dim(" No ledger lines in that window."));
18743
+ lines.push(import_chalk56.default.dim(" No ledger lines in that window."));
18447
18744
  } else {
18448
18745
  for (const l of r.history) lines.push(renderLedgerLine(l));
18449
18746
  }
18450
18747
  if (r.history_next_before) {
18451
- lines.push(import_chalk55.default.dim(` More lines than --limit ${limit}. Next page: ${B.cli} billing history --before ${r.history_next_before} (or raise --limit)`));
18748
+ lines.push(import_chalk56.default.dim(` More lines than --limit ${limit}. Next page: ${B.cli} billing history --before ${r.history_next_before} (or raise --limit)`));
18452
18749
  }
18453
18750
  return lines;
18454
18751
  }
@@ -18482,9 +18779,9 @@ async function runBillingHistory(opts) {
18482
18779
  console.log("");
18483
18780
  if (ledger) for (const l of renderLedger(ledger, limit)) console.log(l);
18484
18781
  console.log("");
18485
- console.log(import_chalk55.default.bold(` Usage \u2014 ${opts.raw ? "raw, one row per 5-minute UTC bucket" : "daily rollups"}${opts.since ? ` since ${opts.since}` : ""}${opts.until ? ` until ${opts.until}` : ""}`));
18782
+ console.log(import_chalk56.default.bold(` Usage \u2014 ${opts.raw ? "raw, one row per 5-minute UTC bucket" : "daily rollups"}${opts.since ? ` since ${opts.since}` : ""}${opts.until ? ` until ${opts.until}` : ""}`));
18486
18783
  for (const l of renderUsageTable(r, !!opts.raw)) console.log(l);
18487
- console.log(import_chalk55.default.dim("\n Exact figures from the money ledger, per project (UTC). Entries the wallet has not sent yet (\u2264 ~5 min) are the pending lines above, not this table. CSV: --format csv\n"));
18784
+ console.log(import_chalk56.default.dim("\n Exact figures from the money ledger, per project (UTC). Entries the wallet has not sent yet (\u2264 ~5 min) are the pending lines above, not this table. CSV: --format csv\n"));
18488
18785
  }
18489
18786
  async function runBillingRebuy(mode, opts) {
18490
18787
  const which = (mode ?? "status").toLowerCase();
@@ -18494,12 +18791,12 @@ async function runBillingRebuy(mode, opts) {
18494
18791
  const c = await readCredits(teamId);
18495
18792
  if (opts.json) return void console.log(JSON.stringify({ team_id: teamId, auto_rebuy: c.auto_rebuy ?? null, owner: typeof c.balance === "number" }));
18496
18793
  const ar2 = c.auto_rebuy;
18497
- if (typeof c.balance !== "number") return void console.log(import_chalk55.default.dim(`
18794
+ if (typeof c.balance !== "number") return void console.log(import_chalk56.default.dim(`
18498
18795
  ${teamName ?? teamId} runs on another owner's wallet; auto-rebuy is theirs to set.
18499
18796
  `));
18500
18797
  console.log(`
18501
- auto-rebuy ${ar2?.enabled ? import_chalk55.default.green("on") : import_chalk55.default.dim("off")}${ar2?.enabled ? ` \u2014 add ${money(ar2.amount_cents)} when available drops under ${money(ar2.threshold_cents)}` : ""}`);
18502
- console.log(import_chalk55.default.dim(` ${B.cli} billing rebuy on --amount 50 --threshold 10 \xB7 ${B.cli} billing rebuy off
18798
+ auto-rebuy ${ar2?.enabled ? import_chalk56.default.green("on") : import_chalk56.default.dim("off")}${ar2?.enabled ? ` \u2014 add ${money(ar2.amount_cents)} when available drops under ${money(ar2.threshold_cents)}` : ""}`);
18799
+ console.log(import_chalk56.default.dim(` ${B.cli} billing rebuy on --amount 50 --threshold 10 \xB7 ${B.cli} billing rebuy off
18503
18800
  `));
18504
18801
  return;
18505
18802
  }
@@ -18515,7 +18812,7 @@ async function runBillingRebuy(mode, opts) {
18515
18812
  throw new UsageError(`--amount must be between $${TOPUP_MIN_USD} and $${TOPUP_MAX_USD} (one card charge).`);
18516
18813
  }
18517
18814
  }
18518
- const spinner = (0, import_ora20.default)(`Auto-rebuy ${which}...`).start();
18815
+ const spinner = (0, import_ora21.default)(`Auto-rebuy ${which}...`).start();
18519
18816
  let r;
18520
18817
  try {
18521
18818
  r = await admin({ method: "PUT", path: `/credits/auto-rebuy?teamId=${encodeURIComponent(teamId)}`, body, summary: `Auto-rebuy ${which}` });
@@ -18528,159 +18825,8 @@ async function runBillingRebuy(mode, opts) {
18528
18825
  if (opts.json) console.log(JSON.stringify(r ?? { auto_rebuy: body }));
18529
18826
  }
18530
18827
 
18531
- // src/commands/transform.ts
18532
- var import_chalk56 = __toESM(require("chalk"));
18533
- var import_ora21 = __toESM(require("ora"));
18534
- init_caller();
18535
- var HEADER_NAME = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
18536
- var ruleNameFor = (header) => `set header ${header.toLowerCase()}`;
18537
- async function target(project, opts) {
18538
- const caller = requireCaller();
18539
- const { teamId } = await resolveActingTeam(caller, opts.team);
18540
- const proj2 = await resolveProjectVia(caller, teamId, project, opts.apiversion);
18541
- const base2 = `/projects/${encodeURIComponent(proj2.projectId)}/${encodeURIComponent(proj2.apiVersion)}/transforms`;
18542
- return { caller, proj: proj2, base: base2 };
18543
- }
18544
- async function listRules(t) {
18545
- const out = await producer(t.caller, {
18546
- method: "GET",
18547
- path: t.base,
18548
- summary: `List transforms for ${t.proj.projectName}`
18549
- });
18550
- return out?.rules ?? [];
18551
- }
18552
- function describe(r) {
18553
- const a = r.action ?? { type: "?" };
18554
- if (a.type === "hardcode") {
18555
- const secret = !a.value || /^abzsec:|^__ABZSEC_|^•+$/.test(a.value);
18556
- return `set ${a.destination} = ${secret ? "(secret)" : a.value}`;
18557
- }
18558
- if (a.type === "remove") return `remove ${a.field}`;
18559
- if (a.type === "map") return `map ${a.source} \u2192 ${a.destination}${a.lookup?.mapping_id ? " (through a mapping table)" : ""}`;
18560
- return a.type;
18561
- }
18562
- async function runTransformList(project, opts) {
18563
- const t = await target(project, opts);
18564
- const rules = await listRules(t);
18565
- if (opts.json) {
18566
- console.log(JSON.stringify(rules, null, 2));
18567
- return;
18568
- }
18569
- if (!rules.length) {
18570
- console.log(import_chalk56.default.dim(`No transforms on ${t.proj.projectName} v${t.proj.apiVersion}.`));
18571
- return;
18572
- }
18573
- for (const r of rules) {
18574
- console.log(`${r.enabled ? import_chalk56.default.green("\u25CF") : import_chalk56.default.gray("\u25CB")} ${import_chalk56.default.bold(r.name)} ${import_chalk56.default.dim(`[${r.phase}] ${r.id}`)}`);
18575
- console.log(` ${describe(r)}`);
18576
- }
18577
- }
18578
- async function runTransformSetHeader(project, header, opts) {
18579
- if (!HEADER_NAME.test(header)) throw new Error(`"${header}" is not a valid header name.`);
18580
- if (opts.value === void 0 === (opts.valueEnv === void 0)) {
18581
- throw new Error("Pass exactly one of --value <value> or --value-env <VAR> (reads the value from that environment variable, so it stays out of your shell history).");
18582
- }
18583
- const value = opts.value ?? process.env[opts.valueEnv];
18584
- if (!value) throw new Error(`Environment variable ${opts.valueEnv} is empty or not set.`);
18585
- const t = await target(project, opts);
18586
- const name = ruleNameFor(header);
18587
- const action = {
18588
- type: "hardcode",
18589
- destination: `header:${header}`,
18590
- value,
18591
- // Encrypted at rest and masked on every read; main-proxy decrypts it only
18592
- // on the way to the upstream.
18593
- ...opts.secret ? { value_secret: true } : {}
18594
- };
18595
- const existing = (await listRules(t)).find((r) => r.name === name && r.phase === "request");
18596
- const summary = `${existing ? "Update" : "Add"} transform: send ${header} to the upstream`;
18597
- const spinner = opts.json ? null : (0, import_ora21.default)(summary + "...").start();
18598
- try {
18599
- const out = await producer(t.caller, existing ? { method: "PUT", path: `${t.base}/${encodeURIComponent(existing.id)}`, body: { action, enabled: true }, summary } : { method: "POST", path: t.base, body: { name, action, phase: "request", enabled: true }, summary });
18600
- spinner?.succeed(`${summary} \u2014 ${t.proj.projectName} v${t.proj.apiVersion}${opts.secret ? " (stored encrypted)" : ""}.`);
18601
- if (opts.json) console.log(JSON.stringify(out ?? { ok: true }));
18602
- else console.log(import_chalk56.default.dim(` Every call the proxy forwards now carries ${header}. Your backend can reject calls without it.`));
18603
- } catch (err) {
18604
- spinner?.fail(summary + " failed.");
18605
- throw err;
18606
- }
18607
- }
18608
- async function runTransformRemove(project, nameOrId, opts) {
18609
- const t = await target(project, opts);
18610
- const rules = await listRules(t);
18611
- const want = nameOrId.toLowerCase();
18612
- const rule = rules.find((r) => r.id === nameOrId || r.name.toLowerCase() === want || r.name === ruleNameFor(nameOrId));
18613
- if (!rule) {
18614
- throw new Error(`No transform "${nameOrId}" on ${t.proj.projectName}.` + (rules.length ? ` Transforms: ${rules.map((r) => r.name).join(", ")}` : ""));
18615
- }
18616
- await producer(t.caller, {
18617
- method: "DELETE",
18618
- path: `${t.base}/${encodeURIComponent(rule.id)}`,
18619
- summary: `Remove transform "${rule.name}"`
18620
- });
18621
- if (opts.json) console.log(JSON.stringify({ ok: true, removed: rule.id }));
18622
- else console.log(`${import_chalk56.default.green("\u2713")} Removed transform ${import_chalk56.default.bold(rule.name)} from ${t.proj.projectName}.`);
18623
- }
18624
- function tablesBase(t) {
18625
- return t.base.replace(/\/transforms$/, "/mappings");
18626
- }
18627
- async function listTables(t) {
18628
- const out = await producer(t.caller, {
18629
- method: "GET",
18630
- path: tablesBase(t),
18631
- summary: `List mapping tables for ${t.proj.projectName}`
18632
- });
18633
- return out?.tables ?? [];
18634
- }
18635
- function parseEntries(pairs) {
18636
- return pairs.map((p) => {
18637
- const i = p.indexOf("=");
18638
- if (i <= 0) throw new Error(`"${p}" is not a from=to pair (e.g. FR=EUR).`);
18639
- return { from: p.slice(0, i), to: p.slice(i + 1) };
18640
- });
18641
- }
18642
- var FIELD_REF = /^(header|query|param|bodyvar|jwt):.+/;
18643
- async function runTransformMapping(project, table, pairs, opts) {
18644
- if (!pairs.length) throw new Error("Give at least one from=to pair, e.g. FR=EUR US=USD.");
18645
- const entries2 = parseEntries(pairs);
18646
- const t = await target(project, opts);
18647
- const existing = (await listTables(t)).find((m) => m.name === table);
18648
- const body = { name: table, entries: entries2, ...opts.secret ? { encrypt_values: true } : {} };
18649
- const summary = `${existing ? "Replace" : "Create"} mapping table "${table}" (${entries2.length} entr${entries2.length === 1 ? "y" : "ies"})`;
18650
- const out = await producer(t.caller, existing ? { method: "PUT", path: `${tablesBase(t)}/${encodeURIComponent(existing.id)}`, body, summary } : { method: "POST", path: tablesBase(t), body, summary });
18651
- if (opts.json) {
18652
- console.log(JSON.stringify(out ?? { ok: true }));
18653
- return;
18654
- }
18655
- console.log(`${import_chalk56.default.green("\u2714")} ${summary} \u2014 ${t.proj.projectName} v${t.proj.apiVersion}.`);
18656
- for (const e of entries2) console.log(import_chalk56.default.dim(` ${e.from} \u2192 ${opts.secret ? "(secret)" : e.to}`));
18657
- }
18658
- async function runTransformMap(project, source, destination, opts) {
18659
- if (!FIELD_REF.test(source)) throw new Error(`Source "${source}" must look like header:X-Country, query:country or bodyvar:order.country.`);
18660
- if (!/^(header|query|bodyvar):.+/.test(destination)) throw new Error(`Destination "${destination}" must look like header:X-Currency, query:currency or bodyvar:order.currency.`);
18661
- if (!opts.table) throw new Error("--table <name> is required: the mapping table to look the value up in (create it with `transform mapping`).");
18662
- const onNoMatch = opts.onNoMatch ?? "skip";
18663
- if (!["skip", "fail", "passthrough"].includes(onNoMatch)) throw new Error("--on-no-match is skip, fail or passthrough.");
18664
- const t = await target(project, opts);
18665
- const table = (await listTables(t)).find((m) => m.name === opts.table);
18666
- if (!table) throw new Error(`No mapping table "${opts.table}" on ${t.proj.projectName}. Create it: npx apiblaze transform mapping ${project} ${opts.table} FR=EUR \u2026`);
18667
- const name = `map ${source} to ${destination}`;
18668
- const action = {
18669
- type: "map",
18670
- source,
18671
- destination,
18672
- lookup: { mapping_id: table.id, on_no_match: onNoMatch }
18673
- };
18674
- const existing = (await listRules(t)).find((r) => r.name === name && r.phase === "request");
18675
- const summary = `${existing ? "Update" : "Add"} transform: ${source} \u2192 ${destination} through "${table.name}"`;
18676
- const out = await producer(t.caller, existing ? { method: "PUT", path: `${t.base}/${encodeURIComponent(existing.id)}`, body: { action, enabled: true }, summary } : { method: "POST", path: t.base, body: { name, action, phase: "request", enabled: true }, summary });
18677
- if (opts.json) {
18678
- console.log(JSON.stringify(out ?? { ok: true }));
18679
- return;
18680
- }
18681
- console.log(`${import_chalk56.default.green("\u2714")} ${summary} \u2014 ${t.proj.projectName} v${t.proj.apiVersion}.`);
18682
- console.log(import_chalk56.default.dim(` A value not in the table: ${onNoMatch === "skip" ? "nothing is written" : onNoMatch === "fail" ? "the call is refused" : "it is copied as-is"}.`));
18683
- }
18828
+ // src/cli.ts
18829
+ init_transform();
18684
18830
 
18685
18831
  // src/commands/config-browse.ts
18686
18832
  var import_chalk63 = __toESM(require("chalk"));
@@ -23341,7 +23487,7 @@ function buildProgram() {
23341
23487
  program2.command("create").description(descriptionFor({
23342
23488
  apiblaze: `Put an app that is already DEPLOYED behind ${B.product}: a public URL and an MCP address for AI agents in front of your URL or OpenAPI spec. Included: API keys, sign-in, ownership rules, rate limits. No login needed. (App on this machine? Use \`dev\`.) Add --compliant to make it a Claude connector, or a ChatGPT plugin with --compliant chatgpt, that meets the directory's policies.`,
23343
23489
  mcpblaze: "Make an MCP server from a deployed API's OpenAPI spec or URL: a connector address, sign-in and per-user rules included. No login needed. (App on this machine? Use `dev`.) Add --compliant for a Claude connector (or a ChatGPT plugin with --compliant chatgpt) that meets the directory policies; it says what is left at every step and hands you the page to finish."
23344
- })).option("--name <name>", B.cli === "mcpblaze" ? "MCP server name (becomes <name>-<tenant>.mcpblaze.com)" : "Proxy name (becomes <name>.abz.run)").option("--target <url|file>", descriptionFor({ apiblaze: "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", mcpblaze: "What to serve as an MCP server \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>", "Open ONE door only: api_key | oauth (sign in with GitHub, APIblaze-hosted) | none. Omitted = both doors.").option("--apikey", "API-key door only (no sign-in): the bootstrap keys are minted and printed; callers send X-API-Key, agents connect with a key.").option("--oauth [config]", `Sign-in door only (no API key). 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 \xB7 oidc); the secret is optional except for github and facebook. '{"provider":"oidc","issuer":"https://acme.okta.com/oauth2/default","clientId":"\u2026"}' = any OpenID Connect IdP by issuer (Okta \xB7 Entra \xB7 Keycloak \xB7 Cognito \xB7 \u2026).`).option("--identified", "Require every call to identify its end user (X-End-User-Id from a backend key, or a login token \u2014 a client key alone cannot); unattributed calls are rejected").option("--iam", `Turn IAM on for the ${B.thingShort}'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 ${B.thingShort} you own adds a version to the existing project.`).option("--tenant <slug>", `Tenant to attach the ${B.thingShort} 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("--auto", `Zero prompts, start to finish: generates the ${B.thingShort} name when --name is omitted (from the target host, salted), takes every confirmation as yes, auto-picks the tenant. Implies --yes.`).option("--new-session", "Start a fresh anonymous session (do not group with prior anonymous creates)").option("--json", "Output machine-readable JSON (non-interactive)").option("--compliant [directories...]", `Directory-ready in one command, to the letter of that directory's policies: create the ${B.thingShort} from --target (an OpenAPI URL/file), apply the safe fixes, set up the custom MCP domain (--domain, one CNAME), ask for every listing answer with the spec's proposal pre-filled (cut to the portal's limits), create the reviewer account, write the submission packet. Bare = claude; or claude \xB7 chatgpt \xB7 all. Ends with the compliance table: every rule the listing satisfies and the policy page it comes from. Same as \`${B.cli} connector <spec> --compliant \u2026\`.`).addOption(new import_commander.Option("--policy [directories...]", "Older spelling of --compliant").hideHelp()).option("--domain <host>", "With --compliant: the MCP server's custom hostname (mcp.<your domain>); asked for when missing, suggested from the spec").option("--wait <minutes>", "With --compliant: how long to wait for the custom domain to activate once its CNAME is in place (default 15; 0 = do not wait)").option("--auth-mode <mode>", "With --compliant: how directory clients get in. signin (default) = OAuth sign-in on the connector, API keys alongside; open = no sign-in at all, for public read-only data (Anthropic allows it) \u2014 the API host keeps its own doors. Asked once when every tool is read-only.").option("--data-handling <mode>", "Compliant: whose API this is (own \xB7 proxied + --data-handling-statement \xB7 third-party); never pre-filled").option("--data-handling-statement <text>", "Compliant, proxied: the permission you hold").option("--health-data <yes|no>", "Compliant: the tools handle health data (never pre-filled)").option("--sponsored-content <yes|no>", "Compliant: tool results carry sponsored content (never pre-filled)").option("--no-exercise", 'Compliant: skip the "Run every tool now?" step').option("--seed", "Sign-in mode: when a read returns nothing for the reviewer, create a few records through the create tools and keep them (asked when omitted)").option("--no-seed", "Never seed the reviewer account").option("--no-email", "Compliant: no email at the end of the run").option("--directory-ready", "Make it directory-ready for the Claude and ChatGPT directories: OAuth door, custom-domain checks, listing fields; the readiness report runs after the create and a blocker exits 1").option("--privacy-url <url>", "Directory listing: public https privacy policy").option("--support <email|url>", "Directory listing: support contact").option("--docs-url <url>", "Directory listing: public documentation URL (the developer portal by default)").option("--prompt <text>", "Directory listing: an example prompt (repeat the flag; three are needed)", collect, []).option("--server-name <name>", 'Directory listing: the name (2\u201340 chars, no "MCP"/"Plugin" suffix)').option("--tagline <text>", "Directory listing: one-line tagline").option("--description <text>", "Directory listing: description").option("--icon-url <url>", "Directory listing: square icon (https)").option("--slug <slug>", "Claude: the listing slug (lowercase-with-hyphens; permanent once published)").option("--high-risk <list>", "Claude policy 1A: none, or any of legal,healthcare,insurance,finance").option("--open-world <yes|no>", "Every tool: reaches public or open-ended data (yes) or only the signed-in account's (no); asked once when omitted").option("--no-watch", "Do not turn on the nightly re-check email when the listing is green").option("--no-wait-login", "Sign-in mode: do not wait for a Claude sign-in before the verdict").option("--mcp-app", "Claude: the listing is an MCP App (the host then advertises the UI extension; needs 3\u20135 --screenshot)").option("--no-mcp-app", "Claude: a plain connector (default)").option("--screenshot <url=prompt>", "Claude MCP App: a carousel screenshot (PNG \u2265 1000 px wide) and the prompt that produced it (repeatable, 3\u20135)", collect, []).option("--vuln-contact <email|url>", "Directory listing: vulnerability-disclosure contact").option("--attest <id>", "Attest (repeatable): guidelines \xB7 own-backend \xB7 no-financial \xB7 no-genai-media \xB7 no-prompt-injection \xB7 no-conversation-data \xB7 public-docs (Claude's seven) \xB7 no-digital-goods \xB7 content-13-no-ads \xB7 no-restricted-data (ChatGPT)", collect, []).option("--allowed-origin <origin>", "Directory mode: an extra browser origin allowed on the MCP host (repeatable)", collect, []).option("--openai-challenge <token>", "ChatGPT: the domain-verification token the OpenAI portal shows under Plugins \u2192 Connect MCP server").action(async (opts) => {
23490
+ })).option("--name <name>", B.cli === "mcpblaze" ? "MCP server name (becomes <name>-<tenant>.mcpblaze.com)" : "Proxy name (becomes <name>.abz.run)").option("--target <url|file>", descriptionFor({ apiblaze: "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", mcpblaze: "What to serve as an MCP server \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>", "Open ONE door only: api_key | oauth (sign in with GitHub, APIblaze-hosted) | none. Omitted = both doors.").option("--apikey", "API-key door only (no sign-in): the bootstrap keys are minted and printed; callers send X-API-Key, agents connect with a key.").option("--oauth [config]", `Sign-in door only (no API key). 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 \xB7 oidc); the secret is optional except for github and facebook. '{"provider":"oidc","issuer":"https://acme.okta.com/oauth2/default","clientId":"\u2026"}' = any OpenID Connect IdP by issuer (Okta \xB7 Entra \xB7 Keycloak \xB7 Cognito \xB7 \u2026).`).option("--identified", "Require every call to identify its end user (X-End-User-Id from a backend key, or a login token \u2014 a client key alone cannot); unattributed calls are rejected").option("--iam", `Turn IAM on for the ${B.thingShort}'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 ${B.thingShort} you own adds a version to the existing project.`).option("--tenant <slug>", `Tenant to attach the ${B.thingShort} 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("--auto", `Zero prompts, start to finish: generates the ${B.thingShort} name when --name is omitted (from the target host, salted), takes every confirmation as yes, auto-picks the tenant. Implies --yes.`).option("--new-session", "Start a fresh anonymous session (do not group with prior anonymous creates)").option("--json", "Output machine-readable JSON (non-interactive)").option("--compliant [directories...]", `Directory-ready in one command, to the letter of that directory's policies: create the ${B.thingShort} from --target (an OpenAPI URL/file), apply the safe fixes, set up the custom MCP domain (--domain, one CNAME), ask for every listing answer with the spec's proposal pre-filled (cut to the portal's limits), create the reviewer account, write the submission packet. Bare = claude; or claude \xB7 chatgpt \xB7 all. Ends with the compliance table: every rule the listing satisfies and the policy page it comes from. Same as \`${B.cli} connector <spec> --compliant \u2026\`.`).addOption(new import_commander.Option("--policy [directories...]", "Older spelling of --compliant").hideHelp()).option("--domain <host>", "With --compliant: the MCP server's custom hostname (mcp.<your domain>); asked for when missing, suggested from the spec").option("--wait <minutes>", "With --compliant: how long to wait for the custom domain to activate once its CNAME is in place (default 15; 0 = do not wait)").option("--target-url <url>", "With --compliant: Where the app runs in production (https): a listing needs the hosted app, not a tunnel; asked when missing").option("--upstream-header <header>", 'With --compliant: "Name: value", the header the backend needs to accept these calls, stored encrypted; asked when missing').option("--upstream-header-env <name=var>", "With --compliant: The same with the value read from an environment variable, so it stays out of your shell history").option("--upstream-open", "With --compliant: The backend checks its own credentials: no header").option("--auth-mode <mode>", "With --compliant: how directory clients get in. signin (default) = OAuth sign-in on the connector, API keys alongside; open = no sign-in at all, for public read-only data (Anthropic allows it) \u2014 the API host keeps its own doors. Asked once when every tool is read-only.").option("--data-handling <mode>", "Compliant: whose API this is (own \xB7 proxied + --data-handling-statement \xB7 third-party); never pre-filled").option("--data-handling-statement <text>", "Compliant, proxied: the permission you hold").option("--health-data <yes|no>", "Compliant: the tools handle health data (never pre-filled)").option("--sponsored-content <yes|no>", "Compliant: tool results carry sponsored content (never pre-filled)").option("--no-exercise", 'Compliant: skip the "Run every tool now?" step').option("--seed", "Sign-in mode: when a read returns nothing for the reviewer, create a few records through the create tools and keep them (asked when omitted)").option("--no-seed", "Never seed the reviewer account").option("--no-email", "Compliant: no email at the end of the run").option("--directory-ready", "Make it directory-ready for the Claude and ChatGPT directories: OAuth door, custom-domain checks, listing fields; the readiness report runs after the create and a blocker exits 1").option("--privacy-url <url>", "Directory listing: public https privacy policy").option("--support <email|url>", "Directory listing: support contact").option("--docs-url <url>", "Directory listing: public documentation URL (the developer portal by default)").option("--prompt <text>", "Directory listing: an example prompt (repeat the flag; three are needed)", collect, []).option("--server-name <name>", 'Directory listing: the name (2\u201340 chars, no "MCP"/"Plugin" suffix)').option("--tagline <text>", "Directory listing: one-line tagline").option("--description <text>", "Directory listing: description").option("--icon-url <url>", "Directory listing: square icon (https)").option("--slug <slug>", "Claude: the listing slug (lowercase-with-hyphens; permanent once published)").option("--high-risk <list>", "Claude policy 1A: none, or any of legal,healthcare,insurance,finance").option("--open-world <yes|no>", "Every tool: reaches public or open-ended data (yes) or only the signed-in account's (no); asked once when omitted").option("--no-watch", "Do not turn on the nightly re-check email when the listing is green").option("--no-wait-login", "Sign-in mode: do not wait for a Claude sign-in before the verdict").option("--mcp-app", "Claude: the listing is an MCP App (the host then advertises the UI extension; needs 3\u20135 --screenshot)").option("--no-mcp-app", "Claude: a plain connector (default)").option("--screenshot <url=prompt>", "Claude MCP App: a carousel screenshot (PNG \u2265 1000 px wide) and the prompt that produced it (repeatable, 3\u20135)", collect, []).option("--vuln-contact <email|url>", "Directory listing: vulnerability-disclosure contact").option("--attest <id>", "Attest (repeatable): guidelines \xB7 own-backend \xB7 no-financial \xB7 no-genai-media \xB7 no-prompt-injection \xB7 no-conversation-data \xB7 public-docs (Claude's seven) \xB7 no-digital-goods \xB7 content-13-no-ads \xB7 no-restricted-data (ChatGPT)", collect, []).option("--allowed-origin <origin>", "Directory mode: an extra browser origin allowed on the MCP host (repeatable)", collect, []).option("--openai-challenge <token>", "ChatGPT: the domain-verification token the OpenAI portal shows under Plugins \u2192 Connect MCP server").action(async (opts) => {
23345
23491
  try {
23346
23492
  const compliant = opts.compliant ?? opts.policy;
23347
23493
  if (compliant !== void 0 && compliant !== false) {
@@ -23367,7 +23513,7 @@ function buildProgram() {
23367
23513
  const connector = program2.command("connector").description(descriptionFor({
23368
23514
  apiblaze: `A compliant Claude connector (--compliant chatgpt: a ChatGPT plugin), directory-ready in one command: from a project or straight from an OpenAPI URL \u2014 creates the ${B.thingShort} if needed, applies the safe fixes, sets up the custom MCP domain (one CNAME), pre-fills every listing answer from the spec, creates the reviewer account, and writes the submission packet when every check passes (you submit it to Anthropic and OpenAI yourself)`,
23369
23515
  mcpblaze: "Make it a Claude connector (--compliant chatgpt: a ChatGPT plugin), directory-ready in one command: the scorecard first, then every open step in order \u2014 the MCP hostname (one CNAME), the listing answers pre-filled from the spec, the reviewer account, the proof run \u2014 and the submission packet when every check passes. Stop any time; `--status` shows what is left and the page to finish on. You submit. They decide."
23370
- })).argument("[project-or-spec]", `The ${B.thingShort} (project name), or an OpenAPI URL/file to create a directory-ready ${B.thingShort} from first`).option("--domain <host>", "Custom hostname for the MCP server (mcp.<your domain>); asked for when missing, suggested from the spec").option("--wait <minutes>", "How long to wait for the custom domain to activate once its CNAME is in place (default 15; 0 = do not wait)").option("--auth-mode <mode>", "How directory clients get in: signin (default) = OAuth sign-in on the connector, API keys alongside; open = no sign-in at all, for public read-only data (Anthropic allows it) \u2014 the API host keeps its own doors. Asked once when every tool is read-only.").option("--name <name>", `When creating from a spec: the ${B.thingShort} name (default: derived from the spec host)`).option("--privacy-url <url>", "Public https privacy policy").option("--support <email|url>", "Support contact").option("--docs-url <url>", "Public documentation URL").option("--prompt <text>", "An example prompt (repeatable; three are needed)", collect, []).option("--server-name <name>", 'Listing name (2\u201340 chars, no "MCP"/"Plugin" suffix)').option("--tagline <text>", "One-line tagline").option("--description <text>", "Description").option("--icon-url <url>", "Square icon (https)").option("--slug <slug>", "Claude: the listing slug (lowercase-with-hyphens; permanent once published)").option("--high-risk <list>", "Claude policy 1A: none, or any of legal,healthcare,insurance,finance").option("--mcp-app", "Claude: the listing is an MCP App (needs 3\u20135 --screenshot)").option("--no-mcp-app", "Claude: a plain connector (default)").option("--screenshot <url=prompt>", "Claude MCP App: a carousel screenshot and the prompt that produced it (repeatable, 3\u20135)", collect, []).option("--vuln-contact <email|url>", "Vulnerability-disclosure contact").option("--attest <id>", "Attest (repeatable): guidelines \xB7 own-backend \xB7 no-financial \xB7 no-genai-media \xB7 no-prompt-injection \xB7 no-conversation-data \xB7 public-docs (Claude's seven) \xB7 no-digital-goods \xB7 content-13-no-ads \xB7 no-restricted-data (ChatGPT). Alone, this only records the attestation.", collect, []).option("--allowed-origin <origin>", "An extra browser origin allowed on the MCP host (repeatable)", collect, []).option("--openai-challenge <token>", "ChatGPT: the domain-verification token the OpenAI portal shows under Plugins \u2192 Connect MCP server; served verbatim at /.well-known/openai-apps-challenge on your MCP domain").option("--data-handling <mode>", "Whose API this is (portal step 7): own \xB7 proxied (add --data-handling-statement) \xB7 third-party. Never pre-filled.").option("--data-handling-statement <text>", "For proxied: the permission you hold (who granted what, and when)").option("--health-data <yes|no>", "The tools handle health data (never pre-filled; yes adds the human-in-the-loop note to the packet)").option("--sponsored-content <yes|no>", "Tool results carry sponsored content (never pre-filled; yes is an unsupported use case)").option("--website-url <url>", "OpenAI's form: the public website (https)").option("--support-url <url>", "OpenAI's form: the support page (https; a URL, not an email)").option("--terms-url <url>", "OpenAI's form: the terms of service page (https)").option("--developer-name <name>", "OpenAI's form: the developer name (\u2264 80; the directory shows your verified identity)").option("--chatgpt-category <name>", "OpenAI's form: one of Productivity \xB7 Creativity \xB7 Developer Tools \xB7 Business & Operations \xB7 Data & Analytics \xB7 Communication \xB7 Education & Research \xB7 Security \xB7 Finance \xB7 Healthcare \xB7 Travel \xB7 Entertainment \xB7 Other").option("--demo-recording-url <url>", "OpenAI's form: the demo recording (required for MCP review)").option("--release-notes <text>", "OpenAI's form: release notes for this submission").option("--short-description <text>", "OpenAI's form: the 30-character subtitle (Claude's tagline stays \u2264 200)").option("--countries <codes>", "OpenAI's form: ISO country codes, comma-separated (default: everywhere)", (v) => v.split(",").map((s) => s.trim()).filter(Boolean)).option("--exercise", "Run every tool now even when the scorecard says step 8 is done (asked only while it is open)").option("--no-exercise", 'Skip the "Run every tool now?" step').option("--step <id>", "Run one step of the scorecard and exit: mode \xB7 address \xB7 access \xB7 tools \xB7 listing \xB7 answers \xB7 attestations \xB7 prove \xB7 signin \xB7 token \xB7 packet").option("--status", "Print the scorecard (what is done, what is left, where) and exit: 0 when ready, 1 while something is left").option("--verbose", "The full rule report at the end instead of the scorecard (also: check --directory-ready)").option("--seed", "Sign-in mode: when a read returns nothing for the reviewer, create a few records through the create tools and keep them (asked when omitted)").option("--no-seed", "Never seed the reviewer account").option("--no-email", "No email at the end of the run").option("--full", "Run the full flow even when only --attest was given").option("--compliant [directory]", "Which directory's policies this run must satisfy: bare = claude; or claude \xB7 chatgpt \xB7 all (repeat or comma-separate)", collect, []).addOption(new import_commander.Option("--policy <directory>", "Older spelling of --compliant").hideHelp()).addOption(new import_commander.Option("--platform <list>", "Older spelling of --compliant").hideHelp()).option("--out <dir>", "Where to write connector-packet-<project>.md/.json (default: current directory)").option("-y, --yes", "No questions: apply the flags, report, exit 1 on a blocker").option("--team <id|name>", "Team the project is in (defaults to your active team)").option("--apiversion <version>", "API version (defaults to the project's)").option("--json", "Output machine-readable JSON").action(action(async (project, opts) => {
23516
+ })).argument("[project-or-spec]", `The ${B.thingShort} (project name), or an OpenAPI URL/file to create a directory-ready ${B.thingShort} from first`).option("--domain <host>", "Custom hostname for the MCP server (mcp.<your domain>); asked for when missing, suggested from the spec").option("--wait <minutes>", "How long to wait for the custom domain to activate once its CNAME is in place (default 15; 0 = do not wait)").option("--target-url <url>", "Where the app runs in production (https): a listing needs the hosted app, not a tunnel; asked when missing").option("--upstream-header <header>", '"Name: value", the header the backend needs to accept these calls, stored encrypted; asked when missing').option("--upstream-header-env <name=var>", "The same with the value read from an environment variable, so it stays out of your shell history").option("--upstream-open", "The backend checks its own credentials: no header").option("--auth-mode <mode>", "How directory clients get in: signin (default) = OAuth sign-in on the connector, API keys alongside; open = no sign-in at all, for public read-only data (Anthropic allows it) \u2014 the API host keeps its own doors. Asked once when every tool is read-only.").option("--name <name>", `When creating from a spec: the ${B.thingShort} name (default: derived from the spec host)`).option("--privacy-url <url>", "Public https privacy policy").option("--support <email|url>", "Support contact").option("--docs-url <url>", "Public documentation URL").option("--prompt <text>", "An example prompt (repeatable; three are needed)", collect, []).option("--server-name <name>", 'Listing name (2\u201340 chars, no "MCP"/"Plugin" suffix)').option("--tagline <text>", "One-line tagline").option("--description <text>", "Description").option("--icon-url <url>", "Square icon (https)").option("--slug <slug>", "Claude: the listing slug (lowercase-with-hyphens; permanent once published)").option("--high-risk <list>", "Claude policy 1A: none, or any of legal,healthcare,insurance,finance").option("--mcp-app", "Claude: the listing is an MCP App (needs 3\u20135 --screenshot)").option("--no-mcp-app", "Claude: a plain connector (default)").option("--screenshot <url=prompt>", "Claude MCP App: a carousel screenshot and the prompt that produced it (repeatable, 3\u20135)", collect, []).option("--vuln-contact <email|url>", "Vulnerability-disclosure contact").option("--attest <id>", "Attest (repeatable): guidelines \xB7 own-backend \xB7 no-financial \xB7 no-genai-media \xB7 no-prompt-injection \xB7 no-conversation-data \xB7 public-docs (Claude's seven) \xB7 no-digital-goods \xB7 content-13-no-ads \xB7 no-restricted-data (ChatGPT). Alone, this only records the attestation.", collect, []).option("--allowed-origin <origin>", "An extra browser origin allowed on the MCP host (repeatable)", collect, []).option("--openai-challenge <token>", "ChatGPT: the domain-verification token the OpenAI portal shows under Plugins \u2192 Connect MCP server; served verbatim at /.well-known/openai-apps-challenge on your MCP domain").option("--data-handling <mode>", "Whose API this is (portal step 7): own \xB7 proxied (add --data-handling-statement) \xB7 third-party. Never pre-filled.").option("--data-handling-statement <text>", "For proxied: the permission you hold (who granted what, and when)").option("--health-data <yes|no>", "The tools handle health data (never pre-filled; yes adds the human-in-the-loop note to the packet)").option("--sponsored-content <yes|no>", "Tool results carry sponsored content (never pre-filled; yes is an unsupported use case)").option("--website-url <url>", "OpenAI's form: the public website (https)").option("--support-url <url>", "OpenAI's form: the support page (https; a URL, not an email)").option("--terms-url <url>", "OpenAI's form: the terms of service page (https)").option("--developer-name <name>", "OpenAI's form: the developer name (\u2264 80; the directory shows your verified identity)").option("--chatgpt-category <name>", "OpenAI's form: one of Productivity \xB7 Creativity \xB7 Developer Tools \xB7 Business & Operations \xB7 Data & Analytics \xB7 Communication \xB7 Education & Research \xB7 Security \xB7 Finance \xB7 Healthcare \xB7 Travel \xB7 Entertainment \xB7 Other").option("--demo-recording-url <url>", "OpenAI's form: the demo recording (required for MCP review)").option("--release-notes <text>", "OpenAI's form: release notes for this submission").option("--short-description <text>", "OpenAI's form: the 30-character subtitle (Claude's tagline stays \u2264 200)").option("--countries <codes>", "OpenAI's form: ISO country codes, comma-separated (default: everywhere)", (v) => v.split(",").map((s) => s.trim()).filter(Boolean)).option("--exercise", "Run every tool now even when the scorecard says step 8 is done (asked only while it is open)").option("--no-exercise", 'Skip the "Run every tool now?" step').option("--step <id>", "Run one step of the scorecard and exit: mode \xB7 address \xB7 access \xB7 tools \xB7 listing \xB7 answers \xB7 attestations \xB7 prove \xB7 signin \xB7 token \xB7 packet").option("--status", "Print the scorecard (what is done, what is left, where) and exit: 0 when ready, 1 while something is left").option("--verbose", "The full rule report at the end instead of the scorecard (also: check --directory-ready)").option("--seed", "Sign-in mode: when a read returns nothing for the reviewer, create a few records through the create tools and keep them (asked when omitted)").option("--no-seed", "Never seed the reviewer account").option("--no-email", "No email at the end of the run").option("--full", "Run the full flow even when only --attest was given").option("--compliant [directory]", "Which directory's policies this run must satisfy: bare = claude; or claude \xB7 chatgpt \xB7 all (repeat or comma-separate)", collect, []).addOption(new import_commander.Option("--policy <directory>", "Older spelling of --compliant").hideHelp()).addOption(new import_commander.Option("--platform <list>", "Older spelling of --compliant").hideHelp()).option("--out <dir>", "Where to write connector-packet-<project>.md/.json (default: current directory)").option("-y, --yes", "No questions: apply the flags, report, exit 1 on a blocker").option("--team <id|name>", "Team the project is in (defaults to your active team)").option("--apiversion <version>", "API version (defaults to the project's)").option("--json", "Output machine-readable JSON").action(action(async (project, opts) => {
23371
23517
  if (!project) throw new Error(`Which ${B.thingShort}? ${B.cli} connector <project> \xB7 ${B.cli} connector https://\u2026/openapi.yaml \xB7 ${B.cli} connector reviewer <project> \xB7 ${B.cli} connector exercise <project> \xB7 ${B.cli} connector answers <project>`);
23372
23518
  await runConnector(project, opts);
23373
23519
  }));