Skip to content

feat: restart_debugging — one-call relaunch with breakpoints re-applied + fix live-proxy relaunch destroying the session (fixes #238) - #269

Merged
debugmcpdev merged 1 commit into
mainfrom
feat/restart-debugging-238
Aug 5, 2026
Merged

feat: restart_debugging — one-call relaunch with breakpoints re-applied + fix live-proxy relaunch destroying the session (fixes #238)#269
debugmcpdev merged 1 commit into
mainfrom
feat/restart-debugging-238

Conversation

@debugmcpdev

Copy link
Copy Markdown
Collaborator

Closes #238. Completes the cluster:breakpoint-tooling trio (#267#268 → this).

The edit-rerun loop — fix a line, rerun to the same breakpoints, confirm the state changed — was 4+ calls with breakpoint state lost (close, create, re-set every breakpoint, start). It is now one call.

restart_debugging {sessionId}

Terminates the current debuggee (if any) and replays the last real launch with the identical configuration — effective script path, args, dapLaunchArgs, adapterLaunchConfig, raw breakOnExceptions (policy defaults re-resolve on replay). Breakpoints re-apply automatically via the existing initialBreakpoints snapshot (#267 keeps their verified state honest). The response mirrors start_debugging plus data.breakpointsReapplied and data.outputReset: true — each launch starts a fresh output buffer, so read get_output from since: 0.

Design choices (per the planning session):

  • Terminate+relaunch uniformly. No adapter advertises native DAP restart, and the DAP spec explicitly blesses the emulation — so every launch-mode language works with zero per-adapter wiring. Native restart stays a future optimization.
  • Works after exit — the primary use case. The server tool deliberately skips validateSession's TERMINATED rejection (same precedent as get_output); a finished session restarts without being recreated.
  • Guards: attach sessions (no launch config to replay — detach/re-attach instead), never-launched and dry-run-only sessions, reentrant restarts, and INITIALIZING starts are refused with specific errors. ERROR state is allowed — relaunch-after-crash is a recovery path.
  • No per-restart overrides (v1) — different config = start_debugging, which itself now works correctly on a live session (below).
  • A launch now clears the sticky attachMode flag, so an attach-then-launch session doesn't wrongly refuse restarts forever.

🐛 Fixed: the session-destroying relaunch landmine

start_debugging (and attach_to_process) on a session with a live proxy called closeSession — which removes the session from the store — and then updated state on the removed session. Net effect: calling start_debugging on a paused session silently destroyed it and reported a bogus "Session not found". Zero test coverage (both existing "restart works" tests used dead proxies).

Both paths now use a new session-preserving stopProxyPreservingSession helper (listeners detached, worker stopped, adapter-registry slot released — repeated restarts can't exhaust the 10-instance cap), and the relaunch proceeds normally. The per-launch reset also clears breakpoint verified/message/adapterId, since a new adapter instance has verified nothing.

Tests

  • New session-manager-restart unit suite: replay fidelity (same script/args/config + breakpoints in the snapshot), the landmine regression (restart-while-paused keeps the session), per-launch verified reset (observable via a launch that dies mid-start), and every guard incl. concurrency. The old coverage test that asserted closeSession gets called now pins the session-preserving behavior instead.
  • Server handler suite: TERMINATED sessions restart; refusals surface as {success: false}; unknown session/missing param errors.
  • E2E tests/e2e/mcp-server-smoke-restart.test.ts across all 8 languages (toolchain-skip): pause at breakpoint → restart while paused (landmine path) → same breakpoint hits again → bounded-continue to completion → restart from TERMINATED → breakpoint hits again without re-issuing set_breakpoint → fresh get_output. 8/8 pass locally (rust/win32 uses the documented Rust/Windows: continue_execution re-stops at the same breakpoint (never advances without a step_over) #255 step_over workaround). Attach rejection asserted live in the python-attach e2e.
  • Dogfooded via the dev proxy: a finished Python session restarted in one call and paused at the re-applied breakpoint with breakpointsReapplied: 1, outputReset: true.

Docs

tool-reference section (+ TOC), README table, CLAUDE.md tool list (25 → 26), usage.md, both skill copies (the root-cause recipe's "fix, then re-run" step now names the tool), error-messages.ts's timeout advice points at the real tool, CHANGELOG Added + Fixed.

🤖 Generated with Claude Code

…landmine

- New restart_debugging {sessionId}: terminate the current debuggee (if
  any) and replay the last real launch with the same configuration.
  Breakpoints re-apply automatically via the initialBreakpoints snapshot;
  data.breakpointsReapplied and data.outputReset (read get_output from
  since=0) are added to the start_debugging-shaped response. Implemented
  uniformly as terminate+relaunch (no adapter advertises native DAP
  restart; the spec blesses the emulation), so every launch-mode language
  works with no per-adapter wiring. Guards: attach sessions and
  never-launched/dry-run-only sessions are refused with clear errors;
  reentrancy and INITIALIZING are refused; ERROR state is allowed (crash
  recovery). The server tool deliberately skips validateSession's
  TERMINATED rejection — restarting after exit is the primary use case.
- LastLaunchSpec captured on ManagedSession at the top of every real
  (non-dry-run) launch: effective scriptPath, args, dapLaunchArgs,
  adapterLaunchConfig, raw breakOnExceptions (policy defaults re-resolve
  on replay). A launch also clears the sticky attachMode flag so
  attach-then-launch sessions can restart.
- FIX (latent bug, zero coverage): startDebugging/attachToProcess on a
  session with a live proxy called closeSession — which removes the
  session from the store — then updated state on the removed session,
  destroying the session and reporting "Session not found". Both paths now
  use a new session-preserving stopProxyPreservingSession helper
  (listeners removed, worker stopped, adapter registry slot released).
- Per-launch reset now clears breakpoint verified/message/adapterId — a
  new adapter instance has verified nothing, so relaunches report honest
  verification.
- error-messages.ts timeout advice now points at the real
  restart_debugging tool.
- Tests: new session-manager-restart unit suite (replay fidelity, landmine
  regression, per-launch reset, all guards); server handler suite; the old
  "should close existing session" assertion now pins the session-PRESERVING
  behavior; e2e tests/e2e/mcp-server-smoke-restart.test.ts across all 8
  languages (restart while paused + restart after exit, 8/8 pass locally);
  attach-rejection asserted live in the python-attach e2e. Dogfooded via
  the dev proxy: a finished session restarted in one call and paused at
  the re-applied breakpoint.
- Docs: tool-reference section + TOC, README table, CLAUDE.md tool list
  25 -> 26, usage.md, skill copies, CHANGELOG Added + Fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.33333% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/session/session-manager-core.ts 75.00% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@debugmcpdev
debugmcpdev merged commit c59cf6d into main Aug 5, 2026
10 checks passed
@debugmcpdev
debugmcpdev deleted the feat/restart-debugging-238 branch August 5, 2026 16:16
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.

[FEATURE] restart_debugging tool — relaunch the current session in one call

2 participants