chore(web): format-gate the ungated first-party TS/JS (server/, vite.config.ts, scripts/) (#1788)

* chore(web): format-gate the ungated first-party TS/JS (#1778)

Prettier only covered core/ and each client's src/, leaving the web Node
backend (clients/web/server/**), web top-level configs (vite.config.ts,
tsup.runner.config.ts, eslint.config.js, ...), and the root build/verify
tooling (scripts/**/*.mjs) ungated — so their formatting was never checked
by validate/CI. eslint already reached these via `eslint .`, so this is a
prettier-only gap.

- clients/web format/format:check now cover src, server, and top-level
  *.{ts,js}, not just src.
- New root format:scripts / format:check:scripts for scripts/**/*.mjs,
  folded into the root format and into validate:core.
- Normalized the newly-covered files with prettier --write (pure
  formatting; no runtime change).

Closes #1778

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5

* chore: future-proof the scripts format glob (#1778 review)

Widen format:scripts / format:check:scripts from "scripts/**/*.mjs" to
"scripts/**/*.{mjs,js,cjs,ts}" so a future non-.mjs file under scripts/
is auto-gated, matching the future-proof glob style clients/web now uses.
A brace glob is a single pattern, so prettier does not error on the
unmatched branches. Addresses observation #2 from the PR #1788 review.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5

* docs: sync AGENTS.md scripts glob after the widening (#1788 review r2)

d86d8f7 widened the scripts glob to {mjs,js,cjs,ts} and updated the
validate:core bullet, but the format bullet at AGENTS.md:217 still said
scripts/**/*.mjs. Bring it in line so the two mentions agree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNdjEPKLG637X8YmhDiEk5

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cliff Hall 2026-07-25 23:15:45 -04:00 • committed by GitHub
commit 166ed38e7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 406 additions and 324 deletions

View file

@ -45,7 +45,12 @@ import { join, resolve } from "node:path";
import { setTimeout as delay } from "node:timers/promises";
const repoRoot = resolve(import.meta.dirname, "..");
const testServer = join(repoRoot, "test-servers", "build", "test-server-stdio.js");
const testServer = join(
repoRoot,
"test-servers",
"build",
"test-server-stdio.js",
);
// Mirrors INSPECTOR_API_TOKEN_GLOBAL in core/mcp/remote/constants.ts; kept as a
// literal because this plain .mjs script can't import the TS source.
@ -72,7 +77,9 @@ function fail(message) {
if (workDir) {
rmSync(workDir, { recursive: true, force: true });
// `tarball` is initialized before `workDir` is ever set, so this is safe.
console.error(`pack:verify — tarball retained for inspection at ${tarball}`);
console.error(
`pack:verify — tarball retained for inspection at ${tarball}`,
);
}
process.exit(1);
}
@ -97,7 +104,9 @@ function ensureTestServer() {
step("building test-servers (missing build output)...");
const status = runInherit("npx", ["tsc", "-p", "test-servers", "--noCheck"]);
if (status !== 0 || !existsSync(testServer)) {
fail("could not build the stdio test server (test-servers/build/test-server-stdio.js)");
fail(
"could not build the stdio test server (test-servers/build/test-server-stdio.js)",
);
}
}
@ -175,10 +184,16 @@ const work = mkdtempSync(join(tmpdir(), "pack-verify-"));
workDir = work; // from now on, fail() cleans this up
try {
ensureTestServer();
step(`installing the tarball into a clean consumer at ${work} (pulls runtime deps)...`);
step(
`installing the tarball into a clean consumer at ${work} (pulls runtime deps)...`,
);
writeFileSync(
join(work, "package.json"),
JSON.stringify({ name: "pack-verify-consumer", private: true, version: "0.0.0" }),
JSON.stringify({
name: "pack-verify-consumer",
private: true,
version: "0.0.0",
}),
);
const install = runInherit(
"npm",
@ -189,8 +204,18 @@ try {
fail("`npm install <tarball>` into the throwaway consumer failed");
}
const installedPkg = join(work, "node_modules", "@modelcontextprotocol", "inspector");
const bin = join(work, "node_modules", ".bin", process.platform === "win32" ? "mcp-inspector.cmd" : "mcp-inspector");
const installedPkg = join(
work,
"node_modules",
"@modelcontextprotocol",
"inspector",
);
const bin = join(
work,
"node_modules",
".bin",
process.platform === "win32" ? "mcp-inspector.cmd" : "mcp-inspector",
);
if (!existsSync(bin)) {
fail(`installed \`mcp-inspector\` bin not found at ${bin}`);
}
@ -213,7 +238,11 @@ try {
env: { ...process.env, ...extraEnv },
shell: process.platform === "win32",
});
return { status: r.status, output: `${r.stdout ?? ""}${r.stderr ?? ""}`, stdout: r.stdout ?? "" };
return {
status: r.status,
output: `${r.stdout ?? ""}${r.stderr ?? ""}`,
stdout: r.stdout ?? "",
};
};
// ---------------------------------------------------------------------------
@ -223,17 +252,33 @@ try {
// build from its installed location.
step("verifying help dispatch (--help, --cli --help, --tui --help)...");
const helpChecks = [
{ args: ["--help"], marker: "Mode flags (--web, --cli, --tui)", label: "launcher --help" },
{ args: ["--cli", "--help"], marker: "Usage: inspector-cli", label: "--cli dispatch" },
{ args: ["--tui", "--help"], marker: "Usage: mcp-inspector-tui", label: "--tui dispatch" },
{
args: ["--help"],
marker: "Mode flags (--web, --cli, --tui)",
label: "launcher --help",
},
{
args: ["--cli", "--help"],
marker: "Usage: inspector-cli",
label: "--cli dispatch",
},
{
args: ["--tui", "--help"],
marker: "Usage: mcp-inspector-tui",
label: "--tui dispatch",
},
];
for (const { args, marker, label } of helpChecks) {
const r = runBin(args);
if (r.status !== 0) {
fail(`\`${args.join(" ")}\` exited ${r.status}\n${r.output.slice(0, 800)}`);
fail(
`\`${args.join(" ")}\` exited ${r.status}\n${r.output.slice(0, 800)}`,
);
}
if (!r.output.includes(marker)) {
fail(`\`${args.join(" ")}\` (${label}) did not print "${marker}"\n${r.output.slice(0, 800)}`);
fail(
`\`${args.join(" ")}\` (${label}) did not print "${marker}"\n${r.output.slice(0, 800)}`,
);
}
}
@ -250,7 +295,15 @@ try {
},
}),
);
const list = runBin(["--cli", "--catalog", catalogPath, "--server", "test", "--method", "tools/list"]);
const list = runBin([
"--cli",
"--catalog",
catalogPath,
"--server",
"test",
"--method",
"tools/list",
]);
if (list.status !== 0) {
fail(`\`--cli … tools/list\` exited ${list.status}\n${list.output}`);
}
@ -258,7 +311,9 @@ try {
try {
parsed = JSON.parse(list.stdout);
} catch {
fail(`\`--cli … tools/list\` did not return JSON on stdout:\n${list.stdout}`);
fail(
`\`--cli … tools/list\` did not return JSON on stdout:\n${list.stdout}`,
);
}
if (!(parsed.tools ?? []).some((t) => t.name === "echo")) {
fail(`\`--cli … tools/list\` missing expected "echo" tool`);
@ -291,7 +346,9 @@ try {
* shipped `dist`. Kills the server before returning.
*/
async function verifyWeb(bin, cwd) {
step("verifying prod `--web` serves the shipped dist from the installed package...");
step(
"verifying prod `--web` serves the shipped dist from the installed package...",
);
const host = "127.0.0.1";
const port = process.env.PACK_VERIFY_WEB_PORT ?? "6399";
const token = "pack-verify-token";
@ -326,7 +383,9 @@ async function verifyWeb(bin, cwd) {
let res = null;
for (let attempt = 0; attempt < 120 && !res; attempt++) {
if (exited) {
fail(`\`--web\` exited (code ${exitCode}) before serving — see output above`);
fail(
`\`--web\` exited (code ${exitCode}) before serving — see output above`,
);
}
try {
res = await fetch(`http://${host}:${port}/`);
@ -342,7 +401,9 @@ async function verifyWeb(bin, cwd) {
}
const body = await res.text();
if (!body.includes(TOKEN_GLOBAL)) {
fail(`\`--web\` served HTML is missing the ${TOKEN_GLOBAL} global (token not injected)`);
fail(
`\`--web\` served HTML is missing the ${TOKEN_GLOBAL} global (token not injected)`,
);
}
if (!body.includes(token)) {
fail("`--web` served HTML is missing the injected auth-token value");

View file

@ -33,7 +33,10 @@ import { tmpdir } from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const repoRoot = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"..",
);
const webDir = path.join(repoRoot, "clients/web");
// Hardcoded browser entry. If it's ever renamed, the guarded read below fails
// with an actionable message rather than a raw ENOENT stack.