feat: break-on-exception support (breakOnExceptions) + exception detail + debuggee exit code (#220) - #245
Merged
Merged
Conversation
…il + exit code (#220) - breakOnExceptions ('uncaught'|'all'|'none', default none) on start_debugging and attach_to_process; abstract mode resolved to per-language DAP filter IDs via AdapterPolicy.getInitializationBehavior().exceptionFilters - worker sends setExceptionBreakpoints between initial breakpoints and configurationDone (all launch/attach variants); failures never abort launch - js-debug path: parent handshake + child sessions + post-attach replay arm the same resolved filters (setExceptionBreakMode threading) - lastStop now records the stopped event's description/text (exception class/message) - debuggee exit code from the DAP exited event surfaced on the session and in list_debug_sessions - mock adapter: setExceptionBreakpoints handler + gated exception simulation; emits exited before terminated (matches debugpy ordering) - runtime-verified js-debug filter IDs ('all'/'uncaught'); corrected the static capability declaration Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 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.
Fixes #220.
What
An uncaught exception in a debuggee previously terminated the session — indistinguishable from a clean exit, with stack and locals gone. This PR adds the missing tool surface and the two related visibility gaps called out in the issue:
breakOnExceptions: "uncaught" | "all" | "none"(default"none", opt-in — zero behavior change when unset) onstart_debuggingandattach_to_process. The abstract mode is resolved to concrete DAPexceptionBreakpointFiltersIDs per language by the adapter policy (getInitializationBehavior().exceptionFilters+ exportedresolveExceptionFilters()):uncaughtalluncaughtraised,uncaughtuncaughtall(runtime-verified against js-debug)uncaughtcaught,uncaughtuser-unhandledallfatal,panicfatal,panicrust_panicrust_panic,cpp_throwanyException detail on stops:
lastStopnow records the stopped event'sdescription/text(exception class and message) — surfaced vialist_debug_sessions,get_stack_trace, and thestart_debuggingresponse.Debuggee exit code: the DAP
exitedevent'sexitCodeis stored on the session and returned inlist_debug_sessions, so a crash (non-zero) is distinguishable from a clean exit.How
setExceptionBreakpointsinhandleInitializedEventbetween initial breakpoints andconfigurationDone— one site covering python launch-first, go/java/ruby/dotnetsendLaunchBeforeConfig, and both attach variants. Failures are warn-logged and never abort the launch (inner try/catch; the outer catch callsshutdown()).MinimalDapClient.setExceptionBreakMode→ChildSessionManager). Unset mode resolves to[]— byte-identical to the previous hardcoded{filters: []}.@debugmcp/shared, shared by both processes, so the mapping cannot drift.setExceptionBreakpointshandler + double-gated exception simulation (filters armed AND program path matches/throws|error/i), and it now emitsexitedbeforeterminated(matching debugpy — the SessionManager tears down handlers onterminated).Verified
tests/e2e/mcp-server-break-on-exceptions.test.ts, 7 tests green): mock full-stack (pause → continue →exitCode: 1), python launch pausing at theZeroDivisionErrorcrash site with localsa=10, b=0live + no-option regression guard (terminates, non-zeroexitCode), javascript pause-at-uncaught, python attach with filters armed during the attach init sequence (newattach_then_raise.pyfixture).lastStopdetail,exitCode: 1after continue.all/uncaught) and corrected the drifted static declaration inadapter-javascript.Notes
uncaughtdoes not fire for top-level ESM module throws (the loader wraps them; V8 predicts "caught") — the js fixture throws from a timer callback. Documented in the fixture.start_debuggingon a pre-existing launch-orchestration race, reproduced on main and filed as [BUG] start_debugging hangs past 60s for a fast-crashing JavaScript script #242. The no-option wire behavior is unchanged and covered at unit level.exceptionInfoenrichment), [FEATURE] Consider defaulting breakOnExceptions to 'uncaught' for launch sessions #244 (consider defaulting'uncaught'on).🤖 Generated with Claude Code