`ui/src` now builds two ways from one tree: the static app `codegraph ui`
serves, and — via `svelte-package` — a Svelte library the Pro app imports.
A forked component would be a second answer to the same question about the
same graph, so there is no fork.
Everything a screen knows arrives through a `GraphAdapter`: eleven methods
answering the wire shapes verbatim, with `createHttpAdapter()` (the loopback
JSON API) as the default and a host's in-process engine reads as the point.
`lib/api.ts` became a one-line-per-call facade over it, which is why no call
site in the views changed. The payload types moved to `lib/wire.ts` — no
imports, no runtime — so a host can depend on the vocabulary alone.
Two more seams and one guard:
- `lib/navigation.ts` holds the href builders behind a `NavigationDriver`, so
a host addresses its own URL space. The app's half — the hash parser and the
live route, which attach window listeners at module scope — stays in
`router.svelte.ts` and is pruned out of the package: rendering a Symbol view
must not install a hash router in somebody else's application.
- `lib/theme.css` carries the design tokens and maps Svelte Flow's `--xy-*`
variables onto them, so a host never sees library defaults. Dark now also
answers to a bare `[data-theme]`, which is how `<CodegraphUi theme>` themes
a container rather than the document.
- `scripts/check-ui-package.mjs` prunes the app's shell, resolves the
extensionless specifiers svelte-package leaves behind, and asserts that
nothing but `lib/adapter.js` reaches the network.
The search box, its keyboard and its panel are one component now
(`SearchPalette`), because splitting them is what breaks a palette.
`__tests__/ui-package.test.ts` mounts the three screens from the package entry
against a mock adapter in jsdom; it runs as a second vitest project so the
`browser` resolve condition it needs cannot reach the engine's suites.
Versioned with the engine. Prepared, not published: `private: true` is the
guard and `pack-npm.sh` only packs a tarball under CODEGRAPH_PACK_UI=1.
The viewer ran a second highlighter over source the engine had already parsed
with a real grammar: Shiki, plus 56 pruned TextMate grammars shipped in
dist/textmate/. The classification now comes off that tree instead, so a file is
read by exactly the grammar that decided what its symbols are.
The swap is complete rather than flagged: @shikijs/core, @shikijs/engine-javascript
and @shikijs/langs are off the dependency list, scripts/prune-grammars.mjs and
`npm run build:textmate` are deleted, and check-ui-build.mjs asserts the
tree-sitter grammars in dist/extraction/wasm instead of dist/textmate.
The wire contract is unchanged — `[classId, text]` pairs with the class names
alongside — so the viewer's decoder and code blocks did not have to be rewritten.
Two classes are added to the six: `type` (a named type reference, painted at
plain ink) and `def` (the name a definition declares, weight 600), the latter
taken from the extractors' own definition tables so it cannot drift from what
indexing calls a definition.
Three differences are not cosmetic:
* Interpolations (`${…}`, `#{…}`, `$"{…}"`, f-strings) are classified as code,
not as string. The call-site overlay refuses to claim a token classed string,
so calls written inside interpolated strings now link.
* Built-in type words are emitted whole and classed `type` in every language.
The grammars disagree about whether `string` is a type_identifier or an
anonymous token inside a predefined_type, and TextMate scoped them
inconsistently too.
* 3 000 lines of TypeScript cost 24-41 ms instead of ~700 ms.
Given up deliberately: Liquid, Razor, YAML, Twig, XML and .properties render
plain. .svelte/.vue/.astro are classified through their <script> blocks, the same
delegation the SFC extractors do. Pulling html/css/vue out of tree-sitter-wasms
would cover them, but those ABI-13 builds are the known cause of shared-WASM-heap
corruption for every other language in the same process.
Measured parity, per-language before/after screenshots and the reproduction
recipe: docs/design/cg57-highlighting-parity.md.
The viewer's code block stops lexing with a hand-rolled dialect table and
reads real TextMate grammars instead, run once in `/api/source`.
Three things make that safe to depend on:
* Highlighting never fails a request. A missing grammar, an oversized
slice, an ESM import that did not resolve — every one of them answers
`engine: 'plain'` with a reason and the source still goes out.
* Identifiers survive whatever token boundaries a grammar chose. Every
code token is split into identifier runs before it goes on the wire, so
the graph's call-site overlay claims a token the highlighter produced
rather than re-cutting the line. `assignRefs` now matches on a token's
text rather than on the class a grammar gave it, so a language that
scopes type names as `storage.type` still links.
* The theme classifies rather than colours: its foregrounds are sentinels
the server maps back to class names, and the viewer paints them from
CSS custom properties — one token stream serves light and dark with no
refetch, and the ramp lives only in app.css.
Comments move from --ink-3 to a new --code-comment. --ink-3 measures
3.46:1 on paper and 3.00:1 on the hot-line tint, both under AA for 12.5px
text; --code-comment is the smallest step along the same ramp that clears
4.5:1 on every background a code line can have, and stays quieter than
the strings and numbers above it.
Shipping: @shikijs/core and @shikijs/engine-javascript are runtime
dependencies (no wasm, no native module); @shikijs/langs stays a
devDependency and `npm run build:textmate` writes only the closure the
engine's 40-odd languages reach — 56 grammars, 2.6 MB, against 11 MB for
all 722. check-ui-build.mjs asserts the tree after every build and inside
every release archive.
Adds `ui/` as an npm workspace (Svelte 5.56 + Vite 7, devDependencies only —
the engine's runtime dependencies are untouched) and chains its build into
`npm run build`, so the browser viewer ships inside `dist/` with everything
else: `build-bundle.sh` already copies `dist` wholesale and `pack-npm.sh`
packs that bundle.
Output is `dist/viewer/`, NOT `dist/ui/`: `src/ui/` is the engine's terminal
ui (shimmer progress + its worker) and tsc compiles it to `dist/ui/`, so
emitting there both deletes those modules — the CLI then dies at startup with
`Cannot find module '../ui/shimmer-progress'` — and would leave the static
server handing out compiled engine internals. The design spec is corrected to
match.
`scripts/check-ui-build.mjs` is the release guard: index.html must exist, be
non-trivial, and every local asset it references must be on disk, and the
compiled engine next door must still be intact. It runs after every UI build,
again in `build-bundle.sh` once the bundle stage has copied `dist`, and again
in `pack-npm.sh` once each archive is unpacked — so a broken viewer fails the
release instead of shipping a CLI that serves a 404.
`vite build` does not override an ambient NODE_ENV, so a shell or runner with
NODE_ENV=development silently shipped dev-mode Svelte (~13 kB of dev-only
runtime checks, warning in the user's console). The config now pins production
for `command === 'build'`; macOS and Windows ARM64 then emit byte-identical
bundle hashes.
The shell itself follows docs/design/codegraph-ui-design-spec.md §2–§3.1:
design tokens as CSS custom properties (light on bare `:root`, dark under both
`prefers-color-scheme` and `[data-theme="dark"]`), square corners, hairline
rules, one oxblood accent; top bar 48px / trail bar 34px / main; a hash router
over `#/s/<id>`, `#/file/<path>`, with `#/map` and `#/flow` reserved for phase
2. Fonts are vendored through @fontsource rather than fetched, so a local
reader works offline and never announces the project to a CDN.
Verified: clean `npm run build` from an empty dist on macOS and on the Windows
ARM64 VM (forward-slash asset URLs, CLI still starts, both assertion failure
modes exit 1); `dist/viewer` present in a real darwin-arm64 bundle and in the
packed npm platform package; shell geometry, tokens, all seven routes, both
themes and font loading checked in headless Chromium with no console errors;
`npm test` unaffected.
- Hero: larger theme-aware standalone Rust logo (new assets/rust-logo{,-dark}.svg
— gear only, no tile card; <picture> swaps by GitHub theme), tagline text
trimmed to 'Kernel powered by Rust'
- 'Built for speed' section: removed the floated language-tile logo (its baked-in
paper card rendered as an odd box on dark theme and pushed the text)
- Removed the '1.0 Released!' banner and the Star History section (+ its
Contents entry)
- package.json → 1.5.0 for the Rust-engine release
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Phase 0 of the Rust extraction-kernel migration (docs/design/
rust-kernel-migration-plan.md, now checked in with §3a recording the
shipped state):
- codegraph-kernel/ napi-rs crate: extractFile(path, content, language)
→ five flat buffers (meta/nodes/edges/refs/arena), one JS boundary
crossing per file. Node ids computed Rust-side, byte-identical to
generateNodeId (pinned by test vector). Reserved per-node metrics slot
for the Arc 3.2 code-metrics work.
- Generic .scm-driven emitter (@def.<kind>/@name/@ref.<kind> captures,
byte-range scope stack → ::-joined qualified names, contains edges,
refs attributed to the innermost enclosing symbol). Seed TS/JS queries
are smoke-level; R2 replaces them with the full port.
- Routing seam in extractFromSource with per-file wasm fallback.
DEFAULT_ROUTED is empty — no behavior change until a language passes
its equivalence gate (R3). Dev opt-in: CODEGRAPH_KERNEL_LANGS. Kill
switch: CODEGRAPH_KERNEL=0. Loader verifies ABI + kind tables before
routing; EDGE_KINDS became a runtime array because kind order is now
wire contract.
- Grammar-source parity: vendored TS/TSX/JS wasm grammars built from the
exact crate revisions (tree-sitter-typescript v0.23.2,
tree-sitter-javascript v0.25.0, checked-in parser.c, ts-cli 0.25.10) —
the tree-sitter-wasms builds were 2023-era, which the new
kernel-grammar-parity test caught on day one. Production TS/JS parsing
gets 2.5 years of grammar fixes; full suite green (2456 tests).
- Build/release wiring: scripts/build-kernel.sh + npm run build:kernel;
release.yml kernel prebuild matrix (continue-on-error — the kernel is
optional everywhere, bundles fall back to the wasm path); bundles stage
lib/kernel/codegraph-kernel.node; release job runs the kernel suites
with CODEGRAPH_KERNEL_EXPECT=1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every published artifact is now cryptographically verifiable as built by
this repo's Release workflow: npm publishes carry npm provenance (OIDC,
shows the Provenance badge on npmjs.com), and the GitHub Release bundles
+ SHA256SUMS get signed build attestations via
actions/attest-build-provenance, verifiable with
`gh attestation verify <file> -R colbymchenry/codegraph`.
pack-npm.sh now writes a repository field into the generated shim and
per-platform package.jsons — npm --provenance refuses to publish without
one matching the repo — and the root package.json gains the same field.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Ships Nix language support and a batch of fixes staged under [Unreleased],
including the Java/Kotlin (Spring) resolution performance fix (#1180).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Patch release: installer prunes old version bundles (#1074) and
`codegraph index` rebuilds an oversized index without wedging (#1067).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Release the four CLI/indexing fixes triaged from @jcrabapple's reports
(#1044 node -f, #1045 query %, #1046 explore count, #1047 Android res XML)
plus the rest of [Unreleased]. The Release workflow promotes the
changelog and publishes.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Benchmark table reordered to lead with tool calls, time, and file reads (the universal wins); cost and tokens moved right with a note that savings are scale-dependent, not a headline claim
- README/introduction/quickstart/installation messaging updated to "surgical context · fewer tool calls · faster answers" framing, dropping the "16% cheaper" headline
- Node engine floor raised from 18 to 20 in CLAUDE.md, package.json description updated
- `codegraph init` now creates and indexes in one step; the `-i` flag is retired (still accepted as a no-op)
- CLI reference expanded with new commands: `explore`, `node`, `unlock`, `daemon`, `telemetry`, `upgrade`, `version`, `help`
- MCP server docs clarified: single `codegraph_explore` tool exposed by default, others unlisted but re-enableable via `CODEGRAPH_MCP_TOOLS`
- Language support adds Objective-C, Astro, and R; framework routes adds Play, Vue Router/Nuxt, and Astro
- API reference documents lower-level exports and embedding requirements (Node 22.5+ for `node:sqlite`)
- Troubleshooting adds WSL/Windows dual-checkout guidance
- How-it-works updated: SQLite backend is now Node's built-in `node:sqlite` in WAL mode, not better-sqlite3/WASM
chokidar v4 holds one OS file descriptor per watched file on macOS (libuv's
kqueue backend registers an fd per vnode; fsevents is installed but v4 no
longer uses it). On a large project the `serve --mcp` daemon accumulated tens
of thousands of open REG descriptors and exhausted kern.maxfiles — crashing
unrelated processes system-wide with ENFILE. #276 only trimmed the count by
ignoring directories; the source tree still cost one fd per file.
Replace chokidar with a pure-JS native fs.watch hybrid, keeping codegraph's
zero-native-addon "any OS builds any bundle" invariant:
- macOS / Windows: a single recursive fs.watch (one FSEvents stream /
ReadDirectoryChangesW handle) -> O(1) descriptors regardless of repo size.
- Linux: one inotify watch per directory (O(dirs), dynamic add for new
dirs, capped via CODEGRAPH_MAX_DIR_WATCHES) instead of per-file watches.
Validated empirically: macOS 0 extra fds at 6k and 12k files; Linux 31 inotify
watches at 6k files (per-file would be 6k); Windows recursive catches nested
and new-directory edits. Full test suite green.
Tests drive the watcher through an inertForTests seam (no OS watcher) for
determinism under parallel vitest, with one real-fs end-to-end test exercising
the genuine native path.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cuts the 0.9.8 release, which carries the restored embedded/programmatic
SDK API (#354) along with the rest of the [Unreleased] changelog. The
Release workflow promotes [Unreleased] -> [0.9.8] and appends the link
reference; only the version fields are bumped here.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The file watcher registered a recursive watch over the entire project (node_modules, build output, caches included) and filtered only in the callback — exhausting the Linux inotify budget on large repos (#276). It now uses chokidar and excludes the same directories the indexer ignores (built-in default-ignore set + the project .gitignore) BEFORE registering a watch, so the watch count on a 900-dir node_modules drops from ~1200 to ~14 even with no .gitignore. Stacks with the shared daemon (#411): one watcher across agents, now small.
Also hardens the #411 daemon lockfile against a concurrent-startup race the new watcher timing made reproducible — the lock is now created atomically with its content (temp-write + hard-link), so racing daemons can never both win. Validated on macOS, Linux (Docker), and Windows (chokidar + fs.linkSync on NTFS).
Co-Authored-By: Colby McHenry <me@colbymchenry.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Installing from a registry mirror (npmmirror/cnpm) that hadn't mirrored the
per-platform optionalDependency left codegraph failing with "no prebuilt
bundle for <platform>" — npm treats an unfetchable optional dep as success and
silently skips it. The npm-shim now self-heals: when the bundle is missing it
downloads the matching archive from GitHub Releases (checksum-verified, with a
download timeout) and caches it, so a global install works on any registry.
release.yml now publishes SHA256SUMS and triggers an npmmirror sync after
publish. Adds hermetic tests for the shim (resolution, cache reuse, disable
knob, download + checksum match/mismatch/absent).
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0.9.3 was prepped in the repo but never released (latest published is
0.9.2), so the turboshaft WASM Zone OOM fix ships as part of 0.9.3.
Fold its changelog entry into [0.9.3] and revert the version bump.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Large multi-language indexes crashed with `Fatal process out of memory:
Zone` on Node 22/24 (including the bundled runtime) — V8's turboshaft
optimizing WASM compiler exhausts its per-compilation Zone arena while
compiling tree-sitter grammars on a background thread, even with tens of
GB free (the Zone is a V8-internal arena, not the JS heap).
Run node with V8 `--liftoff-only`, which keeps grammar compilation on the
Liftoff baseline and never reaches the optimizing tier. Delivered via the
bundled launcher + a one-shot CLI re-exec guard for all other launch
paths. Empirically only `--liftoff-only` stops it (`--no-wasm-tier-up` /
`--no-wasm-dynamic-tiering` do not), and it must be on node's command
line (setFlagsFromString / worker execArgv / NODE_OPTIONS all fail).
Reproduced the exact crash with the real indexer on Node 24.16 against a
2,880-file / 18-language repo and confirmed the fix eliminates it; full
suite + 7 new tests pass. Bumps to 0.9.4.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a cross-channel uninstall that removes CodeGraph from every agent it's
configured on (Claude Code, Cursor, Codex CLI, opencode, Hermes). Prompts
global-vs-local up front (no flags required) and reports which providers it
actually hit; --location / --target / --yes supported for non-interactive use.
Removes only what install wrote; leaves the .codegraph/ index to `uninit`.
Also fixes Cursor uninstall leaving an orphaned .cursor/rules/codegraph.mdc
(its description: CodeGraph frontmatter lingered); the dedicated rules file is
now deleted outright while user content outside our markers is preserved.
Validated end-to-end on macOS and Docker Linux (global + local sweeps clean).
Adds 8 tests; full suite 730 passing. Bumps to 0.9.3 with CHANGELOG entry.
Resolves#313.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The npm thin-installer shim spawned the per-platform bundle's `.cmd`
launcher directly. Modern Node on Windows refuses to spawn `.cmd`/`.bat`
without `shell: true` (the CVE-2024-27980 hardening), so every `codegraph`
command failed with `spawnSync …\codegraph.cmd EINVAL` (seen on Node 24).
On Windows the shim now invokes the bundled `node.exe` against the app
entry point directly, bypassing the `.cmd` (and avoiding the arg-quoting
pitfalls of `shell: true`). Unix is unchanged.
Validated end-to-end against a real win32-x64 bundle: `npm install` of the
packed tarballs + `codegraph init -i`/`status` run on the bundled Node 24.
Also cuts release 0.9.2, rolling up the pending Drupal, zero-config,
config-removal, Hermes-installer, and symlink-security changes.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Remove .codegraph/config.json and the entire config surface. CodeGraph now
indexes every file whose extension maps to a supported language and respects
.gitignore everywhere — git repos via git itself, non-git projects via the
`ignore` library (root + nested .gitignore files, the same way git does).
- Remove CodeGraphConfig/DEFAULT_CONFIG, src/config.ts, and the public config
API (the `config` option on init, getConfig/updateConfig/getConfigPath).
- Derive the source-file allowlist from EXTENSION_MAP (isSourceFile); maxFileSize
is now a constant. Drop the .codegraphignore marker.
- Behavior change: committed, non-gitignored dirs (vendor/, a committed dist/)
are now indexed — .gitignore is the single source of truth.
Earlier inert fields (languages, frameworks, extractDocstrings, trackCallSites,
customPatterns) and their dead helpers are removed as part of this.
Resolves#283.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* 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>
better-sqlite3 ^11.0.0 (latest 11.10.0) ships no prebuilt binary for
Node 24's ABI (node-v137) and predates Node 24, so every Node 24 install
silently fell back to the 5-10x-slower WASM backend. Bump to ^12.4.1 —
the first 12.x with the Node 24 prebuild — and raise the engines floor to
Node 20 (Node 18 is EOL and dropped from better-sqlite3 12.x prebuilds).
Verified on macOS Node 24.15.0 (ABI 137): prebuilt binary used with no
compiler (installs even with CC/CXX sabotaged), `codegraph init -i` shows
no WASM banner, and `codegraph status` reports Backend: native. 639/639
tests pass on Node 22.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(mcp): line numbers in explore output + per-file cluster fixes
Follow-up to #185. Three changes to codegraph_explore:
1. Source sections now carry cat -n style line-number prefixes
(<num>\t<code>), so the agent can cite file:line straight from the
payload instead of re-Reading the file just to recover a line number.
Isolated A/B: the no-line-numbers arm spent 2 Reads + a grep to find a
line number the line-numbered arm cited with zero follow-up calls.
Payload cost ~3-5%. Toggle off with CODEGRAPH_EXPLORE_LINENUMS=0.
2. Per-file cluster selection now ranks clusters containing a query entry
point ahead of dense declaration blocks. Density-only ranking buried
the relevant methods (perform/didCreateURLRequest/task in Alamofire's
Session.swift) under the top-of-file class header + property list.
3. Whole-file "envelope" nodes (a class/struct/etc. spanning >50% of the
file) are excluded from clustering. The Session class spans ~1,400
lines; keeping it collapsed every method into one giant cluster that
tail-trimmed down to just the class header, hiding the methods.
Net vs the 0.7.10 baseline, line numbers on: Alamofire -60%, Excalidraw
-32%, VS Code -12% per explore call.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(mcp): language-neutral omission markers in explore output
The gap separator and the two tail-trim markers used C-style `//`
comments, which aren't comments in Python, Ruby, etc. Switch to plain
`... (gap) ...` / `... (trimmed) ...` so they read correctly inside any
language's fenced source block. With line numbers on, the line-number
jump already corroborates a gap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(mcp): language-neutral truncation marker in codegraph_context
Sibling to the explore marker fix: codegraph_context's code-block
truncation used a C-style `// ... truncated ...`. Switch to
`... (truncated) ...` so it reads correctly in any language's fenced
source block.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(release): bump version to 0.7.11
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* release: 0.7.7 (multi-agent installer — Cursor, Codex, opencode)
* fix(installer): opencode .jsonc + AGENTS.md (0.7.8)
v0.7.7 wrote ~/.config/opencode/opencode.json, but opencode reads
opencode.jsonc by default — so the codegraph MCP entry never appeared
in any opencode session. Also installs AGENTS.md so opencode's model
reaches for codegraph_* tools instead of native Grep.
- Prefer existing .jsonc, fall back to .json, default new installs
to .jsonc.
- Surgical edits via jsonc-parser preserve user comments and
formatting across install / re-install / uninstall round-trips.
- Install AGENTS.md (global ~/.config/opencode/AGENTS.md, local
./AGENTS.md) with the shared INSTRUCTIONS_TEMPLATE — same
marker-delimited approach Codex uses.
- +9 opencode-specific tests covering filename precedence, comment
preservation, AGENTS.md install + sibling-content preservation,
uninstall reverses both files.
575/575 tests pass. Hand-verified end-to-end: opencode session calls
codegraph_node + codegraph_callers for a structural query, zero Grep
calls.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: overhaul CLAUDE.md and add scripts/release.sh + Cursor rules file
Replaces the old Claude-only CLAUDE.md with a comprehensive guide covering
the full project architecture, multi-agent installer, test conventions,
NodeKind/EdgeKind reference, and release workflow. Key additions:
- Documents the layered pipeline, all module paths, and the multi-target
installer (targets/, registry.ts, AgentTarget interface).
- Adds the Cursor `--path` quirk and the "update all three surfaces" rule
when changing MCP tool guidance.
- Documents `npm run eval`, `test:eval`, and the full set of build/test
commands including single-file patterns.
- `scripts/release.sh` — idempotent bash script that tags the current
commit, pushes the tag, and creates a GitHub Release whose notes are
extracted from the matching `## [X.Y.Z]` block in CHANGELOG.md. Safe
to re-run after partial failure.
- `.cursor/rules/codegraph.mdc` — Cursor-specific agent instructions
(tool decision table, rules of thumb, index-lag warning) written by
the installer and kept in sync with server-instructions.ts and
instructions-template.ts.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 0.7.5 tarball shipped `dist/bin/codegraph.js` without the executable
bit set, causing `zsh: permission denied: codegraph` after a fresh global
install. The build script now `chmod +x`'s the binary before packing.
Also adds CHANGELOG.md and documents the release workflow in CLAUDE.md.
* fix: add @clack/prompts transitive deps to fix npx installation
When installed via `npx`, npm's flat node_modules cache fails to
hoist ESM-only transitive dependencies from @clack/prompts → @clack/core.
This causes:
Cannot find package 'fast-wrap-ansi/index.js' imported from
@clack/core/dist/index.mjs
Adding fast-wrap-ansi, fast-string-width, and sisteransi as direct
dependencies ensures they are resolved correctly in all installation
contexts (npx, global, local).
Reproduces on Node 24 + npm 11 with `npx @colbymchenry/codegraph@0.7.3`.
* chore: bump @clack/prompts to 1.3.0 with matching transitive pins
@clack/prompts@1.3.0 shipped with major bumps to its transitive deps
(fast-wrap-ansi 0.1 → 0.2, fast-string-width 1 → 3). Promoting them
at the older pins would have caused npm to install both sets side by
side, defeating the dedup goal of this fix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: mfrancime <mfrancime@users.noreply.github.com>
Co-authored-by: Colby McHenry <me@colbymchenry.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Updates Swift and Kotlin language support from basic to full in documentation and reduces explore budget thresholds to optimize performance for smaller codebases.