apiblaze 0.21.75 → 0.21.77
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 +57 -10
- 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.
|
|
37
|
+
version = "0.21.77";
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
|
|
@@ -5577,6 +5577,7 @@ __export(directory_exports, {
|
|
|
5577
5577
|
stepOpen: () => stepOpen,
|
|
5578
5578
|
stepRunnable: () => stepRunnable,
|
|
5579
5579
|
summaryOf: () => summaryOf,
|
|
5580
|
+
testCasesText: () => testCasesText,
|
|
5580
5581
|
withBrandSource: () => withBrandSource,
|
|
5581
5582
|
writeJsonLine: () => writeJsonLine
|
|
5582
5583
|
});
|
|
@@ -5675,6 +5676,22 @@ function directoryBodyFromFlags(f2) {
|
|
|
5675
5676
|
}
|
|
5676
5677
|
return out;
|
|
5677
5678
|
}
|
|
5679
|
+
function testCasesText(r, platforms) {
|
|
5680
|
+
const cases = r?.target?.metadata?.portalAnswers?.test_cases ?? [];
|
|
5681
|
+
if (!cases.length) return null;
|
|
5682
|
+
const dirs = ["claude", "chatgpt"].filter((x) => platforms.includes(x));
|
|
5683
|
+
const lines = ["Test cases (what reviewers try; results are our pre-check, not their review)"];
|
|
5684
|
+
for (const c of cases) {
|
|
5685
|
+
lines.push(` "${c.prompt}" (${c.kind === "refuse" ? "should say no" : c.tool ? `should use ${c.tool}` : "pick the tool it should use"})`);
|
|
5686
|
+
for (const dir of dirs) {
|
|
5687
|
+
const x = (r?.case_results ?? []).find((y) => y.caseId === c.id && y.directory === dir);
|
|
5688
|
+
const word = !x ? "not run yet" : !x.current ? "out of date, run again" : `${x.pass ? "\u2713" : "\u2717"} ${CASE_STATE[x.state]}${x.state === "other_tool" || x.state === "acted" ? `: ${x.tools.join(", ")}` : ""} \xB7 ${CASE_SOURCE[x.source]}, ${x.at.slice(0, 10)}`;
|
|
5689
|
+
lines.push(` for ${dir === "claude" ? "Claude" : "ChatGPT"}: ${word}`);
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
lines.push(" Run them on the Testing tab, or with the Claude Code lines below.");
|
|
5693
|
+
return lines.join("\n");
|
|
5694
|
+
}
|
|
5678
5695
|
function withBrandSource(url, cli = B.cli) {
|
|
5679
5696
|
return cli === "mcpblaze" ? `${url}?source=mcpblazeCli` : url;
|
|
5680
5697
|
}
|
|
@@ -5821,6 +5838,7 @@ function claudeCodeTests(r, proj2) {
|
|
|
5821
5838
|
seen.add(p);
|
|
5822
5839
|
cases.push({ prompt: p, line: askLine(name, p), expect, refuse });
|
|
5823
5840
|
};
|
|
5841
|
+
for (const c of t?.metadata?.portalAnswers?.test_cases ?? []) add(c.prompt, c.kind === "refuse" ? `it says it can't help${c.why ? ` (${c.why})` : ""}, and calls no tool` : c.expect || "it calls your tools and answers from what comes back", c.kind === "refuse");
|
|
5824
5842
|
for (const p of t?.metadata?.examplePrompts ?? []) add(p, "it calls your tools and answers from what comes back", false);
|
|
5825
5843
|
const tc = t?.metadata?.portalAnswers?.chatgpt_test_cases;
|
|
5826
5844
|
for (const c of tc?.positive ?? []) add(c.prompt, c.expected_behavior || "it calls your tools and answers from what comes back", false);
|
|
@@ -5840,7 +5858,7 @@ function claudeCodeText(cc) {
|
|
|
5840
5858
|
else lines.push(` ${n}. One line per use case:`, ...cc.cases.flatMap((c) => [` ${c.line}`, ` expect: ${c.expect}`]));
|
|
5841
5859
|
return lines.join("\n");
|
|
5842
5860
|
}
|
|
5843
|
-
var import_node_fs, import_chalk17, PLATFORMS, ATTESTATIONS, OPENAI_CATEGORIES, AUTH_MODES, DATA_HANDLING_MODES, STEP_IDS, reportPath, DESCRIPTION_MIN, ccServerName, shellQuote2, askLine;
|
|
5861
|
+
var import_node_fs, import_chalk17, PLATFORMS, ATTESTATIONS, OPENAI_CATEGORIES, AUTH_MODES, DATA_HANDLING_MODES, STEP_IDS, CASE_SOURCE, CASE_STATE, reportPath, DESCRIPTION_MIN, ccServerName, shellQuote2, askLine;
|
|
5844
5862
|
var init_directory = __esm({
|
|
5845
5863
|
"src/lib/directory.ts"() {
|
|
5846
5864
|
"use strict";
|
|
@@ -5872,6 +5890,8 @@ var init_directory = __esm({
|
|
|
5872
5890
|
AUTH_MODES = ["signin", "open"];
|
|
5873
5891
|
DATA_HANDLING_MODES = ["own", "proxied", "third-party"];
|
|
5874
5892
|
STEP_IDS = ["mode", "address", "access", "tools", "listing", "answers", "attestations", "prove", "signin", "token", "packet", "submit"];
|
|
5893
|
+
CASE_SOURCE = { "our-claude": "our test, Claude model", "our-gpt": "our test, GPT model", "claude-code": "your Claude Code", codex: "your Codex CLI", chatgpt: "ChatGPT", claude: "Claude" };
|
|
5894
|
+
CASE_STATE = { passed: "used the right tool", chose_write: "chose the right tool (not run: it changes data)", other_tool: "used a different tool", no_tool: "didn't use a tool", tool_failed: "the tool failed", said_no: "said no", acted: "used a tool when it shouldn't" };
|
|
5875
5895
|
reportPath = (proj2) => `/projects/${encodeURIComponent(proj2.projectId)}/${encodeURIComponent(proj2.apiVersion)}/directory-report`;
|
|
5876
5896
|
DESCRIPTION_MIN = 300;
|
|
5877
5897
|
ccServerName = (projectId) => projectId.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "app";
|
|
@@ -6930,6 +6950,7 @@ Create an ${B.thing}
|
|
|
6930
6950
|
const devPortal = result.devPortal ? stripTenantFromPortal(result.devPortal) : void 0;
|
|
6931
6951
|
const tenant = result.tenant ?? chosenTenant ?? tenantFromPortal(result.devPortal);
|
|
6932
6952
|
if (!tenant) fail4("The server did not report which tenant this proxy belongs to \u2014 cannot build its MCP address. Re-run, or report this.");
|
|
6953
|
+
if (!opts.json) printCreatedLinks({ name, version: version2, env: "dev", tenant, anon: false, teamId, listing: !!opts.directoryReady });
|
|
6933
6954
|
rememberForApichat({
|
|
6934
6955
|
projectId: result.project_id ?? name,
|
|
6935
6956
|
target: opts.target || opts.openapi || name,
|
|
@@ -6988,6 +7009,12 @@ Create an ${B.thing}
|
|
|
6988
7009
|
});
|
|
6989
7010
|
if (directory) printDirectoryOutcome(directory);
|
|
6990
7011
|
}
|
|
7012
|
+
function printCreatedLinks(o) {
|
|
7013
|
+
console.log(` ${import_chalk20.default.dim("MCP server:")} ${import_chalk20.default.bold(mcpUrl(o.name, o.version, o.env, { tenant: o.tenant, anon: o.anon }))}`);
|
|
7014
|
+
if (BRAND !== "mcpblaze" && !o.listing) return;
|
|
7015
|
+
const page = pageLinkOf(null, { projectId: o.name, apiVersion: o.version, teamId: o.teamId });
|
|
7016
|
+
console.log(` ${import_chalk20.default.dim("Scorecard: ")} ${import_chalk20.default.cyan(page)}${o.anon ? import_chalk20.default.dim(` (opens once you sign in: npx ${B.cli} login)`) : ""}`);
|
|
7017
|
+
}
|
|
6991
7018
|
async function applyCreateToggles(name, opts) {
|
|
6992
7019
|
if (!opts.identified && !opts.iam) return;
|
|
6993
7020
|
const { runIamToggle: runIamToggle2, runIdentifiedToggle: runIdentifiedToggle2 } = await Promise.resolve().then(() => (init_iam(), iam_exports));
|
|
@@ -7190,6 +7217,7 @@ Create an ${B.thing}`));
|
|
|
7190
7217
|
if (!tenant) fail4("The server did not report which tenant this proxy belongs to \u2014 cannot build its MCP address. Re-run, or report this.");
|
|
7191
7218
|
const secure = result.secure ?? void 0;
|
|
7192
7219
|
const anonProjectId = result.project_id ?? name ?? "";
|
|
7220
|
+
if (anonProjectId && !opts.json) printCreatedLinks({ name: anonProjectId, version: version2, env: "prod", tenant, anon: true, teamId: result.team_id, listing: !!opts.directoryReady });
|
|
7193
7221
|
if (anonProjectId) {
|
|
7194
7222
|
rememberForApichat({
|
|
7195
7223
|
projectId: anonProjectId,
|
|
@@ -8650,8 +8678,12 @@ async function runConnectorExercise(project, opts = {}) {
|
|
|
8650
8678
|
const codex = deps.codexInstalled !== void 0 ? { installed: deps.codexInstalled, loggedIn: deps.codexInstalled } : clients.includes("codex") ? detectCodex(deps.spawn ?? import_child_process5.spawnSync) : { installed: false, loggedIn: false };
|
|
8651
8679
|
const proven = opts.provenPromptNotes ?? [];
|
|
8652
8680
|
const provenFor = (client) => new Map(proven.filter((n) => n.kind === "prompt" && (n.client ?? "claude") === client).map((n) => [n.prompt.trim(), n]));
|
|
8653
|
-
const
|
|
8654
|
-
const
|
|
8681
|
+
const testCases = target2.metadata?.portalAnswers?.test_cases ?? [];
|
|
8682
|
+
const readTools = new Set(readOnlyToolNames(tools));
|
|
8683
|
+
const casePrompts = testCases.filter((c) => c.kind === "use" && (!c.tool || readTools.has(c.tool))).map((c) => c.prompt);
|
|
8684
|
+
const passPrompts = opts.promptsOnly ?? [...new Set([...(target2.metadata?.examplePrompts ?? []).slice(0, 5), ...casePrompts].filter((p) => typeof p === "string" && p.trim()).map((p) => p.trim()))].slice(0, 10);
|
|
8685
|
+
const refusals = testCases.filter((c) => c.kind === "refuse");
|
|
8686
|
+
const negatives = (refusals.length ? [...refusals.filter((c) => c.send), ...refusals.filter((c) => !c.send)].map((c) => c.prompt) : (target2.metadata?.portalAnswers?.chatgpt_test_cases?.negative ?? []).map((c) => c.prompt)).filter((p) => typeof p === "string" && p.trim()).slice(0, 3);
|
|
8655
8687
|
const readOnly2 = readOnlyToolNames(tools);
|
|
8656
8688
|
const requiredCount = (t) => Object.values(t.inputProperties ?? {}).filter((p) => p.required).length;
|
|
8657
8689
|
const firstRead = [...tools].filter((t) => toolRole(t) === "read").sort((a, b) => requiredCount(a) - requiredCount(b))[0] ?? tools[0];
|
|
@@ -13956,12 +13988,15 @@ async function runConnector(target2, opts) {
|
|
|
13956
13988
|
if (opts.status) {
|
|
13957
13989
|
const cc = claudeCodeTests(r, proj2);
|
|
13958
13990
|
if (json) {
|
|
13959
|
-
writeJsonLine({ ready: isReady(r, platforms), project: proj2.projectId, headline: r.rendered.headline, summary: r.progress?.summary ?? null, progress: r.progress ?? null, claude_code: cc, report: r.report });
|
|
13991
|
+
writeJsonLine({ ready: isReady(r, platforms), project: proj2.projectId, headline: r.rendered.headline, summary: r.progress?.summary ?? null, progress: r.progress ?? null, claude_code: cc, test_cases: r.case_results ?? null, report: r.report });
|
|
13960
13992
|
process.exit(isReady(r, platforms) ? 0 : 1);
|
|
13961
13993
|
}
|
|
13962
13994
|
const card2 = scorecardText(r);
|
|
13963
13995
|
if (card2) console.log(card2);
|
|
13964
13996
|
else printReport(r, false);
|
|
13997
|
+
const tc = testCasesText(r, platforms);
|
|
13998
|
+
if (tc) console.log(`
|
|
13999
|
+
${tc}`);
|
|
13965
14000
|
if (cc) console.log(`
|
|
13966
14001
|
${claudeCodeText(cc)}`);
|
|
13967
14002
|
process.exit(isReady(r, platforms) ? 0 : 1);
|
|
@@ -15340,7 +15375,8 @@ Most people new to it do not know the words tenant, OpenAPI or header, so plain
|
|
|
15340
15375
|
## The two things to offer
|
|
15341
15376
|
|
|
15342
15377
|
1. **"Want me to make an MCP server from this API?"** \u2014 the API is deployed: \`${run2} create --target <its OpenAPI spec or URL>\`
|
|
15343
|
-
(sign-in and per-user rules come with it; it prints the MCP
|
|
15378
|
+
(sign-in and per-user rules come with it; it prints the MCP server and Scorecard links right after the create:
|
|
15379
|
+
give them to the user at once, before anything else). The app runs on this machine:
|
|
15344
15380
|
\`${run2} dev --port <port>\`, as its own detached process. The next step to offer for this folder: ${question}
|
|
15345
15381
|
2. **"Want it listed in Claude or ChatGPT?"** \u2014 right after the MCP server exists, \`${run2} connector <name>\`
|
|
15346
15382
|
(\`--compliant chatgpt\` for ChatGPT, \`--compliant all\` both). Its first line is the page link: give it to the user
|
|
@@ -15393,6 +15429,13 @@ function shipMcpMarkdown() {
|
|
|
15393
15429
|
const run2 = "npx mcpblaze@latest";
|
|
15394
15430
|
return withLatest(`# An MCP server for their API, with MCPblaze
|
|
15395
15431
|
|
|
15432
|
+
**Links first.** \`create\`, \`create --compliant\` and \`connector <spec>\` print two lines the moment the MCP server exists:
|
|
15433
|
+
"MCP server: \u2026" and "Scorecard: \u2026" (the page with every step of the listing). Give both to the user in the chat right
|
|
15434
|
+
then, before the rest of the run finishes and before any other step. **A deployed API (a URL, or the URL of its spec):
|
|
15435
|
+
make it first** (step 4) with the automatic tools, so the links come within a minute; steps 1\u20133 then tune what it made
|
|
15436
|
+
(\`mcp ops hide|show|set\`, \`mcp instructions set\`) instead of coming before it. Only an app that runs on this machine,
|
|
15437
|
+
or an API with no spec anyone can fetch, goes through steps 1\u20133 first.
|
|
15438
|
+
|
|
15396
15439
|
1. **Read what is here.** The route files (every path and method, what each handler does, the id each POST returns), an
|
|
15397
15440
|
existing \`openapi.yaml\` / \`openapi.json\` / spec route, env files, how the app is protected today (a header, a session,
|
|
15398
15441
|
nothing). The code is the best source there is: it says what each route does better than any spec.
|
|
@@ -15404,7 +15447,8 @@ function shipMcpMarkdown() {
|
|
|
15404
15447
|
Explain your choices and show the first-pass draft catalogue before anything is written.
|
|
15405
15448
|
3. **The spec, if there is none.** Write \`./openapi.yaml\` for the operations the design kept, with the descriptions already
|
|
15406
15449
|
written (operation \`summary\` = the tool title, \`description\` = the tool description). Nothing else goes in.
|
|
15407
|
-
4. **Make it.** Deployed: \`${run2} create --target <spec or URL>\` (add \`--compliant\` now if a listing is the goal
|
|
15450
|
+
4. **Make it.** Deployed: \`${run2} create --target <spec or URL>\` (add \`--compliant\` now if a listing is the goal,
|
|
15451
|
+
\`--compliant all\` for Claude and ChatGPT); relay its MCP server and Scorecard lines as soon as they print.
|
|
15408
15452
|
On this machine: \`${run2} dev --port <port> --openapi ./openapi.yaml\` as its own detached process
|
|
15409
15453
|
(\`nohup ${run2} dev \u2026 > mcpblaze-dev.log 2>&1 < /dev/null &\`); the log says "is live on the internet" after
|
|
15410
15454
|
about 20 seconds. Either prints the MCP address and saves the key to \`.env.local\` itself; never show a key in the chat.
|
|
@@ -15418,8 +15462,8 @@ function shipMcpMarkdown() {
|
|
|
15418
15462
|
who can override: the dashboard, Tenant \u2192 Admins.
|
|
15419
15463
|
7. **Try it from Claude Code.** \`claude mcp add --transport http <name> <the MCP address it printed>\`, then \`/mcp\` and
|
|
15420
15464
|
sign in; call one tool. What a reviewer does, before a reviewer does it.
|
|
15421
|
-
8. **List it.** \`${run2} connector <name>\` (Claude; \`--compliant chatgpt\` or \`all\` for OpenAI's directory)
|
|
15422
|
-
the page link
|
|
15465
|
+
8. **List it.** \`${run2} connector <name>\` (Claude; \`--compliant chatgpt\` or \`all\` for OpenAI's directory), unless the
|
|
15466
|
+
create already ran with \`--compliant\`. Give the user the page link first, then follow \`${run2} skills connector\`: the MCP address (one CNAME; relay the exact record),
|
|
15423
15467
|
sign-in and the test account, the listing and the review-team answers that you write by its rules, the tests (one
|
|
15424
15468
|
\`claude -p\` per use case, from \`--status\`), and the packet. It needs the hosted app, not a tunnel. Stop any time;
|
|
15425
15469
|
\`${run2} connector <name> --status\` says what is left. The user submits the packet to Anthropic or OpenAI themselves.
|
|
@@ -15857,8 +15901,11 @@ saved as it is given; \`npx ${cli} connector <name> --status\` says what is left
|
|
|
15857
15901
|
and \`npx ${cli} connector answers <name> --use-cases "\u2026" --prerequisites "\u2026" --category "\u2026" --reviewer-instructions "\u2026"\`.
|
|
15858
15902
|
6. **Test**: \`npx ${cli} connector exercise <name>\` calls every tool as the reviewer. Then
|
|
15859
15903
|
\`npx ${cli} connector <name> --status\` prints the Claude Code lines: one \`claude mcp add\`, one sign-in, and one
|
|
15860
|
-
\`claude -p '\u2026' --allowedTools 'mcp__<name>'\` per example prompt, each with what should come back. Run each, tell the user
|
|
15904
|
+
\`claude -p '\u2026' --allowedTools 'mcp__<name>'\` per test case and example prompt, each with what should come back. Run each, tell the user
|
|
15861
15905
|
what came back, and fix a tool's description (\`npx ${cli} mcp ops set\`) when a prompt did not reach the right tool.
|
|
15906
|
+
\`--status\` also lists the **test cases** (what reviewers try: five that should use a tool and three that should say no
|
|
15907
|
+
for ChatGPT) with each one's latest result and where it ran. Those results are a pre-check, not the directories' review:
|
|
15908
|
+
never tell the user a case "passed in ChatGPT" or "in Claude". The user writes and runs the cases on the page's Testing tab.
|
|
15862
15909
|
7. **Send**: when every check passes it writes the packet. The user submits it on claude.ai/directory/manage (and the
|
|
15863
15910
|
OpenAI portal for ChatGPT).
|
|
15864
15911
|
|