apiblaze 0.21.38 → 0.21.40

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 +122 -42
  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.38";
37
+ version = "0.21.40";
38
38
  }
39
39
  });
40
40
 
@@ -137,21 +137,26 @@ function handleUpgradeRequired(err) {
137
137
  })();
138
138
  return handling;
139
139
  }
140
+ function cliHeaders() {
141
+ if (!guardVersion) return {};
142
+ const h = { [CLI_VERSION_HEADER]: guardVersion, "user-agent": `apiblaze-cli/${guardVersion}` };
143
+ const command = getCommandLabel();
144
+ if (command) {
145
+ h[CLI_COMMAND_HEADER] = command;
146
+ h[CLI_RUN_HEADER] = getRunId();
147
+ }
148
+ return h;
149
+ }
140
150
  function installFetchGuard(version2) {
141
151
  if (installed || typeof globalThis.fetch !== "function") return;
142
152
  installed = true;
153
+ guardVersion = version2;
143
154
  const base2 = globalThis.fetch.bind(globalThis);
144
155
  globalThis.fetch = (async (input, init) => {
145
156
  const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
146
157
  if (!isControlPlaneHost(url)) return base2(input, init);
147
158
  const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
148
- headers.set(CLI_VERSION_HEADER, version2);
149
- const command = getCommandLabel();
150
- if (command) {
151
- headers.set(CLI_COMMAND_HEADER, command);
152
- headers.set(CLI_RUN_HEADER, getRunId());
153
- }
154
- if (!headers.has("user-agent")) headers.set("user-agent", `apiblaze-cli/${version2}`);
159
+ for (const [k, v] of Object.entries(cliHeaders())) if (k !== "user-agent" || !headers.has(k)) headers.set(k, v);
155
160
  const res = await base2(input, { ...init, headers });
156
161
  if (res.status === 426) {
157
162
  let body = null;
@@ -237,7 +242,7 @@ function watchCliPolicy(version2) {
237
242
  t.unref?.();
238
243
  return () => clearInterval(t);
239
244
  }
240
- var import_fs, import_os, import_path, import_chalk, DASHBOARD_BASE, CACHE_MS, UPGRADE_EXIT_CODE, CONTROL_PLANE_HOSTS, CONTROL_PLANE_ENV, CliUpgradeRequired, shutdownHook, handling, installed;
245
+ var import_fs, import_os, import_path, import_chalk, DASHBOARD_BASE, CACHE_MS, UPGRADE_EXIT_CODE, CONTROL_PLANE_HOSTS, CONTROL_PLANE_ENV, CliUpgradeRequired, shutdownHook, handling, guardVersion, installed;
241
246
  var init_version_guard = __esm({
242
247
  "src/lib/version-guard.ts"() {
243
248
  "use strict";
@@ -273,6 +278,7 @@ var init_version_guard = __esm({
273
278
  };
274
279
  shutdownHook = null;
275
280
  handling = null;
281
+ guardVersion = "";
276
282
  installed = false;
277
283
  }
278
284
  });
@@ -372,6 +378,7 @@ __export(api_exports, {
372
378
  bothDoorsBody: () => bothDoorsBody,
373
379
  checkProxyName: () => checkProxyName,
374
380
  claimTeam: () => claimTeam,
381
+ countRun: () => countRun,
375
382
  createProxy: () => createProxy,
376
383
  createProxyAnonymous: () => createProxyAnonymous,
377
384
  deleteDevTunnel: () => deleteDevTunnel,
@@ -385,6 +392,21 @@ __export(api_exports, {
385
392
  putDevTunnel: () => putDevTunnel,
386
393
  sidecarInitAnonymous: () => sidecarInitAnonymous
387
394
  });
395
+ function countRun(opts = {}) {
396
+ if (/^(1|true|yes)$/i.test((process.env.DO_NOT_TRACK ?? "").trim())) return;
397
+ try {
398
+ const child = (0, import_child_process.spawn)(process.execPath, ["-e", COUNT_RUN_CHILD], {
399
+ detached: true,
400
+ stdio: "ignore",
401
+ windowsHide: true,
402
+ env: { ...process.env, ABZ_COUNT_URL: opts.url ?? `${PUBLIC_API_BASE}/cli/hello`, ABZ_COUNT_HEADERS: JSON.stringify(cliHeaders()) }
403
+ });
404
+ child.on("error", () => {
405
+ });
406
+ child.unref();
407
+ } catch {
408
+ }
409
+ }
388
410
  async function createProxyAnonymous(body) {
389
411
  const res = await fetch(`${PUBLIC_API_BASE}/proxy`, {
390
412
  method: "POST",
@@ -543,15 +565,18 @@ function integrationKitCall(project, stack) {
543
565
  summary: `Integration kit for ${project} (${stack})`
544
566
  };
545
567
  }
546
- var import_yaml, DASHBOARD_BASE2, PUBLIC_API_BASE, GITHUB_LOGIN, LOCAL_SPEC_PATHS, INTEGRATION_STACKS;
568
+ var import_child_process, import_yaml, DASHBOARD_BASE2, PUBLIC_API_BASE, COUNT_RUN_CHILD, GITHUB_LOGIN, LOCAL_SPEC_PATHS, INTEGRATION_STACKS;
547
569
  var init_api = __esm({
548
570
  "src/lib/api.ts"() {
549
571
  "use strict";
572
+ import_child_process = require("child_process");
550
573
  init_auth();
574
+ init_version_guard();
551
575
  import_yaml = require("yaml");
552
576
  init_types();
553
577
  DASHBOARD_BASE2 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
554
578
  PUBLIC_API_BASE = "https://api.apiblaze.com";
579
+ COUNT_RUN_CHILD = "fetch(process.env.ABZ_COUNT_URL,{method:'POST',headers:JSON.parse(process.env.ABZ_COUNT_HEADERS||'{}'),signal:AbortSignal.timeout(5000)}).then((r)=>r.body&&r.body.cancel(),()=>{})";
555
580
  GITHUB_LOGIN = { providers: [{ type: "github", managed: true }] };
556
581
  LOCAL_SPEC_PATHS = ["/openapi.json", "/openapi.yaml", "/docs/openapi.json"];
557
582
  INTEGRATION_STACKS = ["nextjs", "express", "fastapi", "other"];
@@ -2281,7 +2306,7 @@ function waitForClaudeConnection(name, timeoutMs = 12e3) {
2281
2306
  for (; ; ) {
2282
2307
  last = claudeServerStatus(name);
2283
2308
  if (last === "connected" || Date.now() >= deadline) return last;
2284
- (0, import_child_process.spawnSync)(process.execPath, ["-e", "setTimeout(()=>{},1200)"], { timeout: 3e3 });
2309
+ (0, import_child_process2.spawnSync)(process.execPath, ["-e", "setTimeout(()=>{},1200)"], { timeout: 3e3 });
2285
2310
  }
2286
2311
  }
2287
2312
  function claudeOneShot(spec2, prompt) {
@@ -2632,18 +2657,18 @@ async function installAndDemo(cli, spec2, getQuestion, log4 = console.log) {
2632
2657
  log4(import_chalk12.default.red(` ${import_chalk12.default.bold(off)}`));
2633
2658
  return true;
2634
2659
  }
2635
- var fs6, os4, path7, import_child_process, import_chalk12, useShell, winQuote, run, detected, mcpLoginSupport, OURS, mask, tomlStr, shellQuote, marker;
2660
+ var fs6, os4, path7, import_child_process2, import_chalk12, useShell, winQuote, run, detected, mcpLoginSupport, OURS, mask, tomlStr, shellQuote, marker;
2636
2661
  var init_external_mcp = __esm({
2637
2662
  "src/lib/external-mcp.ts"() {
2638
2663
  "use strict";
2639
2664
  fs6 = __toESM(require("fs"));
2640
2665
  os4 = __toESM(require("os"));
2641
2666
  path7 = __toESM(require("path"));
2642
- import_child_process = require("child_process");
2667
+ import_child_process2 = require("child_process");
2643
2668
  import_chalk12 = __toESM(require("chalk"));
2644
2669
  useShell = process.platform === "win32";
2645
2670
  winQuote = (a) => /^[A-Za-z0-9_\-.:/\\=]+$/.test(a) ? a : `"${a.replace(/"/g, '""')}"`;
2646
- run = (cmd, args, opts = {}) => (0, import_child_process.spawnSync)(cmd, useShell ? args.map(winQuote) : args, {
2671
+ run = (cmd, args, opts = {}) => (0, import_child_process2.spawnSync)(cmd, useShell ? args.map(winQuote) : args, {
2647
2672
  encoding: "utf-8",
2648
2673
  stdio: opts.interactive ? ["inherit", "inherit", "inherit"] : opts.inherit ? ["ignore", "inherit", "inherit"] : ["ignore", "pipe", "pipe"],
2649
2674
  timeout: opts.inherit || opts.interactive ? void 0 : 15e3,
@@ -2952,7 +2977,7 @@ function decodeJwt2(token) {
2952
2977
  function openBrowser2(url) {
2953
2978
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
2954
2979
  try {
2955
- (0, import_child_process2.spawn)(cmd, [url], { stdio: "ignore", detached: true }).unref();
2980
+ (0, import_child_process3.spawn)(cmd, [url], { stdio: "ignore", detached: true }).unref();
2956
2981
  } catch {
2957
2982
  }
2958
2983
  }
@@ -3028,7 +3053,7 @@ async function validConsumerToken(creds) {
3028
3053
  if (Date.now() < creds.expiresAt - 3e4) return creds;
3029
3054
  return refreshConsumer(creds);
3030
3055
  }
3031
- var fs7, os5, path8, crypto, import_child_process2, AUTH_BASE, APIBLAZE_DIR2, CONSUMER_PATH, DEVICE_GRANT;
3056
+ var fs7, os5, path8, crypto, import_child_process3, AUTH_BASE, APIBLAZE_DIR2, CONSUMER_PATH, DEVICE_GRANT;
3032
3057
  var init_consumer_auth = __esm({
3033
3058
  "src/lib/consumer-auth.ts"() {
3034
3059
  "use strict";
@@ -3036,7 +3061,7 @@ var init_consumer_auth = __esm({
3036
3061
  os5 = __toESM(require("os"));
3037
3062
  path8 = __toESM(require("path"));
3038
3063
  crypto = __toESM(require("crypto"));
3039
- import_child_process2 = require("child_process");
3064
+ import_child_process3 = require("child_process");
3040
3065
  AUTH_BASE = process.env.APIBLAZE_AUTH_BASE || "https://auth.apiblaze.com";
3041
3066
  APIBLAZE_DIR2 = path8.join(os5.homedir(), ".apiblaze");
3042
3067
  CONSUMER_PATH = path8.join(APIBLAZE_DIR2, "consumer.json");
@@ -4738,7 +4763,7 @@ async function removeExternalMcp(projectId, cliKind) {
4738
4763
  const label3 = kind === "claude" ? "Claude CLI" : "Codex CLI";
4739
4764
  let removed = false;
4740
4765
  if (kind === "claude") {
4741
- const r = (0, import_child_process3.spawnSync)("claude", ["mcp", "remove", projectId], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 15e3 });
4766
+ const r = (0, import_child_process4.spawnSync)("claude", ["mcp", "remove", projectId], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 15e3 });
4742
4767
  removed = r.status === 0;
4743
4768
  } else {
4744
4769
  removed = removeCodexServer(projectId);
@@ -4842,14 +4867,14 @@ async function runApichat(opts) {
4842
4867
  if (mcpUrl2 && await maybeInstallExternalCli(p, opts)) return;
4843
4868
  await startChat(p, [], opts);
4844
4869
  }
4845
- var fs9, path9, crypto2, import_child_process3, import_chalk15, import_ora2, import_yaml3, GENERATOR_HINT, revealAuth, apichatsPath;
4870
+ var fs9, path9, crypto2, import_child_process4, import_chalk15, import_ora2, import_yaml3, GENERATOR_HINT, revealAuth, apichatsPath;
4846
4871
  var init_apichat = __esm({
4847
4872
  "src/commands/apichat.ts"() {
4848
4873
  "use strict";
4849
4874
  fs9 = __toESM(require("fs"));
4850
4875
  path9 = __toESM(require("path"));
4851
4876
  crypto2 = __toESM(require("crypto"));
4852
- import_child_process3 = require("child_process");
4877
+ import_child_process4 = require("child_process");
4853
4878
  import_chalk15 = __toESM(require("chalk"));
4854
4879
  import_ora2 = __toESM(require("ora"));
4855
4880
  import_yaml3 = require("yaml");
@@ -7659,6 +7684,7 @@ __export(demo_exports, {
7659
7684
  DEMO_RPS: () => DEMO_RPS,
7660
7685
  demoName: () => demoName,
7661
7686
  isDemoProcess: () => isDemoProcess,
7687
+ portFree: () => portFree,
7662
7688
  routesOf: () => routesOf,
7663
7689
  runDemo: () => runDemo,
7664
7690
  runDemoLogs: () => runDemoLogs,
@@ -7670,13 +7696,27 @@ __export(demo_exports, {
7670
7696
  function demoName() {
7671
7697
  return `demo${pick2(ADJ)}${pick2(NOUN)}${import_crypto.default.randomBytes(2).toString("hex")}`;
7672
7698
  }
7673
- function portFree(port) {
7674
- return new Promise((resolve4) => {
7699
+ async function portFree(port) {
7700
+ const answers = (host) => new Promise((resolve4) => {
7701
+ const sock = import_net2.default.connect({ port, host });
7702
+ sock.setTimeout(1e3, () => {
7703
+ sock.destroy();
7704
+ resolve4(true);
7705
+ });
7706
+ sock.once("connect", () => {
7707
+ sock.destroy();
7708
+ resolve4(true);
7709
+ });
7710
+ sock.once("error", () => resolve4(false));
7711
+ });
7712
+ const bindable = (host) => new Promise((resolve4) => {
7675
7713
  const s = import_net2.default.createServer();
7676
- s.once("error", () => resolve4(false));
7714
+ s.once("error", (e) => resolve4(host === "::1" && (e.code === "EADDRNOTAVAIL" || e.code === "EAFNOSUPPORT")));
7677
7715
  s.once("listening", () => s.close(() => resolve4(true)));
7678
- s.listen(port, "127.0.0.1");
7716
+ s.listen(port, host);
7679
7717
  });
7718
+ const [v4, v6] = await Promise.all([answers("127.0.0.1"), answers("::1")]);
7719
+ return !v4 && !v6 && await bindable("127.0.0.1") && await bindable("::1");
7680
7720
  }
7681
7721
  async function freePort(from, avoid = []) {
7682
7722
  for (let p = from; p < from + 200; p++) if (!avoid.includes(p) && await portFree(p)) return p;
@@ -7737,15 +7777,16 @@ async function stopTunnels() {
7737
7777
  }
7738
7778
  function appCtl(dir, arg) {
7739
7779
  if (!import_fs6.default.existsSync(import_path5.default.join(dir, "start.js"))) return false;
7740
- const r = (0, import_child_process4.spawnSync)(process.execPath, [import_path5.default.join(dir, "start.js"), arg], { cwd: dir, stdio: "ignore", timeout: 15e3 });
7780
+ const r = (0, import_child_process5.spawnSync)(process.execPath, [import_path5.default.join(dir, "start.js"), arg], { cwd: dir, stdio: "ignore", timeout: 15e3 });
7741
7781
  return r.status === 0;
7742
7782
  }
7743
7783
  function isDemoProcess(args) {
7744
- return /[\\/](apiblaze|mcpblaze)-demo[\\/]start\.js(\s|$)/.test(args) || /\sdemo --serve\s/.test(args);
7784
+ const node = String.raw`^(?:\S*[\\/])?node(?:\.exe)?\s+`;
7785
+ return new RegExp(node + String.raw`.*[\\/](?:apiblaze|mcpblaze)-demo[\\/]start\.js$`).test(args.trim()) || new RegExp(node + String.raw`\S.*\sdemo --serve\s`).test(args);
7745
7786
  }
7746
7787
  function demoProcesses() {
7747
7788
  if (process.platform === "win32") return [];
7748
- const r = (0, import_child_process4.spawnSync)("ps", ["-Ao", "pid=,args="], { encoding: "utf8" });
7789
+ const r = (0, import_child_process5.spawnSync)("ps", ["-Ao", "pid=,args="], { encoding: "utf8" });
7749
7790
  if (r.status !== 0 || !r.stdout) return [];
7750
7791
  const out = [];
7751
7792
  for (const line of r.stdout.split("\n")) {
@@ -7918,7 +7959,7 @@ function openBrowser3(url) {
7918
7959
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
7919
7960
  const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
7920
7961
  try {
7921
- (0, import_child_process4.spawn)(cmd, args, { stdio: "ignore", detached: true }).on("error", () => {
7962
+ (0, import_child_process5.spawn)(cmd, args, { stdio: "ignore", detached: true }).on("error", () => {
7922
7963
  }).unref();
7923
7964
  } catch {
7924
7965
  }
@@ -8204,7 +8245,7 @@ function printAddresses(dir) {
8204
8245
  }
8205
8246
  async function spawnTunnel(dir, state) {
8206
8247
  const log4 = import_fs6.default.openSync(import_path5.default.join(dir, STATE_DIR, "tunnel.log"), "a");
8207
- const child = (0, import_child_process4.spawn)(process.execPath, [process.argv[1], "demo", "--serve", dir], { cwd: dir, detached: true, stdio: ["ignore", log4, log4] });
8248
+ const child = (0, import_child_process5.spawn)(process.execPath, [process.argv[1], "demo", "--serve", dir], { cwd: dir, detached: true, stdio: ["ignore", log4, log4] });
8208
8249
  child.unref();
8209
8250
  saveState(dir, { ...state, pid: child.pid, ready: false, error: void 0 });
8210
8251
  registerDemo(dir, child.pid ?? 0);
@@ -8306,14 +8347,14 @@ async function serveTunnel(dir) {
8306
8347
  await new Promise(() => {
8307
8348
  });
8308
8349
  }
8309
- var import_fs6, import_path5, import_net2, import_child_process4, import_crypto, import_chalk24, import_ora9, DIR_NAME, STATE_DIR, LATEST, DEMO_RPS, DEMO_ADMIN_EMAIL, DEMO_GINO_ADMIN_EMAIL, RULE_SENTENCE, DemoError, ADJ, NOUN, pick2, registryFile, alive, interactive, logsCommand;
8350
+ var import_fs6, import_path5, import_net2, import_child_process5, import_crypto, import_chalk24, import_ora9, DIR_NAME, STATE_DIR, LATEST, DEMO_RPS, DEMO_ADMIN_EMAIL, DEMO_GINO_ADMIN_EMAIL, RULE_SENTENCE, DemoError, ADJ, NOUN, pick2, registryFile, alive, interactive, logsCommand;
8310
8351
  var init_demo = __esm({
8311
8352
  "src/commands/demo.ts"() {
8312
8353
  "use strict";
8313
8354
  import_fs6 = __toESM(require("fs"));
8314
8355
  import_path5 = __toESM(require("path"));
8315
8356
  import_net2 = __toESM(require("net"));
8316
- import_child_process4 = require("child_process");
8357
+ import_child_process5 = require("child_process");
8317
8358
  import_crypto = __toESM(require("crypto"));
8318
8359
  import_chalk24 = __toESM(require("chalk"));
8319
8360
  import_ora9 = __toESM(require("ora"));
@@ -8587,7 +8628,7 @@ __export(op_anon_exports, {
8587
8628
  function runCli(args, cwd, home, timeoutMs) {
8588
8629
  return new Promise((resolve4) => {
8589
8630
  const t0 = Date.now();
8590
- const child = (0, import_child_process5.spawn)(process.execPath, [process.argv[1], ...args], { cwd, env: { ...process.env, HOME: home, USERPROFILE: home }, stdio: ["ignore", "pipe", "pipe"] });
8631
+ const child = (0, import_child_process6.spawn)(process.execPath, [process.argv[1], ...args], { cwd, env: { ...process.env, HOME: home, USERPROFILE: home }, stdio: ["ignore", "pipe", "pipe"] });
8591
8632
  let out = "";
8592
8633
  child.stdout.on("data", (d) => {
8593
8634
  out += d;
@@ -8703,7 +8744,7 @@ async function journey(label3, work, home, checks) {
8703
8744
  }
8704
8745
  async function runOpAnon(o = {}) {
8705
8746
  const t0 = Date.now();
8706
- const root = import_fs10.default.mkdtempSync(import_path7.default.join(import_os2.default.tmpdir(), `${B.cli}-op-anon-`));
8747
+ const root = import_fs10.default.mkdtempSync(import_path7.default.join(import_os3.default.tmpdir(), `${B.cli}-op-anon-`));
8707
8748
  const home = import_path7.default.join(root, "home");
8708
8749
  const work = import_path7.default.join(root, "work");
8709
8750
  import_fs10.default.mkdirSync(home);
@@ -8721,7 +8762,7 @@ async function runOpAnon(o = {}) {
8721
8762
  const demoFolder = import_path7.default.join(work, `${B.cli}-demo`);
8722
8763
  if (import_fs10.default.existsSync(import_path7.default.join(demoFolder, "start.js"))) {
8723
8764
  await new Promise((res) => {
8724
- const c = (0, import_child_process5.spawn)(process.execPath, [import_path7.default.join(demoFolder, "start.js"), "--stop"], { cwd: demoFolder, stdio: "ignore" });
8765
+ const c = (0, import_child_process6.spawn)(process.execPath, [import_path7.default.join(demoFolder, "start.js"), "--stop"], { cwd: demoFolder, stdio: "ignore" });
8725
8766
  c.on("close", () => res());
8726
8767
  });
8727
8768
  }
@@ -8745,14 +8786,14 @@ async function runOpAnon(o = {}) {
8745
8786
  if (failed) process.exitCode = 1;
8746
8787
  return { ok: !failed, checks };
8747
8788
  }
8748
- var import_fs10, import_os2, import_path7, import_child_process5, import_chalk70, SECRET;
8789
+ var import_fs10, import_os3, import_path7, import_child_process6, import_chalk70, SECRET;
8749
8790
  var init_op_anon = __esm({
8750
8791
  "src/commands/op-anon.ts"() {
8751
8792
  "use strict";
8752
8793
  import_fs10 = __toESM(require("fs"));
8753
- import_os2 = __toESM(require("os"));
8794
+ import_os3 = __toESM(require("os"));
8754
8795
  import_path7 = __toESM(require("path"));
8755
- import_child_process5 = require("child_process");
8796
+ import_child_process6 = require("child_process");
8756
8797
  import_chalk70 = __toESM(require("chalk"));
8757
8798
  init_brand();
8758
8799
  SECRET = /\bsk_(?:dev|test|prod)_[A-Za-z0-9]{6,}/;
@@ -9280,6 +9321,7 @@ init_create();
9280
9321
 
9281
9322
  // src/commands/skill.ts
9282
9323
  var import_fs7 = __toESM(require("fs"));
9324
+ var import_os2 = __toESM(require("os"));
9283
9325
  var import_path6 = __toESM(require("path"));
9284
9326
  var import_chalk25 = __toESM(require("chalk"));
9285
9327
  init_brand();
@@ -9545,6 +9587,7 @@ function backendPort(f) {
9545
9587
  }
9546
9588
 
9547
9589
  // src/commands/skill.ts
9590
+ init_api();
9548
9591
  var SKILL_NAME = "ship-safely";
9549
9592
  var SKILL_RELATIVE_PATH = import_path6.default.join(".claude", "skills", SKILL_NAME, "SKILL.md");
9550
9593
  var CP_TOOLS = [
@@ -9602,7 +9645,32 @@ function folderReport(f, opts = {}) {
9602
9645
  ownApi: true
9603
9646
  };
9604
9647
  }
9605
- function heroMarkdown(found) {
9648
+ function blockedMarkdown() {
9649
+ return `## If a command is blocked or fails
9650
+
9651
+ A permission prompt declined, a command denied, or a step needing access you do not have:
9652
+ - **A step the rest depends on** (the tunnel, creating the proxy, its key): stop there. In one
9653
+ line, say what it was for and give the user the exact command to run themselves
9654
+ (\`! <command>\` in Claude Code). Then wait. If they would rather not, say it stops here.
9655
+ - **An optional step** (groups, admins, widgets, a rule, limits): skip it. Say in one line what
9656
+ is missing because of it, and carry on with what does not need it.
9657
+ - **Always:** never retry it in pieces, take another route, or write code to replace it. Never
9658
+ say something works until you have checked it: a call that answered, or a page you loaded.
9659
+ `;
9660
+ }
9661
+ function staleSkillCopies(cwd = process.cwd(), home = import_os2.default.homedir()) {
9662
+ const current = skillMarkdown();
9663
+ const out = [];
9664
+ for (const dir of /* @__PURE__ */ new Set([cwd, home])) {
9665
+ const f = import_path6.default.join(dir, SKILL_RELATIVE_PATH);
9666
+ try {
9667
+ if (import_fs7.default.readFileSync(f, "utf8") !== current) out.push(f);
9668
+ } catch {
9669
+ }
9670
+ }
9671
+ return out;
9672
+ }
9673
+ function heroMarkdown(found, stale = []) {
9606
9674
  const P = B.product;
9607
9675
  const run2 = `npx ${B.cli}@latest`;
9608
9676
  const report = found ? folderReport(found) : null;
@@ -9644,6 +9712,15 @@ description: Use when the user asks what ${P} (or ${B.cli}) does or can do for t
9644
9712
 
9645
9713
  # ${P}
9646
9714
 
9715
+ This output is current: it replaces any copy of this skill loaded earlier.
9716
+ ${stale.length ? `
9717
+ ## Outdated copies are installed: ignore them
9718
+
9719
+ ${stale.map((f) => `- \`${f}\``).join("\n")}
9720
+
9721
+ They hold an older walkthrough. Follow only what this output says. Tell the user once that the
9722
+ file is outdated (re-run \`${run2} skills --install --force\` in that folder to refresh it).
9723
+ ` : ""}
9647
9724
  ${folder}
9648
9725
  ## Explain: they ask what ${P} does or can do for them
9649
9726
 
@@ -9670,6 +9747,7 @@ Rules for the demo: keep each update to one line. Do not narrate steps, read the
9670
9747
  files, open logs, run other commands, or write code. Never show a key: the demo saves it
9671
9748
  in \`.env.local\` and never prints it.
9672
9749
 
9750
+ ${blockedMarkdown()}
9673
9751
  ## Their own app: they say yes after the demo
9674
9752
 
9675
9753
  Their app runs on this machine \u2192 it will use \`${run2} dev\`; it is deployed \u2192 \`${run2} create\`.
@@ -9702,7 +9780,8 @@ No code yet? Write the smallest plain backend that does exactly that, plus its \
9702
9780
  `;
9703
9781
  return withLatest(`# Put ${B.product} in front of their app
9704
9782
 
9705
- ${backendRules}${at >= 0 ? legacy.slice(at) : legacy}`);
9783
+ ${backendRules}${blockedMarkdown()}
9784
+ ${at >= 0 ? legacy.slice(at) : legacy}`);
9706
9785
  }
9707
9786
  function skillMarkdown() {
9708
9787
  return `${heroMarkdown()}
@@ -10152,6 +10231,7 @@ async function runForPerson(found) {
10152
10231
  await runDemo2({});
10153
10232
  }
10154
10233
  async function runSkill(opts = {}) {
10234
+ countRun();
10155
10235
  if (opts.install) return installSkill(opts);
10156
10236
  if (opts.static) {
10157
10237
  process.stdout.write(skillMarkdown());
@@ -10169,7 +10249,7 @@ async function runSkill(opts = {}) {
10169
10249
  }
10170
10250
  const found = await detectBackend(process.cwd());
10171
10251
  if (readByAgent(opts)) {
10172
- process.stdout.write(heroMarkdown(found));
10252
+ process.stdout.write(heroMarkdown(found, staleSkillCopies()));
10173
10253
  return;
10174
10254
  }
10175
10255
  await runForPerson(found);
@@ -13445,10 +13525,10 @@ async function runBillingTopup(amount, opts) {
13445
13525
  if (c?.auto_rebuy?.enabled) console.log(import_chalk48.default.dim(` Auto-rebuy is on (${money(c.auto_rebuy.amount_cents)} under ${money(c.auto_rebuy.threshold_cents)}).`));
13446
13526
  else console.log(import_chalk48.default.dim(` Never run dry: ${B.cli} billing rebuy on --amount 50 --threshold 10`));
13447
13527
  if (opts.open) {
13448
- const { spawn: spawn4 } = await import("child_process");
13528
+ const { spawn: spawn5 } = await import("child_process");
13449
13529
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
13450
13530
  try {
13451
- spawn4(cmd, [url], { stdio: "ignore", detached: true }).unref();
13531
+ spawn5(cmd, [url], { stdio: "ignore", detached: true }).unref();
13452
13532
  } catch {
13453
13533
  }
13454
13534
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.21.38",
3
+ "version": "0.21.40",
4
4
  "description": "APIblaze CLI — Chat with your APIs, Manage your API keys, users and groups with the APIblaze serverless proxy",
5
5
  "keywords": [
6
6
  "apiblaze",