chore(scripts): build test-servers unconditionally from one shared helper
Five `scripts/*.mjs` consumers each carried their own `ensureTestServer()` that returned early when `test-servers/build` was already on disk. Presence is not freshness: once that directory exists — which it does on any machine that has run the smokes once — an edit to `test-servers/src` was never picked up again, and the smoke went on driving the previously-built fixture. The failure is silent and misattributed. It does not read as "your fixture is stale"; it reads as a product bug in whatever the smoke is checking. `scripts/lib/ensure-test-servers.mjs` is now the one place that build is produced for a script consumer, and it builds unconditionally — memoized once per process per repo root, so pack-and-verify's two asks stay one tsc pass while a fresh run always rebuilds. Callers name the entries they depend on and get one actionable failure message, replacing five that had drifted. pack-and-verify also stops shelling out to `npx tsc`, which is what made it the one script unrunnable on Windows (#1939). `test-servers/tsconfig.json` gains `incremental` so the up-to-date case is cheap: 3.0s cold, 1.6s incremental here. Unconditional emit is still not a clean — `--noCheck` leaves the stale .js of a deleted src file behind — which is unchanged from before and recorded in the helper's header and AGENTS.md. Closes #2111 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JTHVxSu8AUgHRLvo1ntZ8H Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
2b129087a3
commit
e59452ea8c
1 changed files with 391 additions and 164 deletions
|
|
@ -16,24 +16,19 @@
|
|||
*
|
||||
* Expects `clients/launcher/build` and `clients/tui/build` to be built first
|
||||
* (the validate / CI ordering guarantees this). The bundled stdio test server
|
||||
* (`test-servers/build`) is built on demand here if missing.
|
||||
* (`test-servers/build`) is rebuilt on every run — see
|
||||
* `scripts/lib/ensure-test-servers.mjs` for why presence isn't freshness.
|
||||
*/
|
||||
|
||||
import { spawn, spawnSync } from "node:child_process";
|
||||
import { spawn } from "node:child_process";
|
||||
import { mkdtempSync, existsSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, resolve } from "node:path";
|
||||
import { removeSafe } from "./lib/child-cleanup.mjs";
|
||||
import { resolveNodeBin } from "./lib/resolve-node-bin.mjs";
|
||||
import { ensureTestServers } from "./lib/ensure-test-servers.mjs";
|
||||
|
||||
const repoRoot = resolve(import.meta.dirname, "..");
|
||||
const launcher = join(repoRoot, "clients", "launcher", "build", "index.js");
|
||||
const testServer = join(
|
||||
repoRoot,
|
||||
"test-servers",
|
||||
"build",
|
||||
"test-server-stdio.js",
|
||||
);
|
||||
const RENDER_MARKER = "MCP Servers";
|
||||
const TIMEOUT_MS = Number(process.env.SMOKE_TUI_TIMEOUT_MS ?? 15000);
|
||||
|
||||
|
|
@ -42,29 +37,6 @@ function fail(message) {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
function ensureTestServer() {
|
||||
if (existsSync(testServer)) return;
|
||||
console.log("smoke:tui — building test-servers (missing build output)...");
|
||||
// The root-installed tsc, run via this Node — `npx` is a `.cmd` shim on
|
||||
// Windows that a shell-free spawnSync can't start (ENOENT — #1939).
|
||||
const r = spawnSync(
|
||||
process.execPath,
|
||||
[
|
||||
resolveNodeBin("typescript", "tsc", repoRoot),
|
||||
"-p",
|
||||
"test-servers",
|
||||
"--noCheck",
|
||||
],
|
||||
{ cwd: repoRoot, stdio: "inherit" },
|
||||
);
|
||||
if (r.status !== 0 || !existsSync(testServer)) {
|
||||
fail(
|
||||
"could not build the stdio test server (test-servers/build/test-server-stdio.js). " +
|
||||
"Run `npm run test-servers:build` from clients/cli.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// The Ink TUI requires a real TTY for raw-mode keyboard input. Headless CI has
|
||||
// none, so the app throws "Raw mode is not supported" on mount and exits before
|
||||
// it can render its first frame — making this boot/render check inherently a
|
||||
|
|
@ -81,7 +53,17 @@ if (process.env.CI) {
|
|||
if (!existsSync(launcher)) {
|
||||
fail(`launcher build not found at ${launcher} — run \`npm run build\` first`);
|
||||
}
|
||||
ensureTestServer();
|
||||
// Rebuilt on every run — presence is not freshness (#2111).
|
||||
let testServer;
|
||||
try {
|
||||
[testServer] = ensureTestServers({
|
||||
repoRoot,
|
||||
label: "smoke:tui",
|
||||
requires: ["stdio"],
|
||||
});
|
||||
} catch (e) {
|
||||
fail(e.message);
|
||||
}
|
||||
|
||||
const work = mkdtempSync(join(tmpdir(), "smoke-tui-"));
|
||||
const catalogPath = join(work, "catalog.json");
|
||||
|
|
|
|||
Loading…
Reference in a new issue