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>
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
#!/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');
|
||||
Reference in New Issue
Block a user