mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-24 06:53:52 +08:00
Root cause: createDatabase() caught everything the node:sqlite connection threw and reported it as "CodeGraph requires node:sqlite (Node.js 22.5+)", though the module had loaded and SQLite itself had failed: a database another program held open (SQLITE_CANTOPEN on Windows), a folder the user can't write, an I/O error on a network share. Failures in the connection's first statements (locked, not a database, a WAL I/O error) came out raw, without the path. The MCP server then told the agent "No CodeGraph project is loaded" for a default project whose index exists, or "Tool execution failed: ... requires node:sqlite" for a projectPath one. Meanwhile a runtime that really lacks node:sqlite never got the hint: isInitialized's schema probe loaded the module outside its try, so the CLI and MCP server died with "Unhandled rejection: No such built-in module: node:sqlite". Fix: - src/db/node-sqlite.ts loads node:sqlite in one place; NodeSqliteUnavailableError carries the Node 22.5+ hint, now only for a module that cannot be loaded. The schema probe treats it as "unknown", so the command goes on to the open and reports it from inside its own catch. - src/db/open-error.ts: DatabaseOpenError names SQLite's code and the path, with a hint for BUSY, PERM, READONLY, IOERR (network share), CORRUPT, FULL, CANTOPEN (folder, permissions, another program holding the file) and NOTADB, keeping code/errcode/errstr and the cause. The Windows/WSL shared-index guidance still wins for its case. - DatabaseConnection.open/initialize wrap the connection's first statements as well as the constructor, and close the connection on failure. - MCP: the default project's open failure is reported to a tool call instead of "no project loaded", and a DatabaseOpenError or a missing node:sqlite is answered isError with the retry-once note (a malfunction, per AGENTS.md), worded as what failed rather than "an internal codegraph error". Not-indexed projects keep their success-shaped guidance. Validation: - Windows, an indexed project whose codegraph.db another process holds open with no sharing (a real SQLITE_CANTOPEN): CLI status, sync and query, an MCP default-project call and a projectPath call all said "requires node:sqlite" on main, or "No CodeGraph project is loaded" for the default project; with the fix all name SQLITE_CANTOPEN, the path and the hint. With --no-experimental-sqlite (node:sqlite unloadable), main's CLI and MCP server died with an unhandled rejection; the fix prints the Node 22.5+ explanation and the MCP call answers with it. - New __tests__/sqlite-open-error.test.ts (21 cases): main's source 18 fail / 3 pass, fix 21 pass. Real CANTOPEN (a directory, a file held exclusively), NOTADB and BUSY opens, the CLI and the MCP engine, plus each SQLite code's message. 5 mutations each failed at least one case. - The POSIX-only wsl-shared-index case for a real I/O error outside WSL now expects the named error (DatabaseOpenError, SQLITE_IOERR, the path) instead of the bare "disk I/O error"; it is skipped on Windows, so it was not run here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
37 lines
1.4 KiB
TypeScript
37 lines
1.4 KiB
TypeScript
/**
|
|
* Node's built-in `node:sqlite`, loaded in one place, so that a runtime
|
|
* without it fails with the one explanation that fits it: CodeGraph needs
|
|
* Node.js 22.5+, or its own bundled runtime. Any other failure to open a
|
|
* database is SQLite's own, and is reported as such (see ./open-error.ts).
|
|
*/
|
|
|
|
/** The parts of `node:sqlite` CodeGraph uses. */
|
|
export interface NodeSqliteModule {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
DatabaseSync: new (path: string, options?: { readOnly?: boolean }) => any;
|
|
}
|
|
|
|
/** `node:sqlite` is missing or could not be loaded in this Node.js runtime. */
|
|
export class NodeSqliteUnavailableError extends Error {
|
|
constructor(cause: unknown) {
|
|
const reason = cause instanceof Error ? cause.message : String(cause);
|
|
super(
|
|
`Node.js ${process.version} could not load its built-in SQLite module (${reason}).\n` +
|
|
'CodeGraph requires node:sqlite (Node.js 22.5+). Install the self-contained CodeGraph ' +
|
|
'release (it bundles a compatible Node), or run on Node 22.5+.',
|
|
{ cause }
|
|
);
|
|
this.name = 'NodeSqliteUnavailableError';
|
|
}
|
|
}
|
|
|
|
/** Load `node:sqlite`, or throw {@link NodeSqliteUnavailableError}. */
|
|
export function loadNodeSqlite(): NodeSqliteModule {
|
|
try {
|
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
return require('node:sqlite') as NodeSqliteModule;
|
|
} catch (err) {
|
|
throw new NodeSqliteUnavailableError(err);
|
|
}
|
|
}
|