Commit 284c8e5
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
- crates
- codegraph-server/src
- domain
- handlers
- mcp
- codegraph
- src/graph
- tests/unit
- docs
- jetbrains
- gradle/wrapper
- scripts
- src
- main
- kotlin/ai/codegraph/jetbrains
- actions
- diagnostics
- graph
- indexing
- lsp
- mcp
- notify
- server
- settings
- telemetry
- ui
- vision
- resources
- META-INF
- messages
- test/kotlin/ai/codegraph/jetbrains
- graph
- indexing
- mcp
- server
- telemetry
- mcp-package
- bin
- test
- scripts
- vscode
- media
- walkthrough
- src
- ai
- commands
- telemetry
- views
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
| 33 | + | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
37 | 53 | | |
38 | 54 | | |
39 | 55 | | |
| |||
89 | 105 | | |
90 | 106 | | |
91 | 107 | | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
102 | 125 | | |
103 | 126 | | |
104 | 127 | | |
| |||
117 | 140 | | |
118 | 141 | | |
119 | 142 | | |
120 | | - | |
| 143 | + | |
121 | 144 | | |
122 | 145 | | |
123 | 146 | | |
124 | 147 | | |
125 | 148 | | |
126 | | - | |
127 | | - | |
| 149 | + | |
| 150 | + | |
128 | 151 | | |
129 | 152 | | |
130 | 153 | | |
131 | 154 | | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
143 | 159 | | |
144 | 160 | | |
145 | 161 | | |
| |||
151 | 167 | | |
152 | 168 | | |
153 | 169 | | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
154 | 173 | | |
155 | 174 | | |
156 | | - | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
157 | 178 | | |
158 | 179 | | |
159 | 180 | | |
| |||
339 | 360 | | |
340 | 361 | | |
341 | 362 | | |
342 | | - | |
| 363 | + | |
343 | 364 | | |
344 | 365 | | |
345 | 366 | | |
| |||
356 | 377 | | |
357 | 378 | | |
358 | 379 | | |
359 | | - | |
360 | | - | |
361 | | - | |
362 | | - | |
363 | | - | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
364 | 385 | | |
365 | 386 | | |
366 | 387 | | |
| |||
0 commit comments