Files
codegraph/src/mcp/version.ts
T
995da54430 feat(mcp): share one serve --mcp per project across MCP clients (#411)
One shared, detached daemon per project root: every `codegraph serve --mcp` is a thin stdio<->socket proxy (Unix socket / Windows named pipe) to it, so N agents in one repo share a single file watcher, SQLite connection, and tree-sitter warm-up instead of N copies. The daemon outlives any single session and reaps via client-refcount + idle timeout; `CODEGRAPH_NO_DAEMON=1` opts out.

Hardened during review: detached-process lifecycle (preserves the #277 watchdog via the proxy; the daemon no longer orphans on host SIGKILL), atomic lockfile + pid-verified stale-clear (no double-daemon on concurrent startup), realpath root canonicalization. Validated on macOS, Linux (Docker - 3x fewer inotify watches for 3 agents), and Windows (named pipes); A/B confirms byte-identical tool output vs direct mode. Closes #411.

Co-Authored-By: Colby McHenry <me@colbymchenry.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 19:54:56 -05:00

37 lines
1.4 KiB
TypeScript

/**
* Resolved package version, computed once at module load.
*
* The version string is the rendezvous datum between cooperating daemon and
* proxy processes: the daemon advertises its version in the hello line, and
* the proxy refuses to share IPC across a mismatch (falls back to direct
* mode). Keeping the resolution in one place avoids drift between the CLI
* `--version` output (which reads `package.json` directly) and the daemon
* handshake.
*
* Resolution strategy: read the bundled `package.json` two levels up from
* this file — same relative position whether we're loaded from `src/mcp/` or
* the `dist/mcp/` output, since `tsc` preserves the layout. If reading fails
* (e.g. the package was unpacked oddly), fall back to "0.0.0-unknown" — a
* sentinel that will never match a real version, so the proxy harmlessly
* falls back to direct mode.
*/
import * as fs from 'fs';
import * as path from 'path';
function readPackageVersion(): string {
try {
const pkgPath = path.join(__dirname, '..', '..', 'package.json');
const raw = fs.readFileSync(pkgPath, 'utf8');
const parsed = JSON.parse(raw);
if (typeof parsed?.version === 'string' && parsed.version.length > 0) {
return parsed.version;
}
} catch {
// Fall through to sentinel.
}
return '0.0.0-unknown';
}
export const CodeGraphPackageVersion = readPackageVersion();