Files
factory/lib/wiki-graph/scripts/smoke.mjs
vitya ca669d96e1 feat(lib): bundle MCP servers from .common/lib into factory/lib/
Copies source (no node_modules, dist, .tasks, .wiki, __pycache__) for:
- projects-meta-mcp v2.25.0 (TypeScript/Node)
- wiki-graph v0.3.1 (TypeScript/Node)
- interns-mcp v0.3.3 (Python/FastMCP)

.gitignore: exclude lib build artefacts (node_modules, dist, .venv, __pycache__, *.pyc)
bootstrap.ps1: add MCP build step — npm install+build for TS servers, venv+pip for Python

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 13:17:29 +03:00

83 lines
2.7 KiB
JavaScript

// Smoke test: drive the built MCP server over stdio against a live .wiki corpus.
// Usage: node scripts/smoke.mjs <corpusDir> [from] [to] [hubNode]
import { spawn } from 'node:child_process';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
const here = dirname(fileURLToPath(import.meta.url));
const serverPath = join(here, '..', 'dist', 'server.js');
const corpus = process.argv[2];
const from = process.argv[3] ?? 'alm-pamelas-pro-workout';
const to = process.argv[4] ?? 'euclidean-rhythms';
const hub = process.argv[5] ?? 'euclidean-rhythms';
if (!corpus) {
console.error('usage: node scripts/smoke.mjs <corpusDir> [from] [to] [hubNode]');
process.exit(2);
}
const child = spawn('node', [serverPath], { stdio: ['pipe', 'pipe', 'inherit'] });
let buf = '';
const pending = new Map();
child.stdout.on('data', (d) => {
buf += d.toString();
let nl;
while ((nl = buf.indexOf('\n')) >= 0) {
const line = buf.slice(0, nl).trim();
buf = buf.slice(nl + 1);
if (!line) continue;
const msg = JSON.parse(line);
if (msg.id && pending.has(msg.id)) {
pending.get(msg.id)(msg);
pending.delete(msg.id);
}
}
});
let nextId = 1;
function rpc(method, params) {
const id = nextId++;
return new Promise((resolve) => {
pending.set(id, resolve);
child.stdin.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n');
});
}
function notify(method, params) {
child.stdin.write(JSON.stringify({ jsonrpc: '2.0', method, params }) + '\n');
}
async function call(name, args) {
const t0 = performance.now();
const res = await rpc('tools/call', { name, arguments: { corpus, ...args } });
const ms = (performance.now() - t0).toFixed(1);
return { text: res.result.content.map((c) => c.text).join('\n'), ms };
}
const init = await rpc('initialize', {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: { name: 'wg-smoke', version: '0' },
});
notify('notifications/initialized', {});
console.log(`server: ${init.result.serverInfo.name} ${init.result.serverInfo.version}`);
console.log(`corpus: ${corpus}\n`);
const cold = await call('stats', {});
console.log(`stats [cold ${cold.ms}ms] ${cold.text}`);
const warm = await call('stats', {});
console.log(`stats [warm ${warm.ms}ms] ${warm.text}`);
const p = await call('path', { from, to });
console.log(`path [${p.ms}ms] ${from}${to}\n ${p.text}`);
const n = await call('neighbors', { node: hub, depth: 1 });
console.log(`neighbrs[${n.ms}ms] ${n.text}`);
const b = await call('backlinks', { node: hub });
console.log(`backlnks[${b.ms}ms] ${b.text}`);
const o = await call('orphans', {});
console.log(`orphans [${o.ms}ms] ${o.text.split('\n')[0]} ...`);
child.stdin.end();
child.kill();