Files
memind/scripts/check-codebase-memory-mcp-local.mjs
T
john 47d0d2accd feat(dev-tools): add codebase-memory-mcp local check and docs
Document MIT dev-tool setup for Cursor code intelligence and add an
offline probe for CLI, Cursor MCP config, and Memind index readiness.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 08:32:56 +08:00

121 lines
4.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Local codebase-memory-mcp smoke (dev machine only).
*
* Verifies the global CLI is installed and, when MEMIND_CBM_REQUIRE_INDEX=1
* (default), that this repository is indexed.
*/
import { spawnSync } from 'node:child_process';
import { existsSync, readFileSync } from 'node:fs';
import { homedir } from 'node:os';
import { basename, resolve } from 'node:path';
const repoRoot = resolve(process.cwd());
const requireIndex = process.env.MEMIND_CBM_REQUIRE_INDEX !== '0';
const cliName = process.env.MEMIND_CBM_CLI ?? 'codebase-memory-mcp';
function runCli(tool, args = {}) {
const payload = JSON.stringify(args);
const result = spawnSync(cliName, ['cli', '--json', tool, payload], {
encoding: 'utf8',
maxBuffer: 16 * 1024 * 1024,
});
const stdout = (result.stdout ?? '').trim();
const stderr = (result.stderr ?? '').trim();
if (result.error) {
return { ok: false, error: result.error.message, stdout, stderr };
}
if (result.status !== 0) {
return {
ok: false,
error: stderr.split('\n').pop() || `exit ${result.status}`,
stdout,
stderr,
};
}
try {
const parsed = JSON.parse(stdout);
const structured = parsed.structuredContent ?? parsed;
if (structured?.error || parsed.isError) {
return { ok: false, error: structured.error ?? parsed.isError, data: structured, stdout, stderr };
}
return { ok: true, data: structured, stdout, stderr };
} catch {
return { ok: false, error: 'invalid JSON from cli', stdout, stderr };
}
}
const versionResult = spawnSync(cliName, ['--version'], { encoding: 'utf8' });
const version = (versionResult.stdout ?? versionResult.stderr ?? '').trim();
if (versionResult.status !== 0 || !version) {
console.error('CODEBASE_MEMORY_MCP_FAIL: CLI not found');
console.error(' install: npm install -g codebase-memory-mcp && codebase-memory-mcp install -y');
process.exit(1);
}
console.log('CODEBASE_MEMORY_MCP_PROBE:');
console.log(` version=${version}`);
console.log(` repo=${repoRoot}`);
const cursorMcpPath = resolve(homedir(), '.cursor/mcp.json');
if (existsSync(cursorMcpPath)) {
try {
const cursorConfig = JSON.parse(readFileSync(cursorMcpPath, 'utf8'));
const servers = cursorConfig.mcpServers ?? cursorConfig;
const configured = Boolean(servers?.['codebase-memory-mcp']);
console.log(` cursor_mcp_configured=${configured}`);
if (!configured) {
console.warn('CODEBASE_MEMORY_MCP_WARN: ~/.cursor/mcp.json missing codebase-memory-mcp (run: codebase-memory-mcp install -y)');
}
} catch {
console.warn('CODEBASE_MEMORY_MCP_WARN: could not parse ~/.cursor/mcp.json');
}
} else {
console.warn('CODEBASE_MEMORY_MCP_WARN: ~/.cursor/mcp.json not found');
}
const projects = runCli('list_projects', {});
if (!projects.ok) {
console.error(`CODEBASE_MEMORY_MCP_FAIL: list_projects — ${projects.error}`);
process.exit(1);
}
const projectNames = (projects.data.projects ?? []).map((p) => p.name ?? p.project ?? p);
console.log(` indexed_projects=${projectNames.length}`);
const repoName = basename(repoRoot);
const matched = projectNames.find((name) => {
const normalized = String(name).toLowerCase();
return normalized === repoName.toLowerCase() || normalized.includes('memind');
});
if (!matched) {
const hint = 'codebase-memory-mcp cli --progress index_repository \'{"repo_path":"' + repoRoot + '"}\'';
if (requireIndex) {
console.error('CODEBASE_MEMORY_MCP_FAIL: Memind not indexed yet');
console.error(` run: ${hint}`);
console.error(' or in Cursor after restart: "Index this project"');
process.exit(1);
}
console.warn('CODEBASE_MEMORY_MCP_WARN: Memind not indexed (MEMIND_CBM_REQUIRE_INDEX=0)');
console.log('CODEBASE_MEMORY_MCP_CLI_OK');
process.exit(0);
}
const status = runCli('index_status', { project: matched });
if (!status.ok) {
console.error(`CODEBASE_MEMORY_MCP_FAIL: index_status — ${status.error}`);
process.exit(1);
}
const summary = {
project: status.data.project ?? matched,
status: status.data.status ?? null,
nodes: status.data.nodes ?? null,
edges: status.data.edges ?? null,
parse_partial_count: status.data.parse_partial?.count ?? status.data.parse_partial?.files?.length ?? 0,
};
console.log(` project=${summary.project}`);
console.log(` index=${JSON.stringify(summary)}`);
console.log('CODEBASE_MEMORY_MCP_OK');