mirror of
https://github.com/ruvnet/ruflo.git
synced 2026-09-14 14:01:28 +08:00
858ce28f7e
Investigating why the #1874 boot smoke kept failing in CI uncovered a separate-but-related cli bug: v3/@claude-flow/cli/bin/cli.js auto-routes any `mcp start *` invocation to stdio mode when stdin isn't a TTY — even when the user explicitly passed `-t http`. Result: every smoke / non-TTY caller silently got stdio regardless of the transport flag. This is the same class as #1874: a "smart default" that overrides explicit user intent, with no test catching it. Yet another example of self-consistent code where everyone agreed on the wrong behaviour. Fix: the MCP auto-detect now defers when explicit `-t <non-stdio>`, `--transport <non-stdio>`, or `--transport=<non-stdio>` is in argv. HTTP transport now starts when requested even from non-TTY contexts (CI smoke, daemonized callers, etc.). Verified locally: $ node bin/cli.js mcp start -t http -p N [OK] MCP Server started — Transport: http (was: stdio) Smoke test simplified ───────────────────── The boot-an-actual-server-and-call-initialize approach hit a secondary issue (in-process HTTP server doesn't keep the process alive after `await mcpServer.start()` returns; needs separate plumbing). For #1874's regression coverage, a static dist scan is sufficient and reliable: assert the protocolVersion assignment is a YYYY-MM-DD spec string, reject the {major,...} object form. Combined with witness markers (#1874-mcp, #1874-shared) attesting the spec strings live in dist, and the corrected unit test in mcp.test.ts using the spec string form, this is three-way coverage of the bug class without flaky integration plumbing. A separate issue tracks the boot-smoke gap (cli's HTTP server process-lifetime); not blocking #1874 closure. Co-Authored-By: RuFlo <ruv@ruv.net>
67 lines
2.3 KiB
JavaScript
67 lines
2.3 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Regression guard for ruvnet/ruflo#1874.
|
|
*
|
|
* Static dist scan: assert the MCP server packages emit a spec-compliant
|
|
* `YYYY-MM-DD` string for `protocolVersion`, never the previous
|
|
* `{major,minor,patch}` object form. This catches the regression class
|
|
* without needing to actually boot the HTTP server (which has its own
|
|
* separate plumbing issues — bin/cli.js auto-detects MCP-stdio mode for
|
|
* any `mcp start *` invocation when stdin isn't a TTY, and the
|
|
* in-process HTTP server doesn't keep the process alive after start).
|
|
*
|
|
* Combined with:
|
|
* - witness markers (#1874-mcp, #1874-shared) — manifest attests the
|
|
* spec strings are present
|
|
* - corrected unit test in mcp.test.ts — uses the spec string form
|
|
*
|
|
* This three-way coverage catches the bug class.
|
|
*/
|
|
|
|
import { readFileSync, existsSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
|
|
const REPO_ROOT = resolve(process.argv[2] ?? process.cwd());
|
|
const TARGETS = [
|
|
'v3/@claude-flow/mcp/dist/server.js',
|
|
'v3/@claude-flow/shared/dist/mcp/server.js',
|
|
];
|
|
|
|
const SPEC_DATE_REGEX = /^['"]\d{4}-\d{2}-\d{2}['"]$/;
|
|
const BAD_OBJECT_REGEX = /protocolVersion\s*=\s*\{\s*major:/;
|
|
|
|
let failed = 0;
|
|
const fail = (m) => { console.error(`FAIL: ${m}`); failed++; };
|
|
const pass = (m) => console.log(`ok: ${m}`);
|
|
|
|
for (const target of TARGETS) {
|
|
const path = resolve(REPO_ROOT, target);
|
|
if (!existsSync(path)) {
|
|
fail(`${target} not found — build the package first`);
|
|
continue;
|
|
}
|
|
const src = readFileSync(path, 'utf8');
|
|
|
|
// Reject the buggy object form
|
|
if (BAD_OBJECT_REGEX.test(src)) {
|
|
fail(`${target} contains protocolVersion = {major,...} object (#1874 regression)`);
|
|
continue;
|
|
}
|
|
|
|
// Find the protocolVersion assignment and assert it's a date string
|
|
const match = src.match(/protocolVersion\s*=\s*(['"][^'"]*['"]|\{[^}]+\}|[^;,\n]+)/);
|
|
if (!match) {
|
|
fail(`${target} has no protocolVersion assignment — schema changed?`);
|
|
continue;
|
|
}
|
|
const value = match[1].trim();
|
|
if (!SPEC_DATE_REGEX.test(value)) {
|
|
fail(`${target} protocolVersion = ${value} is not a YYYY-MM-DD spec string`);
|
|
continue;
|
|
}
|
|
pass(`${target}: protocolVersion = ${value}`);
|
|
}
|
|
|
|
console.log(failed === 0 ? '\nMCP protocol-shape compliance ✓' : `\n${failed} compliance failure(s) ✗`);
|
|
process.exit(failed > 0 ? 1 : 0);
|