Two environments that share one working tree — most concretely Windows
and WSL — can't safely share a single `.codegraph/`: the daemon lockfile
records a platform-specific pid + socket (named pipe vs Unix socket), and
SQLite locking across the WSL2/Windows filesystem boundary is unreliable,
so two daemons over one index risks corruption.
Add a `CODEGRAPH_DIR` env var (default `.codegraph`) that overrides the
per-project data directory name, so each environment keeps its own index
in the same tree (e.g. `CODEGRAPH_DIR=.codegraph-win` on Windows). The
name is resolved live and validated (rejects separators / `..` / absolute,
falling back to the default with a one-time stderr warning). Indexing and
file-watching now skip ANY `.codegraph-*` sibling so neither side trips
over the other's data.
Routes the previously-hardcoded `.codegraph` literals (db path, lockfile,
error log, watcher ignore, file-scan skip, installer) through the
resolver. No extraction-version bump — index content is unchanged.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Batch getNodesByIds to collapse N+1 reads in graph traversal, invalidate the
insertNode LRU cache so INSERT OR REPLACE doesn't serve a stale row, and run
incremental PRAGMA optimize + passive WAL checkpoint after bulk writes.
Closes#108
* fix(db): eliminate concurrent-read "database is locked"; add node:sqlite backend (#238)
WAL + busy_timeout were already enabled, so the issue's suggested fix was a
no-op. The real causes, addressed here:
- busy_timeout is now set first (before journal_mode) and lowered 120s -> 5s,
so open-time pragmas wait out a lock instead of hanging for two minutes.
- getCodeGraph no longer opens a second connection to the default project when
a tool passes its own projectPath (the in-process lock amplifier).
- The wasm fallback (no WAL) gets a bounded read-retry on SQLITE_BUSY.
- New: node:sqlite backend, preferred over wasm, so installs whose native
better-sqlite3 build fails land on a real-WAL backend instead of no-WAL wasm.
- codegraph status / codegraph_status now report the effective journal mode, so
a lock report is triageable (wal vs delete).
- CLI hard-blocks Node < 20 to actually enforce the engines floor.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(db)!: node:sqlite is the sole backend; drop better-sqlite3 + wasm
Now that distribution will bundle a Node 24 runtime, node:sqlite (real SQLite
with WAL + FTS5) is always available. Collapse the three-backend adapter to
node:sqlite only and remove the machinery the other two needed:
- Remove better-sqlite3 (optionalDependency) and node-sqlite3-wasm (dependency).
- Remove WasmDatabaseAdapter, the named->positional param translation, the
SQLITE_BUSY read-retry, the wasm fallback banner, the backend env override,
and the native/node-sqlite/wasm selection chain.
- createDatabase now opens node:sqlite directly, with a clear error pointing at
the bundled release / Node 22.5+ when the module is absent.
- NodeSqliteAdapter.close() is idempotent and pragma() supports { simple }, to
match the better-sqlite3 behavior callers relied on.
- status (CLI + MCP) reports the single node:sqlite backend; journal-mode
diagnostics and the getCodeGraph single-connection fix are retained.
- Tests repointed off better-sqlite3 onto node:sqlite.
Net -1044 lines. Running from source now requires Node 22.5+.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(dist): self-contained bundle prototype (vendored Node + install channels)
Phase 3 of the node:sqlite migration: ship a vendored Node runtime so CodeGraph
runs with no system Node and no native build (node:sqlite is built in).
- scripts/build-bundle.sh: build a per-platform archive (official Node + dist +
prod deps + launcher). Same recipe per platform; pins Node v24.16.0.
- install.sh: curl|sh installer (no Node required) — detects os/arch, pulls the
archive from Releases, symlinks onto PATH; re-run to upgrade, --uninstall to
remove. The VPS/SSH path.
- scripts/npm-shim.js: thin launcher for the npm channel — resolves the
per-platform optionalDependency bundle and execs it, so `npm i -g` keeps
working and the real work runs on the bundled Node regardless of the user's.
- BUNDLING.md: distribution design + release-pipeline TODO (CI matrix, platform
packages, code signing, brew, retiring the Node-version gate).
Validated end-to-end: darwin-arm64 and linux-x64 bundles both run init + index +
status (Backend: node:sqlite, Journal: wal) + FTS query with NO system Node —
linux-x64 verified in a clean ubuntu:24.04 amd64 container. Release archives are
gitignored; CI will produce and upload them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(dist): add Windows PowerShell installer (install.ps1)
The `irm … | iex` one-liner for Windows, mirroring install.sh: detect arch,
pull the matching bundle from Releases, extract to %LOCALAPPDATA%\codegraph,
add it to user PATH. Re-run to upgrade. (Windows bundle production in
build-bundle.sh is still TODO.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(dist): release workflow + npm packaging; README/CHANGELOG for bundled distro
- .github/workflows/release.yml: manually-triggered (workflow_dispatch) release
matrix. Builds a self-contained bundle per platform on its own runner
(darwin-arm64/x64, linux-x64/arm64), publishes a GitHub Release with all
archives, and publishes the npm thin-installer (shim + per-platform packages).
Windows targets are TODO (build-bundle.sh is unix-only).
- scripts/pack-npm.sh: assemble the npm packages from built bundles — per-platform
packages tagged os/cpu + the main shim package with them as optionalDependencies
(esbuild pattern). Proven locally: npm-install the tarballs, run via the shim,
resolves the bundle and runs on the bundled Node 24 (node:sqlite / WAL).
- README: install section now leads with the no-Node one-liners (curl|sh, irm|iex)
then npm/npx; "bundled · none required" badge.
- CHANGELOG: standout headline for the self-contained release, plus Added/Changed/
Removed for the install channels, node:sqlite backend, and dropped deps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(dist): Windows bundles + single-trigger release workflow
- build-bundle.sh: add win32-x64 / win32-arm64 targets — download Node's Windows
zip, bundle node.exe + a .cmd launcher, output a .zip. Verified structurally
(PE32+ node.exe, CRLF .cmd, portable node_modules). Since there are no native
addons, any target builds on any OS, so the whole matrix builds on one runner.
- pack-npm.sh: handle .zip bundles and win32 packages (os: win32, node.exe).
- release.yml: simplified to your spec — manual trigger reads the version from
package.json, builds all platform bundles, creates the GitHub Release with notes
pulled from CHANGELOG.md, and publishes the npm shim + platform packages.
- BUNDLING.md: Windows + build-anywhere notes; release pipeline documented.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the visibility gap behind issues #138 (WASM-on-macOS) and #139
(MCP "database is locked"). `better-sqlite3` is in optionalDependencies,
so when the native build fails npm install still succeeds and the
runtime silently falls back to node-sqlite3-wasm — 5-10x slower and
without WAL, so writers block readers (which is what makes the MCP
server appear to "lock the DB" in #139). The only existing signal was
a one-line `console.warn` to stderr that MCP transports typically
swallow.
This patch does NOT change install behavior — better-sqlite3 stays in
optionalDependencies so cross-platform installs keep working. It just
makes the substitution observable + recoverable.
## Visibility (4 surfaces)
- CLI `codegraph status`: new `Backend:` line under Index Statistics.
`native` rendered green; `wasm` rendered yellow with an inline
`npm rebuild better-sqlite3` nudge. Also exposed in `--json` as
`backend: 'native' | 'wasm'`.
- MCP `codegraph_status`: new `**Backend:**` line. Native form reads
`native (better-sqlite3)`; wasm form prepends a warning glyph and
includes the full fix recipe.
- Stderr banner on fallback (`buildWasmFallbackBanner`): replaces the
bare one-line `console.warn` with a multi-line bordered banner
covering macOS + Linux fix steps and optionally appending the
native load error.
- README troubleshooting: new "Indexing is slow / MCP database is
locked / WASM fallback active" entry that walks users to the
`Backend:` line and the fix.
## Per-instance backend tracking
`createDatabase` previously set a module-level `activeBackend` global.
MCP can open multiple project DBs in one process via the
`getCodeGraph()` cache, so the global would race / overwrite. Refactor:
`createDatabase` now returns `{db, backend}`, `DatabaseConnection`
carries `private backend` and exposes `getBackend()`, and
`CodeGraph.getBackend()` is the public surface. The CLI and MCP both
call `cg.getBackend()`.
## What this does NOT fix
The root cause of users landing on WASM is environment-specific (Mac
without Xcode CLT, Node version mismatch, etc.) and not fixable in
code without changing the optionalDependencies design. The README
entry tells users what to run; `Backend: native` after rebuild is the
confirmation signal.
## Tests
New `__tests__/sqlite-backend.test.ts` (6 tests) pins the banner
recipe content (so future edits can't strip the recovery commands),
the `WASM_FALLBACK_FIX_RECIPE` constant, and per-instance
`DatabaseConnection.getBackend()` / `CodeGraph.getBackend()` reporting.
Suite: 503 → 509, all passing.
Credit to @andreinknv whose analysis on #138 (and patches on his fork
at 6d0e7a2 + 69f7001) framed the visibility approach.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace native tree-sitter with web-tree-sitter + tree-sitter-wasms for
universal cross-platform support. Add node-sqlite3-wasm as a fallback
when better-sqlite3 native bindings aren't available. Move better-sqlite3
and sqlite-vss to optionalDependencies so installs never fail.
Fix installer to use npx fallback when global npm install fails, so MCP
config, hooks, and quick-start instructions all work without the bare
codegraph command in PATH.
Fix tests: update schema version expectation, fix db test paths and
method names, extract MAX_OUTPUT_LENGTH as module constant, normalize
Windows path separators in import resolver.
- Add provenance column on edges for tracking how edges were created
- Add project_metadata table for version/provenance tracking
- Make unresolved_refs file_path/language NOT NULL with defaults
- Add composite indexes for unresolved_refs and edges.provenance
- Update v2 migration to handle all new schema additions
- Record schema version on initialize to prevent re-migration
- Add dynamic prepared statement cache (getDynamicStmt) for varying SQL
- Add batch methods: getNodesByIds, getNodesByKinds, getFileHashMap, getFileSyncMap
- Add project metadata methods: getMetadata, setMetadata, getAllMetadata
- Optimize getStats to use single aggregate query
- Optimize getStaleFiles to use temporary table JOIN
- Add provenance parameter to getOutgoingEdges
- Add intent field to SearchOptions type
- SQLite performance pragmas: synchronous=NORMAL, 64MB cache,
memory temp store, 256MB mmap (safe with WAL mode)
- Batch insert for unresolved refs: single transaction instead of
N individual inserts per file
- Symbol caching (warmCaches): pre-load all nodes into memory maps
before resolution, eliminating repeated SQLite queries per ref
- Async file I/O: fs.stat/readFile in indexFile() are now non-blocking
- Denormalize filePath/language onto UnresolvedReference: avoids N
node lookups during resolution, with schema migration v2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds support for Dart and Liquid languages with tree-sitter parsing.
Improves accuracy of code symbol extraction for existing languages.
Indexes project files to enhance code navigation features.
Migrates build system to facilitate code contributions.
Removes git hook functionality.
Integrates Sentry for error tracking and reporting.
Enhances project initialization and configuration loading.