apiblaze 0.20.26 → 0.20.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +117 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1024,7 +1024,7 @@ var import_commander = require("commander");
|
|
|
1024
1024
|
var import_chalk54 = __toESM(require("chalk"));
|
|
1025
1025
|
|
|
1026
1026
|
// package.json
|
|
1027
|
-
var version = "0.20.
|
|
1027
|
+
var version = "0.20.31";
|
|
1028
1028
|
|
|
1029
1029
|
// src/index.ts
|
|
1030
1030
|
init_types();
|
|
@@ -2414,7 +2414,7 @@ function claudeOneShot(spec2, prompt) {
|
|
|
2414
2414
|
return { argv, status: r.status };
|
|
2415
2415
|
}
|
|
2416
2416
|
function claudeInteractive(spec2, prompt) {
|
|
2417
|
-
const argv = ["claude", prompt, "--allowedTools", `mcp__${spec2.name}__
|
|
2417
|
+
const argv = ["claude", prompt, "--allowedTools", `mcp__${spec2.name}__*`, "--append-system-prompt", claudeSystemHint(spec2)];
|
|
2418
2418
|
const r = run(argv[0], argv.slice(1), { interactive: true });
|
|
2419
2419
|
return { argv, status: r.status };
|
|
2420
2420
|
}
|
|
@@ -2492,17 +2492,92 @@ function installIntoCodex(spec2) {
|
|
|
2492
2492
|
return { ok: false, error: err instanceof Error ? err.message : String(err), path: file };
|
|
2493
2493
|
}
|
|
2494
2494
|
}
|
|
2495
|
+
function codexSiblingApiblazeServers(keepName) {
|
|
2496
|
+
try {
|
|
2497
|
+
const text = fs5.readFileSync(codexConfigPath(), "utf-8");
|
|
2498
|
+
const lines = text.split("\n");
|
|
2499
|
+
const out = [];
|
|
2500
|
+
const header = /^\[mcp_servers\.(?:"([^"]+)"|([^\]]+))\]\s*(#.*)?$/;
|
|
2501
|
+
const anyHeader = /^\s*\[[^\]]+\]\s*(#.*)?$/;
|
|
2502
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2503
|
+
const m = lines[i].match(header);
|
|
2504
|
+
if (!m) continue;
|
|
2505
|
+
const name = m[1] ?? m[2];
|
|
2506
|
+
let end = lines.length;
|
|
2507
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
2508
|
+
if (anyHeader.test(lines[j])) {
|
|
2509
|
+
end = j;
|
|
2510
|
+
break;
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
const body = lines.slice(i, end).join("\n");
|
|
2514
|
+
const url = body.match(/^\s*url\s*=\s*"([^"]*)"/m)?.[1];
|
|
2515
|
+
if (name && name !== keepName && url && OURS.test(url)) out.push(name);
|
|
2516
|
+
i = end - 1;
|
|
2517
|
+
}
|
|
2518
|
+
return out;
|
|
2519
|
+
} catch {
|
|
2520
|
+
return [];
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
async function mcpEndpointIsDead(url) {
|
|
2524
|
+
try {
|
|
2525
|
+
const res = await fetch(url, {
|
|
2526
|
+
method: "POST",
|
|
2527
|
+
headers: { "Content-Type": "application/json" },
|
|
2528
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list" }),
|
|
2529
|
+
signal: AbortSignal.timeout(8e3)
|
|
2530
|
+
});
|
|
2531
|
+
if (res.status === 401 || res.status === 403) return false;
|
|
2532
|
+
if (res.status === 404 || res.status >= 500) return true;
|
|
2533
|
+
return false;
|
|
2534
|
+
} catch {
|
|
2535
|
+
return false;
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
function codexServerUrl(name) {
|
|
2539
|
+
try {
|
|
2540
|
+
const lines = fs5.readFileSync(codexConfigPath(), "utf-8").split("\n");
|
|
2541
|
+
const ranges = codexSectionRanges(lines, name);
|
|
2542
|
+
if (!ranges.length) return null;
|
|
2543
|
+
const body = lines.slice(ranges[0].start, ranges[0].end).join("\n");
|
|
2544
|
+
return body.match(/^\s*url\s*=\s*"([^"]*)"/m)?.[1] ?? null;
|
|
2545
|
+
} catch {
|
|
2546
|
+
return null;
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
function removeCodexServer(name) {
|
|
2550
|
+
try {
|
|
2551
|
+
const file = codexConfigPath();
|
|
2552
|
+
const lines = fs5.readFileSync(file, "utf-8").split("\n");
|
|
2553
|
+
const ranges = codexSectionRanges(lines, name);
|
|
2554
|
+
if (!ranges.length) return false;
|
|
2555
|
+
for (const r of [...ranges].reverse()) lines.splice(r.start, r.end - r.start);
|
|
2556
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
2557
|
+
fs5.writeFileSync(tmp, lines.join("\n"), { encoding: "utf-8", mode: 384 });
|
|
2558
|
+
fs5.renameSync(tmp, file);
|
|
2559
|
+
return true;
|
|
2560
|
+
} catch {
|
|
2561
|
+
return false;
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2495
2564
|
function codexOneShot(_spec, prompt) {
|
|
2496
2565
|
const argv = ["codex", "exec", "--skip-git-repo-check", prompt];
|
|
2497
2566
|
const r = run(argv[0], argv.slice(1), { inherit: true });
|
|
2498
2567
|
return { argv, status: r.status };
|
|
2499
2568
|
}
|
|
2500
2569
|
function codexInteractive(_spec, prompt) {
|
|
2501
|
-
const argv = ["codex",
|
|
2570
|
+
const argv = ["codex", prompt];
|
|
2502
2571
|
const r = run(argv[0], argv.slice(1), { interactive: true });
|
|
2503
2572
|
return { argv, status: r.status };
|
|
2504
2573
|
}
|
|
2505
2574
|
var shellQuote = (s) => `"${s.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
2575
|
+
function directedPrompt(spec2, question) {
|
|
2576
|
+
return `Use the "${spec2.name}" MCP server (it exposes this API's tools) to answer: ${question}`;
|
|
2577
|
+
}
|
|
2578
|
+
function claudeSystemHint(spec2) {
|
|
2579
|
+
return `You are connected to the "${spec2.name}" MCP server, which exposes the ${spec2.projectLabel} API as tools (mcp__${spec2.name}__*). For any question about this API, call those tools rather than answering from memory or asking the user for data the API can provide.`;
|
|
2580
|
+
}
|
|
2506
2581
|
function renderCommand(argv) {
|
|
2507
2582
|
return argv.map((a, i) => i === 0 || /^[A-Za-z0-9_@%+=:,./-]+$/.test(a) ? a : shellQuote(a)).join(" ");
|
|
2508
2583
|
}
|
|
@@ -2560,7 +2635,7 @@ async function installAndDemo(cli, spec2, getQuestion, log = console.log) {
|
|
|
2560
2635
|
const abilities = `What are the tool abilities of the MCP server "${spec2.name}"? List them briefly.`;
|
|
2561
2636
|
log(`
|
|
2562
2637
|
${import_chalk12.default.dim("Checking what the API can do\u2026")}`);
|
|
2563
|
-
log(` ${import_chalk12.default.dim("$")} ${renderCommand(cli.kind === "claude" ? ["claude", "-p", abilities, "--allowedTools", `mcp__${spec2.name}__*`] : ["codex", "exec", abilities])}
|
|
2638
|
+
log(` ${import_chalk12.default.dim("$")} ${renderCommand(cli.kind === "claude" ? ["claude", "-p", abilities, "--allowedTools", `mcp__${spec2.name}__*`] : ["codex", "exec", "--skip-git-repo-check", abilities])}
|
|
2564
2639
|
`);
|
|
2565
2640
|
const check = oneShot(spec2, abilities);
|
|
2566
2641
|
if (check.status !== 0) {
|
|
@@ -2575,10 +2650,11 @@ async function installAndDemo(cli, spec2, getQuestion, log = console.log) {
|
|
|
2575
2650
|
const ask = handoff ? cli.kind === "claude" ? claudeInteractive : codexInteractive : oneShot;
|
|
2576
2651
|
log(`
|
|
2577
2652
|
${import_chalk12.default.dim(handoff ? `Opening ${cli.label} with your question \u2014 you'll stay in that session:` : `Your question, through ${cli.label}:`)}`);
|
|
2578
|
-
const
|
|
2653
|
+
const directed = directedPrompt(spec2, question);
|
|
2654
|
+
const shown = cli.kind === "claude" ? handoff ? ["claude", directed, "--allowedTools", `mcp__${spec2.name}__*`, "--append-system-prompt", "\u2026"] : ["claude", "-p", directed, "--allowedTools", `mcp__${spec2.name}__*`] : handoff ? ["codex", directed] : ["codex", "exec", "--skip-git-repo-check", directed];
|
|
2579
2655
|
log(` ${import_chalk12.default.dim("$")} ${renderCommand(shown)}
|
|
2580
2656
|
`);
|
|
2581
|
-
const ans = ask(spec2, question);
|
|
2657
|
+
const ans = ask(spec2, directedPrompt(spec2, question));
|
|
2582
2658
|
if (ans.status !== 0) log(import_chalk12.default.yellow(`
|
|
2583
2659
|
${cli.label} exited with ${ans.status ?? "no status"} \u2014 the MCP stays installed.`));
|
|
2584
2660
|
}
|
|
@@ -4160,12 +4236,47 @@ async function maybeInstallExternalCli(p, opts) {
|
|
|
4160
4236
|
const ran = await installAndDemo(pick2, buildInstallSpec(p), () => resolveQuestion(opts));
|
|
4161
4237
|
if (ran) {
|
|
4162
4238
|
rememberCliOffer(p, pick2.kind, "installed");
|
|
4239
|
+
if (pick2.kind === "codex") await offerToPruneCodexSiblings(p.projectId);
|
|
4163
4240
|
if (p.anon) {
|
|
4164
4241
|
console.log(import_chalk14.default.dim(` Anonymous workspace \u2014 run \`apiblaze apichat ${p.projectId}\` and /claim to keep it (and this MCP) beyond 30 days.`));
|
|
4165
4242
|
}
|
|
4166
4243
|
}
|
|
4167
4244
|
return ran;
|
|
4168
4245
|
}
|
|
4246
|
+
async function offerToPruneCodexSiblings(keepName) {
|
|
4247
|
+
const siblings = codexSiblingApiblazeServers(keepName);
|
|
4248
|
+
if (siblings.length === 0) return;
|
|
4249
|
+
const alive = [];
|
|
4250
|
+
for (const name of siblings) {
|
|
4251
|
+
const url = codexServerUrl(name);
|
|
4252
|
+
if (url && await mcpEndpointIsDead(url)) {
|
|
4253
|
+
if (removeCodexServer(name)) {
|
|
4254
|
+
console.log(import_chalk14.default.dim(` Removed ${import_chalk14.default.bold(name)} from ~/.codex/config.toml \u2014 that proxy no longer exists.`));
|
|
4255
|
+
continue;
|
|
4256
|
+
}
|
|
4257
|
+
}
|
|
4258
|
+
alive.push(name);
|
|
4259
|
+
}
|
|
4260
|
+
if (alive.length === 0) return;
|
|
4261
|
+
const siblingsLabel = alive;
|
|
4262
|
+
console.log(import_chalk14.default.yellow(`
|
|
4263
|
+
Codex also has ${siblingsLabel.length} other APIblaze MCP server${siblingsLabel.length > 1 ? "s" : ""} configured: ${import_chalk14.default.bold(siblingsLabel.join(", "))}.`));
|
|
4264
|
+
console.log(import_chalk14.default.dim(' Codex tries every one at startup and reports "MCP startup incomplete" for any that is not signed in.'));
|
|
4265
|
+
if (!process.stdin.isTTY) {
|
|
4266
|
+
console.log(import_chalk14.default.dim(` Remove the ones you don't use: apiblaze apichat <name> --install-mcp codex (or edit ~/.codex/config.toml)`));
|
|
4267
|
+
return;
|
|
4268
|
+
}
|
|
4269
|
+
const { default: inquirer3 } = await import("inquirer");
|
|
4270
|
+
const { drop } = await inquirer3.prompt([{
|
|
4271
|
+
type: "checkbox",
|
|
4272
|
+
name: "drop",
|
|
4273
|
+
message: "Remove any you no longer use? (space to select, enter to confirm)",
|
|
4274
|
+
choices: siblingsLabel.map((n) => ({ name: n, value: n }))
|
|
4275
|
+
}]);
|
|
4276
|
+
for (const n of drop ?? []) {
|
|
4277
|
+
console.log(removeCodexServer(n) ? ` ${import_chalk14.default.green("\u2714")} Removed ${import_chalk14.default.bold(n)} from ~/.codex/config.toml.` : import_chalk14.default.red(` Could not remove ${n}.`));
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4169
4280
|
async function authorizeClientRegistration(p, cliLabel) {
|
|
4170
4281
|
if (!p.consumerAuth) return;
|
|
4171
4282
|
const teamId = p.teamId ?? loadCredentials()?.teamId;
|