Skip to content

feat: fetch a per-platform engine and add a JetBrains IDE client - #17

Merged
anvanster merged 31 commits into
mainfrom
release/0.20.0
Aug 9, 2026
Merged

feat: fetch a per-platform engine and add a JetBrains IDE client#17
anvanster merged 31 commits into
mainfrom
release/0.20.0

Conversation

@anvanster

Copy link
Copy Markdown
Member

Intent

The developer was driving CodeGraph 0.20.0 to release: a new JetBrains plugin plus a distribution change where all three clients (npm, VS Code, JetBrains) fetch a single per-platform engine from a GitHub release instead of bundling four binaries. Before rebuilding and publishing, they explicitly asked to fix two outstanding bugs found earlier: task #14, where adding bin/** to .vscodeignore dropped the static embedding model so CODEGRAPH_STATIC_MODEL pointed at a path that no longer ships, and task #15, an MCP crash loop where unknown or duplicated arguments made the engine exit 2 via clap before emitting telemetry, causing MCP clients to respawn forever (656k PostHog events from ~134 machines). They then instructed running the work through the no-mistakes gate and pushing to GitHub, noting the gh login had been switched to anvanster so publishing was unblocked, followed by a fresh rebuild of all four platform binaries to include the crash fixes. Standing constraints from their global instructions applied throughout: push only through the no-mistakes gate rather than directly to origin, never hand-edit auto-generated files like CHANGELOG.md, and no commits or pushes without an explicit request.

What Changed

  • Engine distribution moved from bundling four platform binaries in every client to fetching one per-platform binary from a GitHub release: new fetch-engine download/verify path in the npm wrapper, engineDownload.ts in the VS Code extension, and EngineDownloader/EngineInstaller/CodeGraphServerResolver in the new JetBrains plugin, with publish-release-assets.sh and stamp-binary.sh publishing and provenance-stamping the assets and each client pinning the engine version per channel. Workspace version bumped to 0.20.0.
  • Added a JetBrains IDE plugin (jetbrains/) as a thin LSP client - Symbols and Memories tool windows, graph panel, code vision, status bar widget, MCP registration for AI tooling, telemetry gate/reporter, crash breadcrumbs and a restart circuit breaker - and extended the VS Code extension with an activity bar view, CodeLens, hover, onboarding walkthrough and zero-file/first-index funnel recovery.
  • Fixed the MCP crash loop where the wrapper passed a duplicate --mcp flag and the engine exited 2 through clap before reporting: the wrapper now de-duplicates its own flags, explains exit 2, and trips a persistent crash-loop breaker; CODEGRAPH_STATIC_MODEL is no longer pointed at the unbundled bin/ directory. Engine-side, the server now terminates on the LSP exit notification, initializes the workspace from rootUri/rootPath when workspaceFolders is absent, sweeps stale crash breadcrumbs, and stops discarding store errors.

Risk Assessment

⚠️ Medium: Every round-1 finding is correctly resolved and I found no new defects, but the branch remains a ~11k-line distribution rewrite whose principal failure mode — release assets that are unpublished, mistagged or stale — lives outside the diff and is guarded only by the (now-hardened) publish script's pin and manifest checks.

Testing

I exercised both bugs the release was blocked on at the surface an end user actually touches. For the MCP crash loop I staged the base-commit wrapper and the fixed wrapper over the real 0.20.0 engine and ran the exact invocation that was looping (codegraph-mcp --mcp): the old wrapper reproduces clap's "cannot be used multiple times" and exit 2, the fixed one completes the MCP handshake and lists 42 tools, and a genuinely bad flag now prints the assembled argument list and stops reporting after the third identical failure in a minute. For the static-model bug I drove codegraph_memory_store/codegraph_memory_search with --embedding-model static both ways: pointed at the VSIX bin/ directory that .vscodeignore removed, the vector engine fails to initialize and both tools return "Memory manager not initialized"; unset, the engine resolves the shared ~/.codegraph copy, reports "VectorEngine ready (jina-code-static-256, 256d, static)", and the stored memory comes back from search. The targeted automated suites (wrapper-args, fetch-engine, and the new server.spawnEnv vitest guard) all pass, and I mutation-tested the new guard by reintroducing the pre-fix default to confirm it fails, then reverted it. No screenshots: this round's changes are process-argument and spawn-environment behaviour with no rendered surface, so the reviewer-visible artifact is the CLI/JSON-RPC transcript. One gap worth knowing: the JetBrains mirror of the static-model rule reads correctly but has no runnable guard here, since its suite needs the IntelliJ SDK and network - that is the same gap already raised and closed for the VS Code side. Telemetry was disabled and a scratch HOME used throughout, so no events were sent and no state was written outside temp; the worktree is clean.

Evidence: MCP crash loop: before/after transcript with the real 0.20.0 engine

client config: { "command": "codegraph-mcp", "args": ["--mcp"] } ----- BEFORE (wrapper at base commit 06bcc88) ----- error: the argument '--mcp' cannot be used multiple times Usage: codegraph-server-darwin-arm64 [OPTIONS] $? = 2 <- clap rejects the duplicate before any telemetry; the MCP client respawns into the identical failure, forever ----- AFTER (wrapper at 91cc406) ----- initialize -> {"name":"codegraph","version":"0.20.0"} tools/list -> 42 tools, e.g. codegraph_get_dependency_graph, codegraph_get_call_graph, codegraph_analyze_impact, codegraph_get_ai_context $? = 0 <- the wrapper drops the flags it owns, the engine starts and serves ----- AFTER: an argument the engine really does reject is now explained, and the loop is broken ----- attempt 3: error: unexpected argument '--not-a-real-flag' found codegraph-mcp: the engine rejected its arguments and exited 2. arguments: --mcp --not-a-real-flag This is a configuration problem, not a crash. Check the "args" in your MCP client config - the wrapper already supplies --mcp. codegraph-mcp: failed 3 times in under a minute with the same arguments. Not reporting further failures for this configuration.

CodeGraph 0.20.0 - task #15: MCP crash loop from a duplicated --mcp flag
engine: codegraph-server 0.20.0   client config: { "command": "codegraph-mcp", "args": ["--mcp"] }

----- BEFORE (wrapper at base commit 06bcc88) -----
error: the argument '--mcp' cannot be used multiple times

Usage: codegraph-server-darwin-arm64 [OPTIONS]

For more information, try '--help'.
$? = 2   <- clap rejects the duplicate before any telemetry; the MCP client respawns into the identical failure, forever

----- AFTER (wrapper at 91cc406) -----
initialize -> {"name":"codegraph","version":"0.20.0"}
tools/list -> 42 tools, e.g. codegraph_get_dependency_graph, codegraph_get_call_graph, codegraph_analyze_impact, codegraph_get_ai_context
$? = 0   <- the wrapper drops the flags it owns, the engine starts and serves

----- AFTER: an argument the engine really does reject is now explained, and the loop is broken -----
attempt 1:
  error: unexpected argument '--not-a-real-flag' found
  
  Usage: codegraph-server-darwin-arm64 --mcp
  
  For more information, try '--help'.
  
  codegraph-mcp: the engine rejected its arguments and exited 2.
    arguments: --mcp --not-a-real-flag
    This is a configuration problem, not a crash. Check the "args" in
    your MCP client config - the wrapper already supplies --mcp.
attempt 2:
  error: unexpected argument '--not-a-real-flag' found
  
  Usage: codegraph-server-darwin-arm64 --mcp
  
  For more information, try '--help'.
  
  codegraph-mcp: the engine rejected its arguments and exited 2.
    arguments: --mcp --not-a-real-flag
    This is a configuration problem, not a crash. Check the "args" in
    your MCP client config - the wrapper already supplies --mcp.
attempt 3:
  error: unexpected argument '--not-a-real-flag' found
  
  Usage: codegraph-server-darwin-arm64 --mcp
  
  For more information, try '--help'.
  
  codegraph-mcp: the engine rejected its arguments and exited 2.
    arguments: --mcp --not-a-real-flag
    This is a configuration problem, not a crash. Check the "args" in
    your MCP client config - the wrapper already supplies --mcp.
  codegraph-mcp: failed 3 times in under a minute with the same
    arguments. Not reporting further failures for this configuration.
Evidence: Static embedding model: memory tools broken vs working

engine: codegraph-server 0.20.0 | VS Code setting codegraph.embeddingModel = "static" ----- BEFORE: CODEGRAPH_STATIC_MODEL=<extensionPath>/bin/jina-code-static-256 (that directory is gone - bin/** is excluded from the VSIX) ----- codegraph_memory_store -> Error: Failed to store memory: Other("Memory manager not initialized") codegraph_memory_search -> Error: Memory search failed: Other("Memory manager not initialized") engine log: VectorEngine initialization failed: Model("read config.json: No such file or directory (os error 2)") ----- AFTER (91cc406): CODEGRAPH_STATIC_MODEL left unset unless the user names a directory ----- codegraph_memory_store -> {"id":"571bc1c9-b488-4001-be72-2295fd0ec3ba","status":"stored", ...} codegraph_memory_search -> {"results":[{"content":"parse_config reads the JSON configuration file","kind":"convention","score":0.375554 ... engine log: VectorEngine ready (jina-code-static-256 (256d, static), 256d, static)

CodeGraph 0.20.0 - task #14: .vscodeignore bin/** dropped the static embedding model
engine: codegraph-server 0.20.0  |  VS Code setting codegraph.embeddingModel = "static"
user surface exercised: the codegraph_memory_* tools, which are backed by the static vector engine

----- BEFORE: extension exports CODEGRAPH_STATIC_MODEL=<extensionPath>/bin/jina-code-static-256 -----
        (that directory is gone - bin/** is excluded from the VSIX)
  codegraph_memory_store  -> Error: Failed to store memory: Other("Memory manager not initialized")
  codegraph_memory_search -> Error: Memory search failed: Other("Memory manager not initialized")
  engine log: VectorEngine initialization failed: Model("read config.json: No such file or directory (os error 2)")

----- AFTER (91cc406): extension leaves CODEGRAPH_STATIC_MODEL unset unless the user names a directory -----
        (engine resolves ~/.codegraph/static_models/jina-code-static-256, where the npm postinstall puts it)
  codegraph_memory_store  -> {"id":"571bc1c9-b488-4001-be72-2295fd0ec3ba","status":"stored","warning":"Workspace has only 2 nodes — it may not be indexed yet. Run codegraph_reindex_workspace for full code intelligence (typically 
  codegraph_memory_search -> {"results":[{"content":"parse_config reads the JSON configuration file","created_at":"2026-08-09T02:42:26.141019+00:00","id":"571bc1c9-b488-4001-be72-2295fd0ec3ba","kind":"convention","score":0.375554
  engine log: VectorEngine ready (jina-code-static-256 (256d, static), 256d, static)
Evidence: Mutation check: the new guard fails when the regression is reintroduced

Mutation check: reintroduce the pre-fix default (<extensionPath>/bin/jina-code-static-256) in vscode/src/server.ts ❯ src/server.spawnEnv.test.ts (5 tests | 2 failed) × does not point CODEGRAPH_STATIC_MODEL at a bundled path the VSIX no longer ships × leaves an inherited CODEGRAPH_STATIC_MODEL alone rather than clearing it AssertionError: expected '/ext/bin/jina-code-static-256' to be undefined (reverted afterwards; git status --porcelain clean, guard back to 5 passed)

Mutation check: reintroduce the pre-fix default (<extensionPath>/bin/jina-code-static-256) in vscode/src/server.ts


 RUN  v4.1.2 /Users/anvanster/.no-mistakes/worktrees/b8216ba13cd2/01KZJ46XN25EFMSEHDM538ZDM4/vscode

 ❯ src/server.spawnEnv.test.ts (5 tests | 2 failed) 4ms
     × does not point CODEGRAPH_STATIC_MODEL at a bundled path the VSIX no longer ships 2ms
     × leaves an inherited CODEGRAPH_STATIC_MODEL alone rather than clearing it 1ms

⎯⎯⎯⎯⎯⎯⎯ Failed Tests 2 ⎯⎯⎯⎯⎯⎯⎯

 FAIL  src/server.spawnEnv.test.ts > engineSpawnEnv > does not point CODEGRAPH_STATIC_MODEL at a bundled path the VSIX no longer ships
AssertionError: expected '/ext/bin/jina-code-static-256' to be undefined

- Expected:
undefined

+ Received:
"/ext/bin/jina-code-static-256"

 ❯ src/server.spawnEnv.test.ts:33:44
     31|         const env = engineSpawnEnv(config({ embeddingModel: 'static' }…
     32|
     33|         expect(env.CODEGRAPH_STATIC_MODEL).toBeUndefined();
       |                                            ^
     34|     });
     35|

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/2]⎯

 FAIL  src/server.spawnEnv.test.ts > engineSpawnEnv > leaves an inherited CODEGRAPH_STATIC_MODEL alone rather than clearing it
AssertionError: expected '/ext/bin/jina-code-static-256' to be '/from/the/users/shell' // Object.is equality

Expected: "/from/the/users/shell"
Received: "/ext/bin/jina-code-static-256"

 ❯ src/server.spawnEnv.test.ts:59:44
     57|         });
     58|
     59|         expect(env.CODEGRAPH_STATIC_MODEL).toBe('/from/the/users/shell…
       |                                            ^
     60|     });
- Outcome: 🔧 1 issue found → auto-fixed ✅ across 2 runs (19m19s)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 5 issues found → auto-fixed ✅
  • ⚠️ scripts/publish-release-assets.sh:130 - set -euo pipefail is active, so a grep that finds nothing inside a command substitution aborts the script before its own diagnostic runs. Line 70 (pin=&#34;$(grep -m1 &#39;ENGINE_VERSION = &#34;&#39; ... | sed ...)&#34;) and line 130 (recorded=&#34;$(grep -F &#34; $bin&#34; &#34;$MANIFEST&#34; 2&gt;/dev/null | ... )&#34;) are both plain assignments in statement position, so a failed grep propagates through pipefail and terminates the run. The ${pin:-&lt;not found&gt;} and NOT STAMPED messages, and the whole guidance block below them, are unreachable in exactly the cases they were written for. Since every channel now depends on this release existing, the operator gets a bare exit 1 instead of the instructions telling them what to stamp or rebuild. Fix: pin=&#34;$(... || true)&#34; (or || pin=&#39;&#39;) on both, matching the fallbacks already coded.
  • ⚠️ mcp-package/test/wrapper-args.test.js:28 - LOOP_STATE is computed from the real os.homedir() and the test unlinks it three times (lines 116, 129, 140) plus lets the wrapper write to it. Running npm test therefore destroys any genuine crash-loop state in ~/.codegraph/mcp-failures.json, and the breaker assertion silently depends on the developer's real home being writable — recordFailure returns 1 on a write failure, so on a read-only or sandboxed HOME the "breaker engages within three identical failures" check fails for an unrelated reason. Every other resource in this test is already isolated in mkdtempSync. Fix: point HOME (and USERPROFILE for Windows) at a temp dir in the spawnSync env and compute LOOP_STATE from that same dir.
  • ℹ️ scripts/package-npm.sh:46 - The pre-pack gate runs only node test/fetch-engine.test.js. package.json now defines &#34;test&#34;: &#34;node test/fetch-engine.test.js &amp;&amp; node test/wrapper-args.test.js&#34;, and wrapper-args.test.js is the regression guard for the duplicated---mcp collision that produced 656k crash events — the exact defect this release fixes. Packaging can currently succeed with that guard failing. Fix: run npm test here, or add the second file to the same subshell.
  • ℹ️ mcp-package/bin/postinstall.js:68 - Both comments state that codegraph-mcp resolves the engine "from its own bin directory and nowhere else", and the user-facing failure advice only names the bin path. findBinary() (bin/codegraph-mcp.js:171) now honours CODEGRAPH_SERVER_PATH — that was made to work in this same branch. The air-gapped/offline failure messages omit the one mechanism just fixed for that case, so a user hitting the retry path is steered away from the supported option. Fix: mention CODEGRAPH_SERVER_PATH=&lt;engine&gt; alongside the bin path in both messages and drop the stale "nowhere else" claim.
  • ℹ️ jetbrains/src/main/kotlin/ai/codegraph/jetbrains/telemetry/TelemetryReporter.kt:164 - dispose() calls sender.awaitTermination(2, SECONDS) on a project-level service, which IntelliJ disposes on the EDT during project close. With TIMEOUT_MS = 5_000 on both connect and read, an in-flight POST to an unreachable PostHog endpoint blocks project close for the full 2 seconds. The comment immediately above already establishes that the thread is a daemon and cannot keep the IDE alive, which is the reason the wait is not needed. Fix: sender.shutdownNow() without the await.

🔧 Fix: harden release scripts, isolate wrapper test, unblock EDT dispose
✅ Re-checked - no issues remain.

🔧 **Test** - 1 issue found → auto-fixed ✅
  • ⚠️ vscode/src/extension.ts:380 - The VS Code half of the static-model fix (vscode/src/extension.ts:380 - only set CODEGRAPH_STATIC_MODEL when the user names a directory) has no executable regression guard. vscode/vitest.config.ts documents that the private @vsforge test harness the extension suite depends on is permanently lost, and vscode/package.json still declares file:../vsforge/packages/@vsforge/* dependencies that do not exist in the repo, so npm install and therefore vitest cannot run here at all. The equivalent JetBrains change needs the IntelliJ SDK and network. I verified the user-visible outcome end-to-end at the engine boundary instead (both env conditions, real engine), and the change itself by reading the diff, but nothing will catch a future regression in the client-side wiring. Worth a decision on whether to rebuild a minimal vscode mock for this path.
  • node mcp-client-sim.js &lt;pkg&gt; 3 against the base-commit wrapper + real codegraph-server 0.20.0 - reproduced the exit-2 --mcp cannot be used multiple times respawn loop
  • node mcp-client-sim.js &lt;pkg&gt; 1 against the target-commit wrapper - MCP initialize returns serverInfo codegraph 0.20.0, exit 0
  • node bin/codegraph-mcp.js --mcp --bogus x4 with the real engine - exit-2 explanation, argument echo, and crash-loop breaker at the 3rd failure; inspected ~/.codegraph/mcp-failures.json
  • node static-model-probe.js with CODEGRAPH_STATIC_MODEL=&lt;extensionPath&gt;/bin/jina-code-static-256 - engine logs VectorEngine initialization failed: read config.json: No such file or directory, codegraph_memory_search returns Memory manager not initialized
  • node static-model-probe.js with CODEGRAPH_STATIC_MODEL unset - engine resolves ~/.codegraph/static_models/jina-code-static-256, logs VectorEngine ready, memory search responds
  • node test/wrapper-args.test.js in mcp-package (9 checks)
  • node test/fetch-engine.test.js in mcp-package (28 checks)
  • Checked engine version pins: Cargo.toml 0.20.0 vs mcp-package/bin/fetch-engine.js and jetbrains/.../CodeGraphServerResolver.kt - all match
  • git status --porcelain - worktree left clean, no transient artifacts

🔧 Fix: add regression guard for static model spawn env
✅ Re-checked - no issues remain.

  • node mcp-package/test/wrapper-args.test.js - 9 assertions on flag de-duplication, exit-2 diagnostics and the crash-loop breaker
  • node mcp-package/test/fetch-engine.test.js - engine asset/platform resolution for the unbundled distribution
  • npx vitest run src/server.spawnEnv.test.ts (in vscode/) - the new engineSpawnEnv guard, 5 tests
  • Mutation check: reintroduced the pre-fix &lt;extensionPath&gt;/bin/jina-code-static-256 default in vscode/src/server.ts, confirmed 2 of the 5 guard tests fail, then reverted (worktree verified clean via git status --porcelain)
  • Manual end-to-end MCP repro: staged the base-commit (06bcc88) wrapper and the fixed (91cc406) wrapper side by side over the real codegraph-server 0.20.0 binary and ran the previously-looping invocation codegraph-mcp --mcp with a JSON-RPC initialize + tools/list on stdin
  • Manual crash-loop breaker check: three consecutive codegraph-mcp --not-a-real-flag spawns, observing the exit-2 explanation each time and the breaker message on the third
  • Manual static-model repro: ran the engine in MCP mode with --embedding-model static and exercised codegraph_memory_store / codegraph_memory_search, once with CODEGRAPH_STATIC_MODEL pointed at the no-longer-shipped VSIX bin/ directory and once with it unset
⚠️ **Document** - 1 info
  • ℹ️ docs/troubleshooting.md:55 - Placement judgment call left for the author: the MCP crash-loop fix introduces user-visible state and output that no user document names - the persistent failure counter at ~/.codegraph/mcp-failures.json, the "engine rejected its arguments and exited 2" message, and the new mcp.crashloop telemetry event. The wrapper-owned-flags half is now covered in mcp-package/README.md (the owner of npm wrapper usage), which should stop users hitting it at all. The remaining state file and diagnostics would fit a "MCP server keeps restarting" section in docs/troubleshooting.md, but that document is currently scoped entirely to VS Code indexing, so widening it is a scope decision rather than a stale fact.
⚠️ **Lint** - 3 issues (1 warning, 2 infos)
  • ⚠️ vscode/package.json:1 - npm run lint in vscode/ fails outright: eslint 8.57.1 finds no configuration file, and no .eslintrc*/eslint.config.* has ever existed in the repo (confirmed at both 06bcc88 and 91cc406). This change adds or rewrites ~13 TypeScript files (engineDownload.ts, funnel.ts, codeLensProvider.ts, server.ts, extension.ts, telemetry/*), none of which have been linted. Authoring a config is a judgment call, not a mechanical fix, so it is left for the author: a flat config with @typescript-eslint (already a devDependency) would be the minimum. tsc --noEmit passes, so this is a lint-coverage gap, not a type error.
  • ℹ️ crates/codegraph-go/src/visitor.rs:1 - cargo fmt --all -- --check reports drift in ~60 files across the parser crates (codegraph-go, -c, -swift, -perl, -memory, -harness and others), roughly 250 hunks. None of them are touched by this change, and every Rust file that is touched is already rustfmt-clean. Running cargo fmt --all would be mechanical and safe but would bury the 0.20.0 release diff in unrelated churn, so it is left as a follow-up for a standalone style commit.
  • ℹ️ crates/codegraph-server/src/domain/unused_code.rs:17 - clippy reports 22 pre-existing warnings in codegraph-server (the whole find_unused_code module is dead code; BODY_PREFIX_MAX_CHARS is an unused import in 13 parser crates; two map_or/redundant-closure nits in mcp/server.rs). git blame puts all of them before the base commit, and none sit on a line this change touched, so they are reported rather than fixed here.
✅ **Push** - passed

✅ No issues found.

anvanster and others added 30 commits August 1, 2026 23:37
…dex 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>
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>
…atch

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>
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>
…eshooting 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>
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
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
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
… 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
… 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
…rors

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
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
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
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
…ers 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
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
…, 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
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
…ubleshooting doc, fix postinstall asset guard and CodeLens noise
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
…t 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
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

🔍 CodeGraph PR Review

105 files changed (+11192/−546, 363 functions) · Risk: 🔴 high

Blast radius

548 direct callers affected (455 breaking) across CodeGraph/crates/codegraph-dockerfile, CodeGraph/crates/codegraph-fortran, CodeGraph/crates/codegraph-kotlin, CodeGraph/crates/codegraph-toml, CodeGraph/crates/codegraph-verilog

⚠️ Test gaps (256 functions, 0 coverage)

  • start_file_watcher (crates/codegraph-server/src/backend.rs) — body_changed
  • shutdown (crates/codegraph-server/src/backend.rs) — body_changed
  • handle_memory_invalidate (crates/codegraph-server/src/backend.rs) — body_changed
  • handle_memory_update (crates/codegraph-server/src/backend.rs) — body_changed
  • handle_get_curated_context (crates/codegraph-server/src/backend.rs) — body_changed
  • handle_memory_store (crates/codegraph-server/src/backend.rs) — body_changed
  • handle_memory_search (crates/codegraph-server/src/backend.rs) — body_changed
  • handle_memory_stats (crates/codegraph-server/src/backend.rs) — body_changed
  • handle_mine_git_history_for_file (crates/codegraph-server/src/backend.rs) — body_changed
  • memory_manager (crates/codegraph-server/src/backend.rs) — signature_changed
  • …and 246 more

Suggested reviewers

Andrey Vasilevsky (442 lines), anvanster (3 lines)

Suggested commit: feat(codegraph-dockerfile): <describe the change> · 183 tests cover the changes
🤖 Generated by CodeGraph

@anvanster
anvanster merged commit 284c8e5 into main Aug 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant