fix(java): route every launch through the mtime-aware JDI bridge resolution (#646) - #657
Merged
Merged
Conversation
…lution (#646) buildAdapterCommand resolved the compiled bridge with a pure existsSync walk and only fell back to ensureJdiBridgeCompiled() — the one function carrying the isClassStale mtime guard — when no JdiDapServer.class existed at all. So after editing JdiDapServer.java (or a checkout that touched it) every session silently ran the old class: new launch keys dropped, new DAP behavior absent, nothing said why. - jdi-resolver: new ensureJdiBridge() returns {dir, sourceFile, stale, recompiled, error}; ensureJdiBridgeCompiled() is now a thin wrapper. A fresh class costs two stats; a stale one is recompiled; a stale one that cannot be recompiled is returned with the reason (javac missing, or the compiler's first stderr lines — captured instead of inherited into the proxy worker's stdio). JDI_BRIDGE_DIR is an explicit override: never compared, never rebuilt. isJdiBridgeStale() is the no-compile probe. - java-debug-adapter: buildAdapterCommand always calls ensureJdiBridge(), logs the recompile, warns (with the reason) when it must run a stale class; validateEnvironment adds a JDI_BRIDGE_STALE warning. - java-adapter-factory: validate() surfaces the same warning and details.jdiBridgeStale, so `mcp-debugger doctor` shows it. Verified live: touch JdiDapServer.java → doctor warns on the java row → start_debugging recompiles (logged) and stops at the breakpoint with locals intact. Fixes #646 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SNhNB42Y55cgsknYTQb2Bm
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
buildAdapterCommandresolved the compiled JDI bridge with a pureexistsSyncwalk and only fell back toensureJdiBridgeCompiled()— the one function carrying theisClassStalemtime guard — when noJdiDapServer.classexisted at all. After editingJdiDapServer.java(or a checkout that touched it) every session silently ran the old class.packages/adapter-java/src/utils/jdi-resolver.ts— newensureJdiBridge(): JdiBridgeStatus({dir, sourceFile, stale, recompiled, error});ensureJdiBridgeCompiled()is a thin wrapper over it, so the existing API keeps working. A fresh class costs two stats; a stale class is recompiled; a stale class that cannot be recompiled is returned with the reason (javacmissing, or the compiler's first stderr lines — javac's output is now captured instead of inherited into the proxy worker's stdio).JDI_BRIDGE_DIRis treated as an explicit override: never compared against the in-tree source, never rebuilt.isJdiBridgeStale()is the no-compile probe. An install that ships only the class is never stale (stat failure → not stale, unchanged).java-debug-adapter.ts—buildAdapterCommandalways callsensureJdiBridge(), logs a recompile, and warns with the reason when it has to run a stale class.validateEnvironmentadds aJDI_BRIDGE_STALEwarning (valid stays true — the launch will recompile).java-adapter-factory.ts—validate()surfaces the same warning plusdetails.jdiBridgeStale, somcp-debugger doctorshows it.-cp java/outfallback inadapter-policy-java.ts(only reached when noadapterCommandis supplied) is a separate concern.jdi-resolver.test.tsnow mocksstatSync(the mtime branch was unreachable in the old suite) and covers fresh / stale+javac / stale+no-javac / stale+compile-error /JDI_BRIDGE_DIR/ class-only install; newjdi-bridge-staleness.test.tscovers the adapter and factory wiring with the resolver mocked. Changelog fragmentchangelog.d/646.fixed.md.Verified live
touch packages/adapter-java/java/JdiDapServer.java, then:mcp-debugger doctor→ java row⚠️ warn, fix line: JDI bridge source is newer than the compiled class at …; the next launch recompiles it (javac required)…start_debugging examples/java/HelloWorld.javawith a breakpoint on line 24 → the session log carries theJDI_BRIDGE_STALEwarning fromvalidateEnvironmentand then[JavaDebugAdapter] JDI bridge source was newer than the compiled class; recompiled into …/java/out; the class mtime moved past the source; the breakpoint hit andget_local_variablesreturnedx=10, y=20.Fixes #646
🤖 Generated with Claude Code
https://claude.ai/code/session_01SNhNB42Y55cgsknYTQb2Bm