Repository navigation
feat(xdebug): saved breakpoints for sessions without an IDE - #401
Merged
Merged
Conversation
- Table xdebug_breakpoints (line: file+line, or exception class; optional
condition; enabled; source ui|mcp). Sent to every session Buggregator
drives before the script runs; changes go out at once while paused, else
at the next pause. An IDE keeps setting its own.
- REST: GET/POST /api/xdebug/breakpoints, PATCH/DELETE .../{id} (JSON only,
cross-site refused). A condition is PHP code: 403 eval_disabled without
allow_eval; one saved earlier is skipped (not sent) while eval is off.
- GET /api/xdebug/sessions/{id}/breakpoints for a session driven here: each
saved breakpoint with state (resolved, unresolved, skipped, disabled,
pending), resolved_line (breakpoint_resolved notify / breakpoint_list)
and hit_count. WS: breakpoints.changed, breakpoint.resolved.
- GET /api/xdebug/files?q=&limit=: files seen in pauses and stacks (500
most recent, in memory) plus the files of saved breakpoints.
- MCP: xdebug_breakpoints (read, always on); xdebug_breakpoint_set and
xdebug_breakpoint_remove with allow_control.
- waitSeconds clamps before multiplying (no Duration overflow).
- A breakpoint_remove the engine did not take (the script moved on) keeps the engine id and marks the session dirty; a deleted breakpoint is forgotten only after the engine removed it. The next pause retries. - syncBreakpoints reads the current list after taking bpSyncMu, so a sync that waited never applies an older snapshot. - BreakpointsChanged syncs before it returns: a paused session has the breakpoint before the caller can continue it. ownCallReply marks dirty under mu when refused, and on a timeout. - Session state shows pending for a change not applied yet. - MCP xdebug_breakpoints on an IDE-driven session lists the IDE's breakpoints; tool text says when a breakpoint reaches a session. - File paths: absolute, file:// or Windows drive (C:\app\x.php → file:///C:/app/x.php); relative paths are refused.
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.
Part 3 of "Xdebug without an IDE" (parts 1 #392 and 2 #395 are merged): breakpoints that Buggregator keeps and sends to the sessions it drives.
What changes
xdebug_breakpoints, new migration): a line (file+line) or an exception class, optionalcondition,enabled,source(ui|mcp). They survive restarts.breakpoint_set/breakpoint_remove); while it runs, at its next pause. A session an IDE drives is not touched: the IDE sets its own.GET /api/xdebug/breakpoints,POST /api/xdebug/breakpoints,PATCH /api/xdebug/breakpoints/{id},DELETE /api/xdebug/breakpoints/{id}.403 eval_disabledwithoutxdebug.allow_eval. A condition saved earlier while eval is now off is skipped (not sent at all).GET /api/xdebug/sessions/{id}/breakpointsfor a session driven here returns each saved breakpoint withstate(resolved|unresolved|skipped|disabled|pending),resolved_line(Xdebug'sbreakpoint_resolved, e.g. a blank line moves to the next statement) andhit_count. For an IDE-driven session it still lists what the IDE set.breakpoints.changed(the full list),breakpoint.resolved(session_id,breakpoint_id,line).GET /api/xdebug/files?q=&limit=20, files seen in pauses and stacks (500 most recent, in memory) plus files of saved breakpoints; base-name/path prefix first, then substring.xdebug_breakpoints(read, always on);xdebug_breakpoint_set,xdebug_breakpoint_remove(withallow_control).waitSecondsclamps before multiplying (review note on feat(xdebug): MCP tools to drive a session without an IDE #395).Tests
modules/xdebug/breakpoints_test.go(fake DBGp engine): sent beforerun, states incl. skipped/disabled,breakpoint_resolved→ resolved_line, hit_count frombreakpoint_list; add/disable/delete while paused; added while running → pending, sent at the next pause; REST validation (403/400/415/404); conditional command; SQLite persistence through the migration; files search and cap; MCP set/list/remove.go test -race -count=1 ./modules/xdebug/ ./internal/app/ ./internal/storage/ok; breakpoint tests-race -count=10ok.RuntimeExceptionhit; breakpoints kept across a server restart (file DB); disabled ones not sent; a breakpoint added while paused hit onrun.Made with harnsy