Skip to content

Commit 284c8e5

Browse files
anvansterclaude
andauthored
feat: fetch a per-platform engine and add a JetBrains IDE client (#17)
* feat(vscode): onboarding-funnel repair - zero-file recovery, first-index steer, walkthrough Telemetry (30d, ~2,540 active machines) showed two large leaks: ~445 machines produced a zero-file index and 84% never returned, and of ~2,394 that activate cleanly only ~20% ever open a visible surface. This addresses both. - funnel.ts: diagnose why an index came back empty (no folder / no supported languages / indexPaths misconfig / all excluded / server gap) and offer the one recovery that fixes that cause, replacing the dead-end "Indexed 0 files" toast. Diagnosis scopes to indexPaths when set so the misconfig case is actually reachable. Notifications are fire-and-forget so an agent-driven index never hangs awaiting a dialog it can't answer. - First successful index shows a one-time (globalState-gated) steer to the surfaces telemetry shows convert best (Symbols tree, Call Graph). - codegraphSymbols empty state: actionable "Index Workspace / Open Walkthrough" welcome gated on a new codegraph.indexed context key (was a blank panel). - Getting-started walkthrough (index -> explore -> call graph -> AI assistant) plus a codegraph.openWalkthrough command. - New funnel.* telemetry (zeroFileIndex, zeroFileCta, firstIndexCta) with bounded enums; the command-palette reindex now also emits index.completed (it previously emitted none). - Shared filesIndexed()/reportIndexTelemetry() helpers remove the response coercion + telemetry mapping duplicated across 5 sites. - 12 unit tests for the diagnosis and glob logic (inline vscode mock; the legacy vsforge suites remain quarantined). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(vscode): Phase 1 human surfaces - activity bar, CodeLens, hover Telemetry showed humans engage visible surfaces (tree views: 483 machines, call graph: 116) far more than agent tools (238), yet those surfaces were buried in the Explorer and there was nothing inline in the editor. This adds first-class discoverable surfaces. Activity bar: - Dedicated CodeGraph activity-bar container with an SVG icon; the Symbols and Memories tree views move out of the Explorer into it (registration is by view id, unchanged). Server: - New batched LSP request codegraph/getDocumentCodeLens(uri): per function/ method, returns caller count, related-test count, and cyclomatic complexity in one pass, so the editor issues one request per document instead of N. - Caller/test counting filters to EdgeType::Calls (mirrors helpers::get_callers) so structural Contains edges don't inflate counts; test-vs-production split uses a new shared node_props::is_test_like(), which the PR-review path now also calls so the two can't diverge. Editor: - CodeLens above every function ("N callers · M tests · complexity X"), click reveals the symbol and opens its call graph; matching hover with the same stats. Backed by one version-cached request per document, evicted on close and invalidated on reindex. Registered for all on-disk files (server returns empty for unindexed files, so no language list to drift). - codegraph.codeLens.enabled / codegraph.hover.enabled toggles (default on), in the settings snapshot; engagement.codeLensClicked telemetry. Tests: 2 net-new server tests (counts incl. a Contains-edge regression guard, invalid-uri error); extension tsc + 12 vitest green. Verified via workflow code-review (6 findings, all fixed). Note: the bundled platform binaries need a cross-platform rebuild before CodeLens works end-to-end in a shipped extension. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(vscode): wire getDocumentCodeLens to the live executeCommand dispatch The Phase 1 CodeLens endpoint was registered only in handle_custom_request (the `codegraph/*` slash-method dispatcher), which is dead code: the LSP service is built with `LspService::new` and never registers those custom methods, so slash requests return -32601. The live custom-request path is `workspace/executeCommand` matching `codegraph.*` dot-commands in backend.rs::execute_command. As shipped, codegraph/getDocumentCodeLens would have 404'd in the real extension - the unit test passed only because it calls the handler directly, and the code review didn't exercise the runtime dispatch. Building the vsix and probing the running server surfaced it. - backend.rs: add the live `codegraph.getDocumentCodeLens` arm (mirrors getWorkspaceSymbols), and drop the dead slash registration from custom_requests.rs. - codeLensProvider.ts: call via workspace/executeCommand instead of the unregistered slash RequestType. - navigation.rs: skip test functions via is_test_like (structural marker + name/path heuristic) so languages without a structural test marker (Python test_*) don't get a noise lens, matching caller classification. Verified end-to-end against a real indexed workspace: do_work -> 1 caller, 1 test, complexity 2; test functions suppressed. 11 navigation tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(vscode): Symbols tree view uses live executeCommand dispatch The Symbols pane was empty on indexed workspaces: SymbolTreeProvider sent `codegraph/getWorkspaceSymbols` via the slash RequestType, which routes to the dead handle_custom_request (unregistered on the LSP service) and returns method-not-found, so the provider caught the error and rendered nothing. Same root cause as the CodeLens dispatch fix. Switch to workspace/executeCommand with the live `codegraph.getWorkspaceSymbols` dot-command (already handled in backend.rs::execute_command). Verified: returns symbols on an indexed workspace. Memories provider already used executeCommand and was unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(npm): make the memory/macOS embedding note a discoverable Troubleshooting section The CODEGRAPH_SKIP_MEMORY_CHECK / 0-MB-detection-failure guidance (added with the #13 fix) was unlabeled prose after the Options table, so a user hitting 'embeddings disabled on my Mac' wouldn't find it by scanning headings. Give it a Troubleshooting heading and tighten the wording. Docs only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(jetbrains): add JetBrains IDE plugin as a thin LSP client All analysis stays in codegraph-server. The plugin spawns it, speaks LSP over stdio via LSP4IJ, and renders the results - so this is a client shell, not a second implementation. LSP4IJ rather than the platform's own LSP API: the latter is limited to the paid IDEs, which would exclude IDEA CE, PyCharm CE and Android Studio. LSP4IJ is Apache-2.0 and exposes the underlying LSP4J server, so dropping to raw LSP4J stays available if that dependency ever becomes a problem. Surfaces: Code Vision (callers/tests/complexity above declarations), a Symbols tool window, dependency and call graph panels on JCEF with a text fallback, a status bar widget, settings, and the indexing prompt/reindex flow. Engine binaries are not bundled. The Marketplace ships one artifact for every platform, so bundling all four would mean a ~120 MB download for every user to get the ~30 MB they can use. The engine is resolved from an existing install instead; a downloader was written and removed because the per-platform release assets it would fetch do not exist yet. Two verification harnesses, because neither covers the other: - scripts/engine_probe.py replays the plugin's exact wire traffic with no IDE, and diffs the command enum and settings defaults against the engine and the VS Code client so those hand-written files cannot drift silently. - SelfCheckActivity (inert without -Dcodegraph.selfcheck=true) answers what only a running IDE can: JCEF availability, tool window instantiation. Notable fixes found while building this: - getWorkspaceSymbols must omit `query` entirely for the unfiltered view; an empty string takes the engine's modules-only branch and yields an empty tree on a healthy index. Verified against an indexed workspace: 0 vs 7 symbols. - indexOnStartup defaults to false, matching VS Code and the engine. Defaulting it to true raced the index prompt and indexed the workspace twice. - The pre-index grace period now waits for the engine to finish `initialize` rather than for the non-blocking start() call, which provided no grace at all. - Startup activity returns early in headless environments, where there is no user to prompt - this also stops searchable-options generation from hanging. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * feat(jetbrains): add Memories tool window Second tab on the existing CodeGraph tool window rather than its own sidebar slot: memories are the same graph seen from a different angle, and two CodeGraph icons would be two things to learn. Lists via codegraph.memoryList and switches to codegraph.memorySearch once a query is typed, since those are different commands with different response shapes. Both take currentOnly, so invalidated entries are filtered by the engine rather than re-filtered client-side. Invalidated memories render greyed rather than hidden when shown - silently drawing them as current would be worse than showing they exist. Verified against a seeded store: memoryList returns the entries, the tool window reports two tabs, and no exceptions reach the log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * feat(jetbrains): register the engine with AI tooling over MCP The VS Code client declares 28 languageModelTools. Those are Copilot-specific, and porting them would mean a second hand-written tool list drifting against the engine. Pointing the AI tooling at the engine's own MCP mode instead keeps the tool surface correct for free - verified end to end, the registered command answers an MCP initialize and lists 42 tools. Writes <project>/.mcp.json in the mcpServers shape that Junie, Claude Code, Cursor and the AI Assistant MCP settings all read, and offers the same config on the clipboard, since every AI client stores MCP configuration somewhere different and pasting always works. Merges rather than overwrites: a project may already point at other MCP servers, and silently dropping them to add ourselves would be a hostile way to install a feature. Tests cover that case specifically - it is the failure that is invisible until some unrelated AI tool stops working. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * feat(jetbrains): telemetry parity, marketplace metadata, startup race fix Telemetry sends the same event and property names as the VS Code client so both editors land in one funnel, adding only ide/ideProduct/ideBuild so a dashboard can split by editor without a second schema. The gate is a pure function with its own tests. A mistake there means measuring someone who declined, which nothing downstream can detect or undo, so every refusal path is asserted individually rather than trusting one happy path. The IDE's own statistics consent is a hard gate the plugin setting can narrow but never widen, and a build with no compiled-in key cannot send at all - so builds from source and forks are silent with no setting to remember. Unknown values are dropped rather than sent as "unknown": a placeholder string looks like a real value in a dashboard and inflates whatever bucket it lands in. Also fixes a pre-existing startup race, found by a self-check run that failed where earlier runs had passed. start() is asynchronous, so a command issued straight after it could get a null server back and fail fast. That is "not up yet", not "cannot run" - and it fails the first command of a session, which is the one a user is most likely to notice, such as a reindex they just asked for. The plugin configuration verifier caught Kotlin apiVersion set to 2.1 while since-build 243 only guarantees 2.0; the mismatch would surface as a NoSuchMethodError on a 2024.3 user's machine rather than at build time. Verifier IDE selection narrowed from recommended() to the development platform: each recommended release is a ~3 GB download, which is a lot of someone else's disk to consume by default. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * fix(jetbrains): drop internal API and deprecated class flagged by the verifier The plugin verifier now runs against both ends of the supported range and reports Compatible for IC-243 and IC-252. Getting there required two real fixes. Telemetry no longer consults StatisticsUploadAssistant.isSendAllowed(). That is @ApiStatus.Internal - not an API plugins may call, and one that can change without notice. There is no public equivalent, because the platform does not offer third-party plugins a statistics-consent signal to honour at all. So the setting is now opt-in rather than default-on. The VS Code client can default to on because VS Code exposes env.isTelemetryEnabled, a platform consent it honours; with no such signal here, defaulting to on would mean collecting from people who never agreed to anything. The marketplace disclosure and the gate's own documentation say so plainly. ToggleActionButton is deprecated and scheduled for removal, which matters more than usual because until-build is unbounded - a removal would break the Memories toolbar on IDEs this plugin claims to support. Replaced with ToggleAction. Verifier IDE selection is current() + latest{} rather than pinned versions: a pinned "newest" stops being newest without anyone noticing, which is exactly the break it exists to catch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * fix(server): unblock non-VS-Code clients and stop discarding store errors Three fixes found by building a second editor client against this engine. Embedding settings are no longer gated on `extensionPath`. They sat inside `if let Some(extension_path)`, which made a VS Code-specific option the gate for two unrelated settings: any client that omitted it silently lost its embedding model choice and fell back to signature-only embeddings, degrading duplicate detection, clustering and similarity search with nothing in the log to say why. The path itself is optional and only ever meant "a directory the client owns", so it is now logged rather than load-bearing. Verified: initialize without extensionPath now honours granite-97m and fullBodyEmbedding, where before it logged CRITICAL and used the defaults. `codegraph.getDocumentCodeLens` is now advertised in executeCommandProvider. It was dispatched but unadvertised; VS Code never noticed because it uses the custom-request form, but a client that gates on ServerCapabilities - LSP4IJ's supportsCommand does - would treat the whole inline-CodeLens surface as unsupported. Checked for the collision the neighbouring comment warns about: no VS Code command is registered under that id. Advertised count 35 -> 36. memoryStore no longer maps its failure through `.map_err(|_| internal_error())`. That discarded the cause and logged nothing, so a store failure was unactionable from a user report - and it led me to a wrong diagnosis that took five probes to characterise and was still wrong. It now logs and returns the reason. 361 server tests pass; the JetBrains contract probe passes against the rebuilt engine. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * style(server): apply rustfmt to two files that had drifted Pre-existing `cargo fmt --check` violations in navigation.rs and parser_registry.rs, neither touched by the preceding fix. Separated from that commit so the functional change stays readable; this one is pure reflow and changes no behaviour. 361 tests still pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * fix(server): sweep crash breadcrumbs left by killed processes Measured before the fix: 312 last-phase.<pid>.json files in ~/.codegraph, the oldest two months old. After: 4, all belonging to live processes. clear() only removes the current process's marker, and main.rs calls it after the LSP serve loop returns - which does not happen when a client force-kills the engine, as both clients do. Every killed process therefore leaked its marker permanently. The disk cost is trivial. The real cost is that stale markers make the clients' 15-second freshness window the only thing standing between a two-month-old marker and a wrong crash diagnosis today. The sweep requires two conditions, so it can never destroy a live diagnosis: the marker is older than an hour, AND its process is gone. Age alone would delete the marker of a long-running engine that later crashes hard; liveness alone would race a client that has not yet read a fresh crash. Verified in practice - one marker survived the first pass because its pid was still alive, and was swept on the next once it had exited. last-recovery markers are deliberately excluded: they are reported once with no freshness window, so an old one still matters to a client that has not read it. sweep_orphans_in() takes the directory so the policy is testable without setting HOME, which is process-global and would race other tests in this binary. Six tests cover both refusal paths, the exclusion, and non-marker files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * fix(server): terminate on the LSP `exit` notification Measured before: shutdown answered in 0.00s, process still alive 120s after exit, terminated only when stdin closed. After: exits 2.05s after exit, rc=0. I had originally written this off as an upstream limitation not worth working around. That was wrong on the risk analysis: both clients already SIGKILL the engine at exactly this point, so returning from main a moment after `shutdown` is *gentler* than the status quo, not riskier. It also covers the case no client handles - anything holding the pipe open after `exit`, where the engine would linger holding an entire graph in memory. Two causes, one behind the other. tower-lsp 0.20 dispatches `exit` through service.call(), which flips the state to Exited but does not break the read loop; the loop only notices via poll_ready when the *next* message arrives. So `shutdown` now signals a waiter that main races against serve(). That alone was not enough: with the select resolving, the process still hung. tokio::io::stdin() reads on a blocking-pool thread that cannot be cancelled, and dropping the runtime waits for blocking tasks - the very read we are trying not to wait for. The request path now exits explicitly after clearing its crash breadcrumb. Also fixes the probe that produced the original diagnosis. It sent `"params": {}` on shutdown, which tower-lsp rejects with -32602 "Unexpected params" - a reply that looks like success to anything checking only for a response, while the server's shutdown handler never runs. The probe now omits params and asserts both the shutdown result and prompt termination, instead of printing a note about a known deviation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * fix(server): initialize the workspace from rootUri when workspaceFolders is absent `workspaceFolders` is optional in LSP - a client may legally send only `rootUri`, or the deprecated `rootPath`, and several do. The engine read only the first, so those clients got a server whose memory subsystem never initialised: every memory command failed for the entire session while indexing and search kept working normally. A half-broken server is worse than an obviously broken one, because nothing points at the cause. Measured against a cold ~/.codegraph, first-ever memoryStore: rootUri only, before: fails, and keeps failing - "Memory manager not initialized" on every subsequent call too rootUri only, after: succeeds in 13.4s (cold embedding model load) workspaceFolders: unchanged This is what the earlier "architectural_decision is broken" report actually was. That diagnosis was wrong twice over - not kind-specific, and not a cold embedding model either. The real cause only became visible once memoryStore stopped discarding its error, which is the second time that discarded error sent an investigation down the wrong path. An empty `workspaceFolders` list is treated as absent rather than as "no workspace", so a client sending [] alongside a usable rootUri still works. The selection is extracted into workspace_paths_from() so all six cases are tested without standing up a backend. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * feat: publish engine binaries as release assets, and download them Adds scripts/publish-release-assets.sh and restores the JetBrains engine downloader it unblocks. The script uploads what the existing cross-platform build already produces in vscode/bin/, under tag v<version> read from Cargo.toml, each asset beside a .sha256. It builds nothing and changes nothing about how binaries are made - it slots in after the manual per-host build. Staging is the default; --publish is required to upload, matching package-npm.sh. It refuses to publish a partial set. A client that resolves its own platform and finds nothing has no way to distinguish "not built yet" from "never supported", so half a release is worse than none. The downloader fetches only the platform it needs - roughly 30 MB against the 498 MB unpacked npm package that is the alternative for users without Node - and verifies every file against its published checksum before installing. An engine runs with the user's permissions; TLS says nothing about a mirror, a proxy or a truncated transfer. Two things the first attempt at this got wrong, both now covered by tests: Windows needs onnxruntime.dll alongside the executable. Fetching only the exe gives a download that succeeds and then fails at startup - package-npm.sh warns about precisely this. The sidecar is part of the install, and a checksum failure on it leaves nothing behind. The URL scheme now matches the convention already in use: the npm postinstall fetches its model from releases/download/<tag>/, and the repository name casing is load-bearing. The download is offered, never automatic. Pulling a native binary unasked on project open is not a decision the plugin should make. Verified end to end against a real release tree served over loopback: the script's checksum format is exactly what the downloader parses, and a 116 MB binary verifies against it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * feat: fetch the engine per platform instead of bundling it everywhere, 0.20.0 Every channel used to carry all four platform binaries so that each user could run exactly one of them. The binaries are now published once as release assets and each channel fetches only what it needs. npm package 88 MB compressed / 498 MB unpacked -> 16 kB / 50.7 kB VSIX 118 MB (plus four targeted variants) -> 554 kB, one artifact JetBrains already fetched; unchanged mcp-package/bin/fetch-engine.js is the single implementation of the download contract - URL layout, checksum format, the Windows sidecar rule - for both JavaScript channels. The VS Code extension does not reimplement it: esbuild follows the relative path and inlines the same file into out/extension.js, verified by checking the bundle rather than assuming. The JetBrains plugin implements the same contract in Kotlin against the same assets. Where each channel fetches: npm postinstall, into <pkg>/bin/ - the path is unchanged because consumers resolve it directly, codegraph-pr.yml among them VSIX first activation, into ~/.codegraph/bin, since a VSIX has no install hook. server.ts now looks there too, so an engine installed through any channel is found by all of them. Both offer rather than assume. Pulling a native binary that runs with the user's permissions, unasked, is not a decision these clients should make. Escape hatches for air-gapped installs: CODEGRAPH_SKIP_BINARY_FETCH, a pre-placed binary, codegraph.serverPath, or npx codegraph-mcp-fetch-engine to retry. A failed fetch never fails `npm install` - rolling back a package whose CLI, hooks and docs all work would be the wrong trade. Version 0.20.0 rather than a patch: 0.19.1 is published, this adds a distribution channel and changes how every install obtains its engine. Note on coverage: vscode/src/server.ts and extension.ts changes are compile-checked only. Those suites are quarantined because the vsforge test harness they import is permanently lost - a pre-existing condition, not introduced here. The download logic itself is covered by 12 checks in mcp-package/test and 6 in the JetBrains suite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * no-mistakes(review): fix engine platform/version handling and JetBrains plugin defects * no-mistakes(review): fix engine update safety, platform mapping, and graph panel defects * no-mistakes(review): pin engine version per channel and fix CodeLens test classification * fix(release): verify binary provenance, not just presence publish-release-assets.sh checked that each binary existed. vscode/bin/ is a staging directory that is not cleaned between releases, so a binary from an earlier version sits there looking exactly as valid as a fresh one - and it would have been published under the new tag with perfectly correct checksums for the wrong build. Caught in practice: the 0.19.1 Windows engine was still staged while preparing 0.20.0. The first attempt scraped version strings out of the binaries and reported all three good ones as stale, because the engine does not store its version as a standalone string on every target. A check that blocks legitimate releases is worse than no check. So provenance is recorded where it is knowable instead of guessed afterwards: stamp-binary.sh records what produced each binary, on the host that could actually run --version, and publishing refuses anything not stamped for the version being released. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * no-mistakes(review): address review findings across engine download and IDE clients * no-mistakes(review): filter PR-review callers to Calls edges, add troubleshooting doc, fix postinstall asset guard and CodeLens noise * no-mistakes(document): update docs for fetched engine and JetBrains plugin * no-mistakes(document): align tool/language counts and unbundled static model docs * no-mistakes(document): align VS Code static model setting docs with unbundled reality * fix(mcp): stop the crash loop caused by a duplicated --mcp flag 656,283 mcp.crash events from ~134 machines in 30 days - 63% of all telemetry volume - traced to one argument collision. The wrapper always prepends --mcp. Every doc and example also shows --mcp, so a user who put it in their MCP client config got it twice, and clap rejects that with "the argument '--mcp' cannot be used multiple times" and exits 2. The exit happens before McpServer::run(), which is where mcp.start is emitted, so the engine never reported itself; the client respawned into the identical failure and looped. Deterministic, cross-platform, and invisible: the user just sees a tool that does not work. Reproduced against the 0.20.0 engine, and the previously-looping invocation (`codegraph-mcp --mcp`) now starts the server normally. Flags the wrapper owns are filtered out of the client's arguments rather than forwarded, so agreeing with the wrapper about the mode is harmless. Three further changes, each aimed at a way this stayed hidden: - exit 2 now prints what was rejected, including the assembled argument list, and says it is a configuration problem rather than a crash. The arguments are not visible to the user anywhere else. - A crash-loop breaker stops reporting after three identical failures in a minute, matching the VS Code extension and the JetBrains plugin. Those count in memory; this cannot, because an MCP client respawns a fresh process each time, so the count lives in ~/.codegraph/mcp-failures.json keyed by the arguments. One machine sent 504,256 events for want of this. - mcp.crash now carries the version. Only mcp.start did, and mcp.start is by definition absent for a failure before startup - so the case most needing attribution to a release was the one that could not be attributed. Also makes CODEGRAPH_SERVER_PATH work. findBinary() only ever looked in __dirname, while the postinstall told users to set that variable when a download fails or the machine is air-gapped. The advice pointed at something that did nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * fix(clients): stop pointing CODEGRAPH_STATIC_MODEL at a directory that no longer ships Excluding `bin/**` from the VSIX removed the four bundled engines, which was the intent - but jina-code-static-256 lived in that directory too. The extension still set CODEGRAPH_STATIC_MODEL to <extensionPath>/bin/jina-code-static-256, so anyone selecting the static embedding model without naming their own path got an override pointing at nothing. Both clients now set the variable only when the user names a directory. Left unset, the engine resolves ~/.codegraph/static_models/jina-code-static-256 itself (embedding/mod.rs::default_static_model_dir) - which is exactly where the npm postinstall downloads it, and is shared across every client. Overriding a correct default with a path that does not exist is strictly worse than not overriding. The JetBrains client had the same shape and its own copy of that fallback path. The copy is deleted rather than fixed: a second statement of the same rule is free to drift from the engine's, and this is the third time in this branch that a duplicated rule has been the bug. Found by the no-mistakes document phase, which correctly declined to fix it - it is a runtime behaviour change, outside that phase's scope - and documented the behaviour instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013iTPP3eSpGSgWN6c5w4Fm1 * no-mistakes(review): harden release scripts, isolate wrapper test, unblock EDT dispose * no-mistakes(test): add regression guard for static model spawn env * no-mistakes(document): align static-model, engine-path and profile docs with code --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 06bcc88 commit 284c8e5

105 files changed

Lines changed: 11192 additions & 546 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ members = [
6060
]
6161

6262
[workspace.package]
63-
version = "0.19.1"
63+
version = "0.20.0"
6464
edition = "2021"
6565
license = "Apache-2.0"
6666
repository = "https://github.com/codegraph-ai/codegraph"

README.md

Lines changed: 55 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE)
66

7-
CodeGraph builds a semantic graph of your codebase — functions, classes, imports, call chains — and exposes it through **45 MCP tools**, a **VS Code extension**, and a **persistent memory layer**. Parses **37 languages** via tree-sitter. AI agents get structured code understanding instead of grepping through files.
7+
CodeGraph builds a semantic graph of your codebase — functions, classes, imports, call chains — and exposes it through **42 MCP tools**, a **VS Code extension**, a **JetBrains IDE plugin**, and a **persistent memory layer**. Parses **38 languages** via tree-sitter. AI agents get structured code understanding instead of grepping through files.
88

99
## Quick Start
1010

@@ -30,10 +30,26 @@ The server indexes the current working directory automatically.
3030
Install the VSIX:
3131

3232
```bash
33-
code --install-extension codegraph-0.14.0.vsix
33+
code --install-extension codegraph-0.20.0.vsix
3434
```
3535

36-
The extension starts the server automatically and registers all tools as Language Model Tools for Copilot.
36+
One VSIX serves every platform.
37+
The analysis engine is not bundled: on first activation the extension offers to download the engine built for your platform, verifies it against the published checksum, and installs it into `~/.codegraph/bin` - the same location the JetBrains plugin uses, so one download serves both.
38+
The download is offered rather than performed automatically, because it is a native binary that runs with your permissions.
39+
Decline it and run **CodeGraph: Download Analysis Engine** from the command palette whenever you are ready.
40+
41+
Once an engine is present, the extension starts it automatically and registers all tools as Language Model Tools for Copilot.
42+
43+
### JetBrains IDEs
44+
45+
A plugin for IntelliJ IDEA, PyCharm, GoLand, Android Studio and the rest of the
46+
family drives the same engine over LSP: Code Vision, Symbols and Memories tool
47+
windows, a graph panel, and one-click MCP registration for the AI Assistant.
48+
It resolves or downloads the engine the same way the VS Code extension does,
49+
sharing `~/.codegraph/bin`.
50+
51+
**[jetbrains/README.md](jetbrains/README.md)** for surfaces, engine
52+
resolution order, and building from source.
3753

3854
### Rules for AI agents
3955

@@ -89,16 +105,23 @@ one tool and exits without the MCP stdio handshake — ideal for scripting.
89105
Static (model2vec) embeddings replace the ONNX transformer with a token→vector
90106
lookup table: indexing is **~100× faster** (this repo's 5,873 symbols embed in
91107
~1 s vs ~3.4 min with BGE) and there's **no ONNX runtime or 1.5 GB RAM gate**.
92-
Retrieval stays **hybrid (BM25 + semantic)**, so end-to-end quality is **~90% of
93-
BGE**. The VS Code extension ships the model bundled, so `static` works there
94-
with no setup. For the CLI/MCP server it needs a local model directory
95-
(`config.json` + `tokenizer.json` + `model.safetensors`):
96-
97-
- Point at it with `CODEGRAPH_STATIC_MODEL=/path/to/model` (or the VS Code
98-
`codegraph.staticModelPath` setting to override the bundled model). Default:
99-
`~/.codegraph/static_models/jina-code-static-256`.
100-
- Distill one from any sentence-transformer (Apache-2.0 Jina-Code by default) in
101-
~30 s on CPU: `python scripts/distill_static_model.py`.
108+
Retrieval stays **hybrid (BM25 + semantic)**, so end-to-end quality is **~90% of BGE**.
109+
The model is not bundled with any client — it needs a local model directory
110+
(`config.json` + `tokenizer.json` + `model.safetensors`) at
111+
`~/.codegraph/static_models/jina-code-static-256`, or wherever
112+
`CODEGRAPH_STATIC_MODEL` points:
113+
114+
- Installing `@astudioplus/codegraph-mcp` from npm downloads it into that
115+
default location for you (best-effort; set `CODEGRAPH_SKIP_MODEL_FETCH=1` to
116+
skip, and the install never fails over it).
117+
- Otherwise fetch the prebuilt one with `scripts/fetch-static-model.sh`, or
118+
distill your own from any sentence-transformer (Apache-2.0 Jina-Code by
119+
default) in ~30 s on CPU: `python scripts/distill_static_model.py`.
120+
- A model in the default location needs no IDE setting: both IDE clients leave
121+
`CODEGRAPH_STATIC_MODEL` unset and let the engine resolve it. To use a model
122+
kept somewhere else, set `codegraph.staticModelPath` in VS Code, or
123+
*Settings → Tools → CodeGraph → Embeddings → Static model directory* in
124+
JetBrains; each client then passes that path as `CODEGRAPH_STATIC_MODEL`.
102125

103126
#### `CODEGRAPH_SKIP_MEMORY_CHECK` — force the embedding model past the RAM gate
104127

@@ -117,29 +140,22 @@ It works in both MCP and one-shot `--run-tool` modes.
117140

118141
#### `--profile` — narrow the MCP tool surface
119142

120-
The full 32-tool surface is convenient but inflates the agent's prompt-context cost. A profile exposes only the slice you need (also settable via the `CODEGRAPH_TOOL_PROFILE` env var):
143+
The full 42-tool surface is convenient but inflates the agent's prompt-context cost. A profile exposes only the slice you need (also settable via the `CODEGRAPH_TOOL_PROFILE` env var):
121144

122145
| Profile | Tools | Use when |
123146
|---------|-------|----------|
124147
| `all` *(default)* | every tool (community + pro) | normal sessions |
125148
| `core` | 8 — search + symbol info + AI context | chatty agent sessions where you only need lookups |
126-
| `graph` | 16 — callers/callees/deps/impact/traverse | refactoring + structural analysis |
127-
| `memory` | 7`codegraph_memory_*` only | note-taking / knowledge-base workflows |
149+
| `graph` | 17 — callers/callees/deps/impact/traverse/PR context | refactoring + structural analysis |
150+
| `memory` | 14`codegraph_memory_*` plus the docs tools | note-taking / knowledge-base workflows |
128151
| `security` | pro security tools only (empty on community) | pro security audits |
129152

130153
### VS Code settings
131154

132-
```jsonc
133-
{
134-
"codegraph.indexOnStartup": true,
135-
"codegraph.indexPaths": ["/path/to/project-a", "/path/to/project-b"],
136-
"codegraph.excludePatterns": ["**/cmake-build-debug/**", "**/generated/**"],
137-
"codegraph.embeddingModel": "bge-small", // or "static" for ~100× faster indexing
138-
"codegraph.staticModelPath": "", // model2vec model dir when embeddingModel is "static"
139-
"codegraph.maxFileSizeKB": 1024,
140-
"codegraph.debug": false
141-
}
142-
```
155+
The `codegraph.*` settings are documented once, next to the extension that
156+
reads them:
157+
158+
**[vscode/README.md — Configuration](vscode/README.md#configuration)**
143159

144160
Full-body embeddings are enabled by default. Function body text is captured at parse time with zero I/O overhead.
145161

@@ -151,9 +167,14 @@ Built-in exclusions (always skipped) cover ~47 directories across three categori
151167

152168
Plus glob patterns for binary archives, native libraries, OS metadata, and **secret file extensions** (`*.pem`, `*.key`, `*.p12`, `*.pfx`, `*.crt`, `*.gpg`, `*.kdbx`, SSH key conventions like `id_rsa`, etc.) — defense in depth against accidentally embedding credentials.
153169

170+
Indexing produced zero files, or something else looks wrong? See
171+
**[docs/troubleshooting.md](docs/troubleshooting.md)**.
172+
154173
---
155174

156-
## Tools (42 community + 27 pro, 17 security)
175+
## Tools
176+
177+
42 community tools, plus 27 more (17 of them security analyzers) in CodeGraph Pro.
157178

158179
### Code Analysis (11)
159180

@@ -339,7 +360,7 @@ Additional tools available in [CodeGraph Pro](https://codegraph.astudioplus.com/
339360
| **Functional** | Haskell, OCaml, Julia, Erlang, Elm, Clojure |
340361
| **Enterprise** | C#, COBOL, Fortran, Go |
341362
| **Blockchain** | Solidity |
342-
| **Shell/Config** | Bash, HCL/Terraform, TOML, YAML |
363+
| **Shell/Config** | Bash, Dockerfile, HCL/Terraform, TOML, YAML |
343364
| **Hardware** | Verilog/SystemVerilog, Tcl |
344365
| **Data Science** | R, Julia |
345366

@@ -356,11 +377,11 @@ HTTP handler detection: Python (FastAPI/Flask/Django), TypeScript (NestJS), Java
356377
## Architecture
357378

358379
```
359-
MCP Client (Claude, Cursor, ...) VS Code Extension
360-
| |
361-
MCP (stdio) LSP Protocol
362-
| |
363-
└───────────┐ ┌───────────┘
380+
MCP Client (Claude, Cursor, ...) VS Code Extension JetBrains Plugin
381+
| | |
382+
MCP (stdio) LSP Protocol LSP Protocol
383+
| | |
384+
└───────────┐ ┌──────┴──────────────────┘
364385
▼ ▼
365386
┌─────────────────────────────┐
366387
│ codegraph-server │

0 commit comments

Comments
 (0)