mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-18 13:53:01 +08:00
ee97a57a9b
* fix(directory): a schema-less codegraph.db does not make a project initialized (#1895) isInitialized() accepted any existing .codegraph/codegraph.db, so an empty or table-less file in an ancestor directory (an interrupted init, a stray touch, a never-populated ~/.codegraph/) captured the upward walk of findNearestCodeGraphRoot / resolveProjectPath / resolveServerRoot for every project beneath it: the real index of a sub-project became unreachable, the sub-project down-scan never ran, and commands either operated on the broken file or failed opening it instead of showing the not-initialized guidance. An initialized project is now one whose db carries the schema: the probe is gated by file size (>= the 100-byte SQLite header), then the header magic, then a read-only node:sqlite open with a single sqlite_master lookup for the `nodes` table, memoized per path + mtime + size so hot callers (the prompt hook, MCP root resolution on every call) never reopen an unchanged db. The handle is closed immediately so the probe never holds the db on Windows; a locked/busy db counts as live. createDirectory() uses the same predicate, so `codegraph init` in the directory with the broken file repairs it in place (the schema is applied with CREATE ... IF NOT EXISTS) instead of refusing with "Already initialized"; the CLI says what it found. Nothing is deleted automatically. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(directory): a database we cannot open read-only still counts as initialized The schema probe failed CLOSED: a real WAL codegraph.db in a directory the process cannot write (a read-only checkout, a mount, another user's tree) made the read-only node:sqlite open throw — SQLite must create `-shm` to open a WAL database — and isInitialized() reported the project as not initialized, where main's file-exists check had been right. The probe now fails OPEN. Once the size gate and the `SQLite format 3\0` header have passed, the file is a SQLite database; only a SUCCESSFUL sqlite_master query proving the `nodes` table absent may return false. Any open/prepare error (locked, busy, cantopen, readonly, disk I/O) returns true, the pre-existing behaviour for a database we cannot inspect. No error strings are matched. The per path + mtime + size memo is unchanged, and schema-less/empty files still return false, so `codegraph init` still repairs them and never touches a real db. Test: a WAL db copied into a `.codegraph/` made read-only with chmod stays initialized — skipped on win32 and when running as root (root ignores mode bits). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(init): refuse a codegraph.db that is not SQLite instead of promising a rebuild Review found that a `.codegraph/codegraph.db` holding bytes that are not SQLite at all counted as "schema-less", so `init` printed "rebuilding it" and then failed with SQLite's "file is not a database". Only an empty file or a SQLite database without the codegraph tables can be rebuilt in place; `hasSchemalessDb` now means exactly that, and the new `hasForeignDbFile` names the other case. `init` stops on it with exit 1, says which file it is and to move or delete it, and never touches it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(directory): ask SQLite what codegraph.db is instead of reading its header ourselves (#1895) The header check opened and closed a descriptor of our own on `codegraph.db`. Closing any descriptor on a database file drops every POSIX lock the process holds on it, including those of a connection it already has open (sqlite.org/howtocorrupt.html §2.2.1) — and the MCP server resolves projects through isInitialized on every call while it holds the index as its writer. mcp-projectpath-lifecycle's takeover tests caught it: after a real owner exits, the taking-over engine's next read failed with "disk I/O error" (2 of 21 fail with the header read; 21/21 on main and with this change). One read-only SQLite probe now answers all three questions: the schema is there, SQLite opened it and the schema is not (repairable), or SQLite refused it as not a database (SQLITE_NOTADB). Anything else — locked, busy, no `-shm` possible — still fails open as initialized. SQLite's own connections share one lock table per file, so opening and closing a second one leaves the first one's locks alone. A test pins that isInitialized and both init helpers never open the file themselves while this process holds it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(changelog): keep the #1895 entry clear of #1917's, so the carries merge in any order Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: danusha2345 <danusha2345@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>