This commit is contained in:
Oleg Maslov
2026-09-02 10:14:22 +02:00
parent 0c3e2ead3b
commit b20b138fe4
771 changed files with 161561 additions and 9027 deletions

View File

@@ -5,6 +5,7 @@ import path from 'node:path';
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { describe, expect, it } from 'vitest';
import { shutdown } from '../src/core/setup.js';
const ROOT = path.resolve(import.meta.dirname, '..', '..', '..');
const SERVER_ENTRY = path.join(ROOT, 'packages', 'hive-mind-mcp-server', 'dist', 'index.js');
@@ -20,14 +21,16 @@ interface AsyncRunResult {
stderr: string;
}
function run(command: string, args: string[]): Promise<AsyncRunResult> {
return runInCwd(command, args, ROOT);
}
function runInCwd(command: string, args: string[], cwd: string): Promise<AsyncRunResult> {
function runInCwd(
command: string,
args: string[],
cwd: string,
env: NodeJS.ProcessEnv = process.env,
): Promise<AsyncRunResult> {
return new Promise((resolve, reject) => {
const child = spawn(command, args, {
cwd,
env,
shell: process.platform === 'win32' && command.endsWith('.cmd'),
});
let stdout = '';
@@ -41,6 +44,37 @@ function runInCwd(command: string, args: string[], cwd: string): Promise<AsyncRu
});
}
function runNpm(args: string[], cwd: string = ROOT): Promise<AsyncRunResult> {
const bundledNpmCli = path.join(
path.dirname(process.execPath),
'node_modules',
'waggle-node-runtime',
'node_modules',
'npm',
'bin',
'npm-cli.js',
);
const npmCli = [bundledNpmCli, process.env.npm_execpath]
.find((candidate): candidate is string => (
typeof candidate === 'string' && fs.existsSync(candidate)
));
const npmEnv = { ...process.env };
const inheritedPath = Object.entries(npmEnv)
.find(([key]) => key.toLowerCase() === 'path')?.[1] ?? '';
for (const key of Object.keys(npmEnv)) {
if (key.toLowerCase() === 'path') delete npmEnv[key];
}
npmEnv.PATH = [
...(npmCli ? [path.dirname(npmCli)] : []),
path.dirname(process.execPath),
inheritedPath,
].filter(Boolean).join(path.delimiter);
return npmCli
? runInCwd(process.execPath, [npmCli, ...args], cwd, npmEnv)
: runInCwd(bin('npm'), args, cwd, npmEnv);
}
async function withTimeout<T>(work: Promise<T>, ms: number): Promise<T> {
let timeout: NodeJS.Timeout | undefined;
const timer = new Promise<never>((_, reject) => {
@@ -68,14 +102,19 @@ const HIVE_MIND_MCP_PACKAGE_CLOSURE = [
] as const;
describe('@waggle/hive-mind-mcp-server built runtime', () => {
it('shuts down safely before initialization and remains idempotent', () => {
expect(() => shutdown()).not.toThrow();
expect(() => shutdown()).not.toThrow();
});
it('saves and recalls memory through the built write-scope MCP server', async () => {
const coreBuild = await run(bin('npm'), ['run', 'build', '--workspace', '@waggle/hive-mind-core']);
const coreBuild = await runNpm(['run', 'build', '--workspace', '@waggle/hive-mind-core']);
expect(coreBuild.status).toBe(0);
const wikiBuild = await run(bin('npm'), ['run', 'build', '--workspace', '@waggle/hive-mind-wiki-compiler']);
const wikiBuild = await runNpm(['run', 'build', '--workspace', '@waggle/hive-mind-wiki-compiler']);
expect(wikiBuild.status).toBe(0);
const mcpBuild = await run(bin('npm'), ['run', 'build', '--workspace', '@waggle/hive-mind-mcp-server']);
const mcpBuild = await runNpm(['run', 'build', '--workspace', '@waggle/hive-mind-mcp-server']);
expect(mcpBuild.status).toBe(0);
const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hive-mind-mcp-write-'));
@@ -122,7 +161,7 @@ describe('@waggle/hive-mind-mcp-server built runtime', () => {
await client.close().catch(() => {});
fs.rmSync(dataDir, { recursive: true, force: true });
}
}, 30_000);
}, 60_000);
it('installs the local package closure and lists tools from the installed server', async () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hive-mind-mcp-installed-'));
@@ -137,11 +176,10 @@ describe('@waggle/hive-mind-mcp-server built runtime', () => {
try {
const dependencies: Record<string, string> = {};
for (const workspace of HIVE_MIND_MCP_PACKAGE_CLOSURE) {
const build = await run(bin('npm'), ['run', 'build', '--workspace', workspace]);
const build = await runNpm(['run', 'build', '--workspace', workspace]);
expect(build.status).toBe(0);
const pack = await run(
bin('npm'),
const pack = await runNpm(
['pack', '--workspace', workspace, '--pack-destination', packsDir, '--json'],
);
expect(pack.status).toBe(0);
@@ -156,8 +194,7 @@ describe('@waggle/hive-mind-mcp-server built runtime', () => {
JSON.stringify({ private: true, type: 'module', dependencies }, null, 2),
);
const install = await runInCwd(
bin('npm'),
const install = await runNpm(
['install', '--no-audit', '--no-fund', '--prefer-offline'],
projectDir,
);
@@ -182,7 +219,7 @@ describe('@waggle/hive-mind-mcp-server built runtime', () => {
} as Record<string, string>,
});
await withTimeout(client.connect(transport), 10_000);
await withTimeout(client.connect(transport), 30_000);
const tools = await withTimeout(client.listTools(), 10_000);
const names = tools.tools.map((tool) => tool.name);
@@ -193,5 +230,5 @@ describe('@waggle/hive-mind-mcp-server built runtime', () => {
await client.close().catch(() => {});
fs.rmSync(tempDir, { recursive: true, force: true });
}
}, 120_000);
}, 180_000);
});