Point the previously-dead (#) support badges at new Supported Platforms / Supported Agents sections, grouped with Supported Languages near the bottom of the README.
Co-authored-by: Andrew Barnes <bortstheboat@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
O_NOFOLLOW is undefined on Windows (libuv ignores it), so the bitwise-OR
silently dropped it and markSessionConsulted would follow a pre-planted symlink
at the tmp marker path — the CWE-59 gap #280 closed on POSIX but not Windows.
Add a cross-platform lstatSync isSymbolicLink() refuse-check before openSync
(O_NOFOLLOW stays as the atomic, TOCTOU-free guard on POSIX). The existing
Session-marker-symlink-resistance test now passes on Windows.
Refs #280
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Validate projectPath in getCodeGraph so MCP clients can't open a codegraph in a
sensitive system directory. Guarded with existsSync so nested/not-yet-created
sub-paths still resolve up to the default project (preserves issue #238). Adds
MCP-handler rejection tests (POSIX + Windows-gated); validated on a real
Windows 11 VM.
Closes#230
Drop the no-op try/catch around insertNode.run, and lowercase the Windows
SENSITIVE_PATHS entries so validateProjectPath's case-insensitive check
actually blocks c:\windows. Adds a validateProjectPath test (POSIX +
Windows-gated); the Windows-gated case was validated on a real Windows 11 VM.
Closes#327
Document the Mac-host -> Parallels Windows 11 SSH workflow for validating
Windows-specific behavior, the win32-gated test convention (it.runIf), and
guest toolchain quirks (PATH refresh, Windows-local clone, VC++ ARM64 redist).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Route handleContext's output through the shared truncateOutput cap
(MAX_OUTPUT_LENGTH) so codegraph_context can no longer blow past the context
budget — every sibling MCP tool already truncates; this was the one uncapped
output path.
Closes#296
Co-authored-by: Baijack-star <71923891+Baijack-star@users.noreply.github.com>
Replace the 7 unbounded ReferenceResolver Map caches with a bounded LRU
(env-tunable via CODEGRAPH_RESOLVER_CACHE_SIZE) so memory stays flat on large
codebases, and add length caps on MCP tool string inputs (query/task/symbol +
projectPath/path/pattern) to prevent oversized-payload DoS. Includes LRU,
MCP-input-limit, and full-pipeline integration tests.
Closes#213
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
The standalone installer resolved the latest release via the GitHub API, which
rate-limits unauthenticated requests to 60/hr per IP and returns 403 on shared
or cloud hosts (devboxes, CI) — leaving "could not resolve latest version". It
now reads the version from the releases/latest web redirect (no rate limit),
falling back to the API, and normalizes CODEGRAPH_VERSION so a bare "0.9.4"
works as well as "v0.9.4".
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>
GitHub deprecated Node.js 20 for actions: actions/checkout@v4 and
actions/setup-node@v4 run on Node 20 and emit a deprecation warning.
Node 24 becomes the forced default on 2026-06-02 and Node 20 is removed
on 2026-09-16. Bump both to @v6 (Node 24). Config is unchanged —
node-version: 22 and registry-url are both supported in v6.
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>
Detects Drupal projects via composer.json drupal/* deps; extracts routes from *.routing.yml (route nodes + references edges to controllers/forms/entity handlers) and Drupal hook implementations from .module/.install/.theme/.inc. Adds yaml/twig as file-level languages and excludes core/contrib by default. Resolves#268.
Adds Hermes Agent (Nous Research) as a CodeGraph installer target. Writes mcp_servers.codegraph and ensures platform_toolsets.cli includes mcp-codegraph in $HERMES_HOME/config.yaml, with full installer contract-test coverage.
`markSessionConsulted` writes `${tmpdir()}/codegraph-consulted-${hash}` on
every `codegraph_context` call so external tooling can detect that an MCP
session has consulted CodeGraph. The old `writeFileSync` followed symlinks
unconditionally, so on a multi-user system any other local user could
pre-create that marker path as a symlink pointing at a victim-writable
file — the next codegraph context call would then overwrite the target's
contents with the ISO timestamp string (CWE-59).
The session-id hash gates predictability and makes opportunistic exploit
infeasible on its own, but tmpdir() is world-writable (mode 1777 on Linux)
and the proper pattern is to never follow links into a shared-prefix
tmpfile. Switch to `openSync` with O_NOFOLLOW + mode 0o600. ELOOP from a
planted symlink lands in the existing silent-fail catch — refuse to write
rather than touch an attacker-chosen target.
Detected by Aeon + manual review.
Severity: medium
CWE-59 (link following), CWE-732 (incorrect permission for critical resource)
Co-authored-by: aaronjmars <aaron@aeon.local>
The old entry described the retired multi-backend chain (better-sqlite3 → wasm
with npm-rebuild instructions). CodeGraph now bundles Node + node:sqlite (WAL),
so the lock class is gone. The entry now covers the only real cases: an old
pre-0.9 install (reinstall) or WAL disabled by the filesystem (move to local disk).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `<div align="center">` hero centered each line of the code blocks, so shorter
lines (`cd your-project`, `npm i -g …`) rendered with stray leading indentation.
Close the centered hero after the badges; install/init sections render normally.
Only the screenshot stays centered.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
install.sh symlinks ~/.local/bin/codegraph -> the bundle launcher, but the
launcher derived its dir from $0, which is the symlink path — so it looked for
`node` next to the symlink and failed with `exec: .../node: not found`. Follow
the symlink chain to the real bundle dir first. (npm was unaffected — the shim
invokes the launcher by absolute path.) Verified via the symlinked install path
in a clean no-Node Linux container.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The first 0.9.0 run published 6/7 npm packages: npm printed
`+ @colbymchenry/codegraph-linux-x64@0.9.0` but the registry never persisted it
(a known npm flake), so the job went green while linux-x64 npm installs were
broken. Now:
- the GitHub Release step is idempotent (create, else upload --clobber);
- the publish loop skips packages already on the registry, so a re-run only fills
gaps;
- a new verify step queries the registry (with retries) and fails the job if any
package@version is missing — green now means actually shipped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Releases now go through .github/workflows/release.yml, which builds the bundles
and publishes the npm thin-installer. The old manual paths published the root
(non-bundled) package, which would break Node < 22.5 users — remove them so they
can't be run by accident. CLAUDE.md + add-lang updated to point at the workflow.
scripts/extract-release-notes.mjs is kept (the workflow uses it).
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>
Pre-0.8 installers wrote `codegraph mark-dirty` / `sync-if-dirty` hooks
to Claude Code's settings.json. Both subcommands were removed from the
CLI, so the Stop hook fails every turn ("unknown command
'sync-if-dirty'"). The cleanup that once removed them was lost when the
installer moved to the per-target architecture.
Add cleanupLegacyHooks(), wired into both install (upgrades self-heal)
and uninstall (so the npm preuninstall step fully reverses a legacy
install). Surgical at the command level: only codegraph's own hook
entries are dropped, so unrelated hooks sharing a matcher group or event
(e.g. GitKraken's `gk ai hook run`) survive, and a settings.json with no
legacy hooks is left byte-for-byte untouched.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Delete dead dev scratch (debug_python_ast*.js, test_python_inheritance.js),
the obsolete tree-sitter-dart native patch (Dart loads via WASM now and the
package is no longer a dependency), and orphaned docs superseded by the
current code and the agent-eval skill (IMPLEMENTATION_PLAN.md,
DELPHI-SUPPORT.md, run-interactive-test.md).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Detect NestJS projects and emit `route` nodes (each linked by a `references`
edge to its handler method) across all four transport layers:
- HTTP controllers: @Controller prefix joined with
@Get/@Post/@Put/@Patch/@Delete/@Head/@Options/@All
- GraphQL resolvers: @Query/@Mutation/@Subscription
- Microservices: @MessagePattern/@EventPattern
- WebSocket gateways: @SubscribeMessage (prefixed with gateway namespace)
Detected from any @nestjs/* dependency in package.json (falls back to scanning
*.controller.ts/*.resolver.ts/*.gateway.ts). Handles class+method path joining
with empty @Controller()/@Get(), a string-aware balanced-paren arg reader so
GraphQL type thunks (@Query(() => [User])) aren't truncated, stacked decorators
(@UseGuards) when locating the handler, and disambiguates the @Query() GraphQL
method decorator from the REST @Query() param decorator (GraphQL only counts
inside @Resolver classes). Also resolves injected *Service/*Controller refs to
their classes by Nest file-naming convention.
Adds 18 framework tests; updates the README framework table and CHANGELOG.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* perf(mcp): steer agents to answer directly instead of delegating to subagents
CodeGraph beats native grep/read on cost only when the agent queries it
directly. When the agent delegates to file-reading sub-agents, those
sub-agents read files regardless of the index, so CodeGraph becomes net
overhead on top of the reads. The install templates even told agents to
"spawn a subagent for explore-class questions" — the expensive path.
Changes:
- server-instructions + both install templates: add an "Answer directly —
don't delegate exploration" directive; reposition codegraph_explore as the
efficient one-call multi-symbol tool (was: "spawn a subagent for it").
- codegraph_explore: hard-cap output to its adaptive budget (it overran,
~30k vs a 28k cap) and tighten the medium tier (28k->13k).
- codegraph_node: return a member outline for container kinds instead of the
full class body.
Rigorous N>=4-per-arm warm-block benchmark (median total_cost_usd):
excalidraw (~600 files): WITH $0.54 vs native $1.02 (-47%)
vscode (~10k files): WITH $0.41 vs native $0.72 (-42%)
ky (~25 files): WITH $0.46 vs native $0.44 (wash)
Answers were equal-or-better (correct, file:line-cited) with ~6x fewer tool
calls; the directive drove the direct path on 14/14 codegraph runs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(readme): rebuild benchmark with real-world repos + cost/token/time/tool savings
Replace the "Claude Code (Python+Rust/Java)" rows — which benchmarked the
Claude Code CLI repo, not real codebases in those languages — with real
open-source projects per language: Django (Python), Tokio (Rust), OkHttp
(Java), Gin (Go), plus Alamofire (Swift) and the existing TypeScript repos
(VS Code, Excalidraw).
The table now reports all four savings the change targets — cost, tokens,
time, tool calls — as the median of 4 runs per arm (Claude Opus 4.7,
headless claude -p, with vs empty MCP config). Averages across the 7 repos:
35% cheaper, 59% fewer tokens, 49% faster, 70% fewer tool calls. Adds a
methodology note and raw WITH->WITHOUT medians.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both git fast-paths in ExtractionOrchestrator (sync and getChangedFiles)
classified every untracked (`??`) file as "added" without checking the
index. Indexing a file doesn't make git track it, so the file stayed `??`
and was re-reported as pending and re-indexed on every run: `codegraph
status` listed it under Pending Changes forever and each `sync` re-added
it, even though its symbols were already queryable.
Merge the modified + added handling into a single hash-compared loop so
untracked files get the same treatment as tracked ones: "added" only if
missing from the index, "modified" if contents changed, skipped otherwise.
The non-git fallback path already did this and is unchanged.
Closes#206. Reported by @15290391025.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`codegraph init -i` from a git super-repo containing independent nested
git repositories (not submodules) reported "No files found to index":
git ls-files reports an embedded repo only as an opaque `subdir/` entry
and never lists its files. Detect embedded repos via that trailing-slash
signal and recurse `git ls-files` into each, indexing tracked + untracked
source and honoring each repo's own .gitignore.
Reported by @timxx.
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>
Renames the `.claude/skills/audit/` directory and all internal references to `agent-eval`, aligning the skill name with the `/agent-eval` command it invokes.
MCP tools failed with "CodeGraph not initialized" when a client launched
the server outside the project and sent no rootUri/workspaceFolders — the
server fell back to its own cwd, missed the project's .codegraph/, and
returned a misleading "run codegraph init" error on every call. The only
workaround was passing projectPath by hand to each tool.
When no explicit path is given, the server now asks the client for its
workspace root via the standard MCP roots/list request (gated on the
client advertising the roots capability) before falling back to cwd. This
required teaching the stdio transport to send server->client requests and
match their responses by id (previously responses were dropped as invalid).
When a project still can't be resolved, the error now names the directory
it searched and tells the user to pass projectPath or add --path to the
MCP config, instead of pointing at a re-init they don't need.
Reported-by: @zhangyu1197
Closes#196
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Recursive fs.watch on a WSL2 /mnt NTFS/9p mount walks the directory tree
with every readdir/stat crossing the Windows boundary, stalling the event
loop long enough to blow past opencode's 30s MCP handshake timeout so the
tools never appear. This is the file-watcher half of the #172 fix, which
moved the DB/WASM open off the handshake but left the watcher on the
critical path.
- Add watchDisabledReason() policy: CODEGRAPH_NO_WATCH (off) >
CODEGRAPH_FORCE_WATCH (force on) > WSL2 + /mnt auto-detect (off).
FileWatcher.start() and the MCP server both honor it; the server now
logs why watching is off and how to refresh.
- Add `codegraph serve --mcp --no-watch`.
- When watching is off, init/install offer git sync hooks (post-commit,
post-merge, post-checkout) that run `codegraph sync` in the background,
or fall back to manual sync; either way the user is told the index
stays frozen until re-synced. uninit removes the hooks.
- Tests: watch-policy + git-hooks (idempotency, user-content preservation,
core.hooksPath).
Root-cause analysis and workaround by @mengfanbo123.
Closes#199
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Project-local installs wrote the MCP server to ./.claude.json, which Claude Code never reads — project-scoped servers must live in .mcp.json. The codegraph tools silently never loaded until users renamed the file by hand. Local installs now write ./.mcp.json and migrate any stale ./.claude.json entry on install and uninstall (siblings preserved). Global installs (~/.claude.json, user scope) were already correct.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the old interactive publish.js script with two Claude skills and
a full agent-evaluation harness:
- `.claude/skills/audit/` — `/audit` skill drives `scripts/agent-eval/audit.sh`
to benchmark retrieval quality (with vs. without codegraph) on a chosen
real-world repo from the new `corpus.json` (17 repos across 14 languages).
- `.claude/skills/publish/` — `/publish` skill orchestrates the full release
workflow (preflight → changelog → confirmation gate → bump/build → npm
publish → GitHub release), replacing `publish.js`.
- `scripts/agent-eval/` — headless (`run-agent.sh`, `run-all.sh`) and
interactive tmux (`itrun.sh`) harnesses with stream-json parsers
(`parse-run.mjs`, `parse-session.mjs`) that report tool calls, token
usage, and a VERDICT line summarising codegraph_explore vs. Read/Grep counts.
- `run-interactive-test.md` — documents the two harnesses, idle-detection
approach, and what "good" agent behavior looks like after explore-first
guidance.
* 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>
Output is now scaled to indexed file count. Small projects (<500 files)
cap at ~18KB and skip the "Additional relevant files" / completeness /
explore-budget reminders that earn their keep on larger codebases; medium
(<5,000) caps at ~28KB; large (<15,000) keeps the historical ~35KB; very
large goes up to ~38KB.
A per-file char cap also prevents a single file with many adjacent
symbols from collapsing into one whole-file dump (the pathological
Alamofire `Session.swift` case reported in #185), and a per-file symbol-
list cap stops the `#### path — sym(kind), ...` header from leaking
multi-KB lists when many adjacent symbols cluster together.
Measured against the README's benchmark repos: Alamofire (~100 files)
~62% smaller per call, Excalidraw (~600 files) ~35%, VS Code (~10k
files) ~14%. Agent-trust floor preserved — Relationships, scored cluster
selection, and structured-source output are all retained.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three fixes prompted by retroactively unwrapping the 0.7.6 / 0.7.7 /
0.7.9 release notes:
- Add `--stdin` mode so the extractor can clean up an existing release
body (via `gh release view ... --json body --jq '.body'`) without
needing a matching CHANGELOG.md entry. The 0.7.9 release didn't have
one — its body had been hand-rolled from the 0.7.8 entry on publish.
- Stop treating `+` as a bullet marker. CommonMark allows it, but our
CHANGELOG uses literal `+` inline (`MCP config + instructions`) and
the script was misreading those as nested bullets. Keep `-`, `*`,
and `N.` only.
- Preserve fenced code blocks verbatim. The 0.7.6 entry has a triple-
backtick ```bash block; the previous pass was joining its lines into
one, producing unreadable code.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitHub renders release-note Markdown with GFM hard breaks, so every
`\n` becomes `<br>`. The CHANGELOG is hard-wrapped at ~75 chars for
readable diffs, which renders as awkward visible line breaks on the
release page (see https://github.com/colbymchenry/codegraph/releases/tag/v0.7.10).
Add `scripts/extract-release-notes.mjs` to extract a version block
and join indented continuation lines into a single line per bullet.
Nested list items, headings, and link references are preserved.
`scripts/release.sh` now uses this helper instead of the inline awk
extractor — repo-level CHANGELOG.md viewing is unaffected because
CommonMark there treats newlines as spaces.
Also fix the 0.7.10 entry: "Two underlying fixes" -> "Three", "Rust
file-/level" broken hyphen, and move the closes/credit line above
the nested list so it doesn't strand as a top-level paragraph.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>