textual-debugger 0.1.4__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/PKG-INFO +157 -21
- {textual_debugger-0.1.4/src/tdb → textual_debugger-0.2.0}/README.md +156 -20
- {textual_debugger-0.1.4 → textual_debugger-0.2.0/src/tdb}/README.md +156 -20
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/__init__.py +1 -1
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/app.py +63 -13
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/app_handlers/dap_events.py +2 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/app_handlers/inspection.py +56 -8
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/cli.py +61 -2
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/dap/client.py +45 -75
- textual_debugger-0.2.0/src/tdb/languages/__init__.py +21 -0
- textual_debugger-0.2.0/src/tdb/languages/base.py +139 -0
- textual_debugger-0.2.0/src/tdb/languages/cpp.py +150 -0
- textual_debugger-0.2.0/src/tdb/languages/python.py +116 -0
- textual_debugger-0.2.0/src/tdb/languages/registry.py +106 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/mcp/server.py +12 -2
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/mcp/session.py +48 -4
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/persist.py +15 -1
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/server/handlers.py +9 -4
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/server/runner.py +23 -9
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/child_processes.py +7 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/controller.py +71 -19
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/inspect_service.py +14 -2
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/statement_stepper.py +16 -3
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/source_analysis.py +20 -4
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/code_view.py +6 -3
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/textual_debugger.egg-info/PKG-INFO +157 -21
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/textual_debugger.egg-info/SOURCES.txt +5 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/LICENSE +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/pyproject.toml +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/setup.cfg +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/__main__.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/_timeouts.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/app_handlers/__init__.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/app_handlers/routing.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/app_handlers/ui_panels.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/app_helpers.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/breakpoint_hook.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/dap/__init__.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/dap/messages.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/dap/protocol.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/dap/types.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/inspection.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/inspection_full.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/keybindings/__init__.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/mcp/__init__.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/mcp/__main__.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/post_mortem.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/processes_cache.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/server/__init__.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/server/app.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/server/event_handler.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/server/rpc_types.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/__init__.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/event_bus.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/messages.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/post_mortem_loader.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/state.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/terminal.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/session/textual_handler.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/__init__.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/_inspection_modal.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/async_tasks_modal.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/breakpoint_view.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/console_view.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/evaluate_console.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/full_contents_modal.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/menu_bar.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/modals.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/processes_modal.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/stack_view.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/status_bar.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/threads_modal.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/tdb/widgets/variable_view.py +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/textual_debugger.egg-info/entry_points.txt +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/textual_debugger.egg-info/requires.txt +0 -0
- {textual_debugger-0.1.4 → textual_debugger-0.2.0}/src/textual_debugger.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: textual-debugger
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A TUI Python debugger based on textual and debugpy
|
|
5
5
|
Author-email: Al Danial <al.danial@gmail.com>
|
|
6
6
|
License: textual-debugger is licensed to you under the MIT/X Consortium license:
|
|
@@ -67,12 +67,18 @@ Dynamic: license-file
|
|
|
67
67
|
# `textual-debugger`
|
|
68
68
|
|
|
69
69
|
`textual-debugger` (the package) provides `tdb` (the command-line tool and module),
|
|
70
|
-
a full-featured terminal-based Python
|
|
71
|
-
|
|
72
|
-
`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
a full-featured terminal-based debugger for Python and other languages
|
|
71
|
+
with a Debug Adapter Protocol (DAP) implementation. C and C++ support (via
|
|
72
|
+
`gdb` or `lldb-dap`) is built in.
|
|
73
|
+
|
|
74
|
+
`tdb` is built with [textual](https://github.com/Textualize/textual) and speaks
|
|
75
|
+
DAP to a pluggable debug adapter: [debugpy](https://github.com/microsoft/debugpy)
|
|
76
|
+
(the engine behind VS Code's Python debugger) for Python,
|
|
77
|
+
[GDB's DAP mode](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html) or
|
|
78
|
+
[lldb-dap](https://lldb.llvm.org/resources/lldbdap.html)
|
|
79
|
+
for compiled code. It provides a rich interactive interface for stepping through
|
|
80
|
+
code, inspecting variables, managing breakpoints, and evaluating expressions in
|
|
81
|
+
complex programs.
|
|
76
82
|
|
|
77
83
|
- PyPI: https://pypi.org/project/textual-debugger/
|
|
78
84
|
- GitHub: https://github.com/AlDanial/tdb
|
|
@@ -83,6 +89,10 @@ MIT License. Copyright 2026 by Al Danial.
|
|
|
83
89
|
|
|
84
90
|
`tdb`:
|
|
85
91
|
|
|
92
|
+
- debugs multiple languages through the Debug Adapter Protocol: Python (via `debugpy`,
|
|
93
|
+
the richest feature set) and C/C++ (via `gdb -i dap` or `lldb-dap`), with the language
|
|
94
|
+
auto-detected from the target (ref. [Multi-Language Debugging](#multi-language-debugging)).
|
|
95
|
+
|
|
86
96
|
- supports debugging of synchronous, asynchronous, multi-threaded, and multi-process Python code.
|
|
87
97
|
It specifically supports modules
|
|
88
98
|
- `asyncio` (with a built-in async task inspector and task wait graph)
|
|
@@ -91,7 +101,8 @@ It specifically supports modules
|
|
|
91
101
|
|
|
92
102
|
- supports remote attachment to debugpy-enabled Python programs
|
|
93
103
|
|
|
94
|
-
- includes a JSON-RPC server mode
|
|
104
|
+
- includes a JSON-RPC server mode, an MCP mode, and a `SKILL.md` file that enable
|
|
105
|
+
programmatic debug control, making it suitable for
|
|
95
106
|
automated, headless debugging workflows and AI-assisted debugging
|
|
96
107
|
|
|
97
108
|
- can spawn the debuggee in an external terminal to enable debugging TUI applications
|
|
@@ -120,6 +131,9 @@ as open source.
|
|
|
120
131
|
[Claude for Open Source](https://claude.com/contact-sales/claude-for-oss) program.
|
|
121
132
|
`tdb` was made almost entirely with Claude Code.
|
|
122
133
|
|
|
134
|
+
- OpenAI, for providing access to Codex through the
|
|
135
|
+
[Codex for Open Source](https://developers.openai.com/community/codex-for-oss) program.
|
|
136
|
+
|
|
123
137
|
## Gallery
|
|
124
138
|
<p align="center">
|
|
125
139
|
<img src="https://github.com/AlDanial/tdb/blob/main/gallery/async_breakpoint.png" alt="at breakpoint" width="300">
|
|
@@ -165,6 +179,16 @@ tdb my_program.py
|
|
|
165
179
|
# debug with arguments
|
|
166
180
|
tdb my_program.py arg1 arg2
|
|
167
181
|
|
|
182
|
+
# debug a C/C++ (or other native) executable built with -g. The ELF/Mach-O/PE
|
|
183
|
+
# binary is auto-detected and debugged through GDB's DAP mode (GDB >= 14)
|
|
184
|
+
tdb ./myprog arg1 arg2
|
|
185
|
+
|
|
186
|
+
# same, but using lldb-dap (LLVM >= 17) instead of gdb
|
|
187
|
+
tdb --adapter lldb-dap ./myprog
|
|
188
|
+
|
|
189
|
+
# force the language when auto-detection can't tell (e.g. an extensionless script)
|
|
190
|
+
tdb --lang python ./mytool
|
|
191
|
+
|
|
168
192
|
# add breakpoints at lines 20 and 35 of `my_program.py` and line 14
|
|
169
193
|
# of `module.py` (when -k is given, --no-stop-on-entry is set and the
|
|
170
194
|
# program runs to the first breakpoint)
|
|
@@ -206,6 +230,79 @@ Alternatively, use the module entry point:
|
|
|
206
230
|
python -m tdb my_program.py
|
|
207
231
|
```
|
|
208
232
|
|
|
233
|
+
## Multi-Language Debugging
|
|
234
|
+
|
|
235
|
+
`tdb` debugs any language that has a Debug Adapter Protocol backend. Two
|
|
236
|
+
languages are supported out of the box:
|
|
237
|
+
|
|
238
|
+
| Language | Adapter(s) | How to get the adapter | Feature level |
|
|
239
|
+
|----------|------------|------------------------|---------------|
|
|
240
|
+
| Python | `debugpy` (default) | installed with `textual-debugger` | everything in this README |
|
|
241
|
+
| C / C++ (any native binary) | `gdb` (default), `lldb-dap` (alternate) | `gdb -i dap` requires GDB ≥ 14; `lldb-dap` ships with LLVM ≥ 17 (e.g. `apt install lldb`) | core debugging: breakpoints, stepping, stack, variables, evaluate console |
|
|
242
|
+
|
|
243
|
+
### Language detection and selection
|
|
244
|
+
|
|
245
|
+
The language is auto-detected from the debug target:
|
|
246
|
+
|
|
247
|
+
1. File extension: `.py` → Python.
|
|
248
|
+
2. Native executables (ELF, Mach-O, PE magic bytes) → C/C++.
|
|
249
|
+
3. A `#!...python` shebang → Python.
|
|
250
|
+
4. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
|
|
251
|
+
hint: compile with debug info (`g++ -g -O0`) and debug the binary.
|
|
252
|
+
5. Anything else produces an error naming the `--lang` override.
|
|
253
|
+
|
|
254
|
+
`--lang` forces the language; `--adapter` picks a non-default adapter within
|
|
255
|
+
it (`tdb --lang cpp --adapter lldb-dap ./myprog`).
|
|
256
|
+
|
|
257
|
+
> **Migration note:** extensionless Python scripts without a `python` shebang
|
|
258
|
+
> were previously assumed to be Python; they now require `--lang python`.
|
|
259
|
+
|
|
260
|
+
### Adapters are found on `PATH`
|
|
261
|
+
|
|
262
|
+
`tdb` does not download or bundle adapters. If the adapter executable isn't
|
|
263
|
+
found, the error names the package to install. To use an adapter from a
|
|
264
|
+
non-standard location, or change a language's default adapter, add to
|
|
265
|
+
`config.json` (see [Configuration](#configuration)):
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"},
|
|
270
|
+
"default_adapters": {"cpp": "lldb-dap"}
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### What works for non-Python languages
|
|
275
|
+
|
|
276
|
+
Core debugging works identically for every language: breakpoints (incl.
|
|
277
|
+
conditions and persistence), stepping, continue/pause, run-to-cursor, stack
|
|
278
|
+
navigation, variable inspection, the evaluate console, syntax highlighting,
|
|
279
|
+
and the JSON-RPC / MCP programmatic modes.
|
|
280
|
+
|
|
281
|
+
Python-specific features are hidden or return a clear "not supported for this
|
|
282
|
+
language" message when debugging other languages: statement-granularity
|
|
283
|
+
stepping (non-Python languages always step per line), the async task /
|
|
284
|
+
process inspectors and wait graph, the evaluate console's trailing-`?` help,
|
|
285
|
+
remote attach (`-r`), `--python`/`--pv`, `--no-subprocess`,
|
|
286
|
+
automatic child-process attachment, and the post-mortem / `tdb.breakpoint()`
|
|
287
|
+
hooks (those hooks live inside Python programs by nature). `--terminal` is
|
|
288
|
+
currently ignored for non-Python targets.
|
|
289
|
+
|
|
290
|
+
### C/C++ tips
|
|
291
|
+
|
|
292
|
+
- Compile with `-g` (ideally `-g -O0`). If no breakpoint in a file can be
|
|
293
|
+
bound, `tdb` prints a console warning suggesting the program may lack
|
|
294
|
+
debug info.
|
|
295
|
+
- Stack frames pointing into system libraries often have no source on disk;
|
|
296
|
+
the Code View shows a `<Could not read …>` placeholder while the stack,
|
|
297
|
+
variables, and evaluate console remain fully usable.
|
|
298
|
+
- GDB (the default adapter) has the most complete libstdc++
|
|
299
|
+
pretty-printing. `lldb-dap` (via `--adapter lldb-dap`) also debugs
|
|
300
|
+
GCC-built binaries fine — DWARF is compiler-neutral.
|
|
301
|
+
- **GDB evaluate-console quirk:** GDB's DAP treats REPL input as CLI
|
|
302
|
+
commands, so evaluate expressions with an explicit `print`, e.g.
|
|
303
|
+
`print x` rather than bare `x` (bare `x` collides with GDB's
|
|
304
|
+
examine-memory command). `lldb-dap` evaluates bare expressions directly.
|
|
305
|
+
|
|
209
306
|
## Layout
|
|
210
307
|
|
|
211
308
|
```
|
|
@@ -234,7 +331,7 @@ The footer shows the most relevant keybindings for the current mode.
|
|
|
234
331
|
### Navigation and Keybindings
|
|
235
332
|
|
|
236
333
|
|
|
237
|
-
The Code View shows syntax-highlighted
|
|
334
|
+
The Code View shows syntax-highlighted source (lexer chosen per language) with line numbers.
|
|
238
335
|
A cursor line (blue) tracks your position; the current execution line is highlighted in gold.
|
|
239
336
|
|
|
240
337
|
**View focus shortcuts (global):**
|
|
@@ -326,6 +423,9 @@ lands on `print(results)`, not on each interior sub-line of the `gather` call. S
|
|
|
326
423
|
stops on each physical line--useful for inspecting how a complex expression is built up.
|
|
327
424
|
The choice is saved to `~/.config/tdb/config.json`.
|
|
328
425
|
|
|
426
|
+
Statement mode requires a source-language model and is currently Python-only;
|
|
427
|
+
other languages always step per line (the Step Mode menu says so if you try).
|
|
428
|
+
|
|
329
429
|
### Breakpoints
|
|
330
430
|
|
|
331
431
|
Click the gutter in the Code View to toggle a breakpoint, or press `b` in Debug mode.
|
|
@@ -383,6 +483,15 @@ interactive evaluation of expressions in the current scope:
|
|
|
383
483
|
|
|
384
484
|
Variable values set here are reflected in the running code.
|
|
385
485
|
|
|
486
|
+
### Cut / Paste
|
|
487
|
+
|
|
488
|
+
Expression for the Evaluate Console are often copied from the Code View.
|
|
489
|
+
Doing this in `tdb` differs from traditional terminal behavior, because `textual` applications
|
|
490
|
+
capture mouse events for their own use.
|
|
491
|
+
|
|
492
|
+
Instead, hold the `Shift` key while performing your conventional cut/paste keystrokes or mouse
|
|
493
|
+
operation to get the expected behavior.
|
|
494
|
+
|
|
386
495
|
### Console Output
|
|
387
496
|
|
|
388
497
|
The Console View captures stdout (normal text) and stderr (red text) from the debuggee
|
|
@@ -442,6 +551,17 @@ Snapshot depth / breadth is capped (5 levels, 50 children per container) to keep
|
|
|
442
551
|
capture cheap even for pathological object graphs; cycles are handled via identity
|
|
443
552
|
memoization.
|
|
444
553
|
|
|
554
|
+
### Post-Mortem within a Docker Container
|
|
555
|
+
|
|
556
|
+
The `textual-debugger` GitHub repository's `examples/` directory has three files
|
|
557
|
+
that show how to run a `tdb`-enabled Python program under `tmux` in a Docker
|
|
558
|
+
container so that you can attach to the container and inspect the program
|
|
559
|
+
in `tdb` post-mortem analysis mode if the program hits an unhandled exception:
|
|
560
|
+
|
|
561
|
+
- [post_mortem_example.py](https://github.com/AlDanial/tdb/blob/main/examples/post_mortem_example.py)
|
|
562
|
+
- [post_mortem_entrypoint.sh](https://github.com/AlDanial/tdb/blob/main/examples/post_mortem_entrypoint.sh)
|
|
563
|
+
- [Dockerfile.post_mortem](https://github.com/AlDanial/tdb/blob/main/examples/Dockerfile.post_mortem)
|
|
564
|
+
|
|
445
565
|
### Live Breakpoint Hook
|
|
446
566
|
|
|
447
567
|
`tdb` has an improved implemenation of the standard `breakpoint()` function (or equivalently,
|
|
@@ -739,7 +859,7 @@ curl -s -X POST http://127.0.0.1:8150/rpc \
|
|
|
739
859
|
| `set_breakpoint` | `["file:line"]` or `["file:line", "condition", "hit_condition"]` | Set a breakpoint |
|
|
740
860
|
| `remove_breakpoint` | `["file:line"]` | Remove a breakpoint |
|
|
741
861
|
| `list_breakpoints` | `[]` | Show all breakpoints |
|
|
742
|
-
| `continue` | `[]` or `[timeout_s]` | Resume execution; on timeout returns `"still running
|
|
862
|
+
| `continue` | `[]` or `[timeout_s]` | Resume execution; on timeout returns `"still running--call pause or wait again"` (success) |
|
|
743
863
|
| `next` | `[]` or `[timeout_s]` | Step over |
|
|
744
864
|
| `step_in` | `[]` or `[timeout_s]` | Step into |
|
|
745
865
|
| `step_out` | `[]` or `[timeout_s]` | Step out |
|
|
@@ -778,7 +898,7 @@ Each is JSON with `event`, `data`, and `timestamp` fields.
|
|
|
778
898
|
tdb ships a Model Context Protocol (MCP) server (`tdb-mcp`) that exposes
|
|
779
899
|
the debugger as a curated set of tools an AI agent can call. The MCP
|
|
780
900
|
server is a third in-process consumer of the same dispatch handlers the
|
|
781
|
-
TUI and the HTTP server use
|
|
901
|
+
TUI and the HTTP server use so an agent gets the same lock semantics,
|
|
782
902
|
including the pause-during-continue bypass, and the same DAP-backed
|
|
783
903
|
inspection surface.
|
|
784
904
|
|
|
@@ -817,17 +937,24 @@ client expects to launch servers.
|
|
|
817
937
|
| Breakpoints | `set_breakpoint(spec, condition?, hit_condition?)`, `remove_breakpoint(spec)`, `list_breakpoints()` |
|
|
818
938
|
| Differentiators | `threads(thread_id?)`, `tasks(task_name?)`, `processes(name_or_pid?)`, `wait_graph()` |
|
|
819
939
|
|
|
820
|
-
`control` is intentionally one tool that takes an action enum
|
|
940
|
+
`control` is intentionally one tool that takes an action enum. The six
|
|
821
941
|
underlying RPC actions share a return shape, and agents perform
|
|
822
942
|
measurably better with a small surface than with one tool per action.
|
|
823
943
|
`threads` / `tasks` / `processes` overload list-vs-inspect via a
|
|
824
944
|
single optional argument for the same reason.
|
|
825
945
|
|
|
946
|
+
`debug_launch` accepts optional `lang` and `adapter` parameters mirroring the
|
|
947
|
+
CLI's `--lang`/`--adapter`; when omitted, the language is auto-detected from
|
|
948
|
+
`program`, so an agent can hand it a compiled binary directly. The
|
|
949
|
+
`tasks`/`processes`/`wait_graph` tools stay registered for every language but
|
|
950
|
+
return a structured "not supported when debugging C/C++"-style error for
|
|
951
|
+
non-Python debuggees.
|
|
952
|
+
|
|
826
953
|
### Agent flow for a long-running step
|
|
827
954
|
|
|
828
955
|
```
|
|
829
956
|
agent → control(action="continue", timeout_s=30)
|
|
830
|
-
mcp → "still running
|
|
957
|
+
mcp → "still running, call pause or wait again"
|
|
831
958
|
agent → control(action="pause") # OR: control(action="wait_for_stop", timeout_s=30)
|
|
832
959
|
mcp → "<file>:<line>"
|
|
833
960
|
agent → inspect(["x", "len(buf)"])
|
|
@@ -836,7 +963,7 @@ mcp → "x = 7\nlen(buf) = 1024"
|
|
|
836
963
|
|
|
837
964
|
`pause` bypasses the dispatch lock so it can interrupt a `continue`
|
|
838
965
|
that's still mid-flight (HTTP and MCP share the same `NO_LOCK_ACTIONS`
|
|
839
|
-
policy
|
|
966
|
+
policy; see `tdb/server/app.py`).
|
|
840
967
|
|
|
841
968
|
### Security caveat
|
|
842
969
|
|
|
@@ -845,22 +972,23 @@ execution in the debuggee process**. This is inherent to a debugger and
|
|
|
845
972
|
not a tdb-specific concern, but MCP clients (and the humans running
|
|
846
973
|
them) should apply appropriate permission models: don't auto-approve
|
|
847
974
|
`inspect` against untrusted expressions, and don't expose `tdb-mcp` on
|
|
848
|
-
a network
|
|
975
|
+
a network (stdio transport only by design).
|
|
849
976
|
|
|
850
977
|
### Deferred / out of scope (v1)
|
|
851
978
|
|
|
852
|
-
- SSE-style event push
|
|
979
|
+
- SSE-style event push: `control` and `wait_for_stop` make polling
|
|
853
980
|
efficient enough; events would also need uneven MCP-client support.
|
|
854
|
-
- HTTP / streamable-HTTP transports
|
|
981
|
+
- HTTP / streamable-HTTP transports: would require auth (which the
|
|
855
982
|
HTTP RPC server also currently lacks); stdio inherits the trust of
|
|
856
983
|
the process that spawned it.
|
|
857
|
-
- Multi-session
|
|
984
|
+
- Multi-session: one debug session per MCP process.
|
|
858
985
|
|
|
859
986
|
## CLI Reference
|
|
860
987
|
|
|
861
988
|
```
|
|
862
989
|
usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
863
990
|
[--no-just-my-code] [--no-subprocess] [--python PYTHON] [--pv]
|
|
991
|
+
[--lang LANGUAGE] [--adapter ADAPTER]
|
|
864
992
|
[--keybindings {default,vim,emacs}]
|
|
865
993
|
[--terminal {xterm,konsole,gnome-terminal,ghostty,kitty,iterm2,warp,wezterm,terminator}]
|
|
866
994
|
[--local-root PATH] [--remote-root PATH]
|
|
@@ -876,8 +1004,10 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
876
1004
|
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated). Passing `-k` implies `--no-stop-on-entry` so the program runs straight to the first breakpoint. |
|
|
877
1005
|
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
878
1006
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
879
|
-
| `--python PATH` | Python interpreter for the debuggee |
|
|
1007
|
+
| `--python PATH` | Python interpreter for the debuggee (Python targets only) |
|
|
880
1008
|
| `--pv` | Shorthand for --python .venv/bin/python |
|
|
1009
|
+
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`); default: auto-detect from the target |
|
|
1010
|
+
| `--adapter ADAPTER` | Debug adapter within the language (e.g. `--lang cpp --adapter lldb-dap`); default: the language's standard adapter |
|
|
881
1011
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
882
1012
|
(default: skipped). On uncaught exceptions, the crash modal always shows the full traceback
|
|
883
1013
|
including library frames, regardless of this flag. |
|
|
@@ -897,9 +1027,14 @@ On Windows, it uses `%APPDATA%\tdb\`.
|
|
|
897
1027
|
|
|
898
1028
|
| File | Contents |
|
|
899
1029
|
|------|----------|
|
|
900
|
-
| `config.json` | User preferences (keybinding scheme, color theme, step mode) |
|
|
1030
|
+
| `config.json` | User preferences (keybinding scheme, color theme, step mode, adapter overrides) |
|
|
901
1031
|
| `breakpoints.json` | Breakpoints from previous sessions, keyed by project directory |
|
|
902
1032
|
|
|
1033
|
+
Adapter-related keys in `config.json`: `adapters` maps an adapter id to an
|
|
1034
|
+
executable path (`{"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"}}`), and
|
|
1035
|
+
`default_adapters` picks a language's default adapter
|
|
1036
|
+
(`{"default_adapters": {"cpp": "lldb-dap"}}`).
|
|
1037
|
+
|
|
903
1038
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
904
1039
|
directory. Each project's breakpoints are independent.
|
|
905
1040
|
|
|
@@ -919,7 +1054,8 @@ fires as expected.
|
|
|
919
1054
|
## Tech Stack
|
|
920
1055
|
|
|
921
1056
|
- [textual](https://github.com/Textualize/textual) : TUI framework
|
|
922
|
-
- [debugpy](https://github.com/microsoft/debugpy) : Debug Adapter Protocol implementation
|
|
1057
|
+
- [debugpy](https://github.com/microsoft/debugpy) : Debug Adapter Protocol implementation for Python
|
|
1058
|
+
- [gdb](https://sourceware.org/gdb/) / [lldb-dap](https://lldb.llvm.org/resources/lldbdap.html) : optional, user-installed DAP adapters for C/C++
|
|
923
1059
|
- [pygments](https://pygments.org/) : Syntax highlighting
|
|
924
1060
|
- [FastAPI](https://fastapi.tiangolo.com/) + [uvicorn](https://www.uvicorn.org/) : JSON-RPC server
|
|
925
1061
|
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
# `textual-debugger`
|
|
2
2
|
|
|
3
3
|
`textual-debugger` (the package) provides `tdb` (the command-line tool and module),
|
|
4
|
-
a full-featured terminal-based Python
|
|
5
|
-
|
|
6
|
-
`
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
a full-featured terminal-based debugger for Python and other languages
|
|
5
|
+
with a Debug Adapter Protocol (DAP) implementation. C and C++ support (via
|
|
6
|
+
`gdb` or `lldb-dap`) is built in.
|
|
7
|
+
|
|
8
|
+
`tdb` is built with [textual](https://github.com/Textualize/textual) and speaks
|
|
9
|
+
DAP to a pluggable debug adapter: [debugpy](https://github.com/microsoft/debugpy)
|
|
10
|
+
(the engine behind VS Code's Python debugger) for Python,
|
|
11
|
+
[GDB's DAP mode](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html) or
|
|
12
|
+
[lldb-dap](https://lldb.llvm.org/resources/lldbdap.html)
|
|
13
|
+
for compiled code. It provides a rich interactive interface for stepping through
|
|
14
|
+
code, inspecting variables, managing breakpoints, and evaluating expressions in
|
|
15
|
+
complex programs.
|
|
10
16
|
|
|
11
17
|
- PyPI: https://pypi.org/project/textual-debugger/
|
|
12
18
|
- GitHub: https://github.com/AlDanial/tdb
|
|
@@ -17,6 +23,10 @@ MIT License. Copyright 2026 by Al Danial.
|
|
|
17
23
|
|
|
18
24
|
`tdb`:
|
|
19
25
|
|
|
26
|
+
- debugs multiple languages through the Debug Adapter Protocol: Python (via `debugpy`,
|
|
27
|
+
the richest feature set) and C/C++ (via `gdb -i dap` or `lldb-dap`), with the language
|
|
28
|
+
auto-detected from the target (ref. [Multi-Language Debugging](#multi-language-debugging)).
|
|
29
|
+
|
|
20
30
|
- supports debugging of synchronous, asynchronous, multi-threaded, and multi-process Python code.
|
|
21
31
|
It specifically supports modules
|
|
22
32
|
- `asyncio` (with a built-in async task inspector and task wait graph)
|
|
@@ -25,7 +35,8 @@ It specifically supports modules
|
|
|
25
35
|
|
|
26
36
|
- supports remote attachment to debugpy-enabled Python programs
|
|
27
37
|
|
|
28
|
-
- includes a JSON-RPC server mode
|
|
38
|
+
- includes a JSON-RPC server mode, an MCP mode, and a `SKILL.md` file that enable
|
|
39
|
+
programmatic debug control, making it suitable for
|
|
29
40
|
automated, headless debugging workflows and AI-assisted debugging
|
|
30
41
|
|
|
31
42
|
- can spawn the debuggee in an external terminal to enable debugging TUI applications
|
|
@@ -54,6 +65,9 @@ as open source.
|
|
|
54
65
|
[Claude for Open Source](https://claude.com/contact-sales/claude-for-oss) program.
|
|
55
66
|
`tdb` was made almost entirely with Claude Code.
|
|
56
67
|
|
|
68
|
+
- OpenAI, for providing access to Codex through the
|
|
69
|
+
[Codex for Open Source](https://developers.openai.com/community/codex-for-oss) program.
|
|
70
|
+
|
|
57
71
|
## Gallery
|
|
58
72
|
<p align="center">
|
|
59
73
|
<img src="https://github.com/AlDanial/tdb/blob/main/gallery/async_breakpoint.png" alt="at breakpoint" width="300">
|
|
@@ -99,6 +113,16 @@ tdb my_program.py
|
|
|
99
113
|
# debug with arguments
|
|
100
114
|
tdb my_program.py arg1 arg2
|
|
101
115
|
|
|
116
|
+
# debug a C/C++ (or other native) executable built with -g. The ELF/Mach-O/PE
|
|
117
|
+
# binary is auto-detected and debugged through GDB's DAP mode (GDB >= 14)
|
|
118
|
+
tdb ./myprog arg1 arg2
|
|
119
|
+
|
|
120
|
+
# same, but using lldb-dap (LLVM >= 17) instead of gdb
|
|
121
|
+
tdb --adapter lldb-dap ./myprog
|
|
122
|
+
|
|
123
|
+
# force the language when auto-detection can't tell (e.g. an extensionless script)
|
|
124
|
+
tdb --lang python ./mytool
|
|
125
|
+
|
|
102
126
|
# add breakpoints at lines 20 and 35 of `my_program.py` and line 14
|
|
103
127
|
# of `module.py` (when -k is given, --no-stop-on-entry is set and the
|
|
104
128
|
# program runs to the first breakpoint)
|
|
@@ -140,6 +164,79 @@ Alternatively, use the module entry point:
|
|
|
140
164
|
python -m tdb my_program.py
|
|
141
165
|
```
|
|
142
166
|
|
|
167
|
+
## Multi-Language Debugging
|
|
168
|
+
|
|
169
|
+
`tdb` debugs any language that has a Debug Adapter Protocol backend. Two
|
|
170
|
+
languages are supported out of the box:
|
|
171
|
+
|
|
172
|
+
| Language | Adapter(s) | How to get the adapter | Feature level |
|
|
173
|
+
|----------|------------|------------------------|---------------|
|
|
174
|
+
| Python | `debugpy` (default) | installed with `textual-debugger` | everything in this README |
|
|
175
|
+
| C / C++ (any native binary) | `gdb` (default), `lldb-dap` (alternate) | `gdb -i dap` requires GDB ≥ 14; `lldb-dap` ships with LLVM ≥ 17 (e.g. `apt install lldb`) | core debugging: breakpoints, stepping, stack, variables, evaluate console |
|
|
176
|
+
|
|
177
|
+
### Language detection and selection
|
|
178
|
+
|
|
179
|
+
The language is auto-detected from the debug target:
|
|
180
|
+
|
|
181
|
+
1. File extension: `.py` → Python.
|
|
182
|
+
2. Native executables (ELF, Mach-O, PE magic bytes) → C/C++.
|
|
183
|
+
3. A `#!...python` shebang → Python.
|
|
184
|
+
4. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
|
|
185
|
+
hint: compile with debug info (`g++ -g -O0`) and debug the binary.
|
|
186
|
+
5. Anything else produces an error naming the `--lang` override.
|
|
187
|
+
|
|
188
|
+
`--lang` forces the language; `--adapter` picks a non-default adapter within
|
|
189
|
+
it (`tdb --lang cpp --adapter lldb-dap ./myprog`).
|
|
190
|
+
|
|
191
|
+
> **Migration note:** extensionless Python scripts without a `python` shebang
|
|
192
|
+
> were previously assumed to be Python; they now require `--lang python`.
|
|
193
|
+
|
|
194
|
+
### Adapters are found on `PATH`
|
|
195
|
+
|
|
196
|
+
`tdb` does not download or bundle adapters. If the adapter executable isn't
|
|
197
|
+
found, the error names the package to install. To use an adapter from a
|
|
198
|
+
non-standard location, or change a language's default adapter, add to
|
|
199
|
+
`config.json` (see [Configuration](#configuration)):
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"},
|
|
204
|
+
"default_adapters": {"cpp": "lldb-dap"}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### What works for non-Python languages
|
|
209
|
+
|
|
210
|
+
Core debugging works identically for every language: breakpoints (incl.
|
|
211
|
+
conditions and persistence), stepping, continue/pause, run-to-cursor, stack
|
|
212
|
+
navigation, variable inspection, the evaluate console, syntax highlighting,
|
|
213
|
+
and the JSON-RPC / MCP programmatic modes.
|
|
214
|
+
|
|
215
|
+
Python-specific features are hidden or return a clear "not supported for this
|
|
216
|
+
language" message when debugging other languages: statement-granularity
|
|
217
|
+
stepping (non-Python languages always step per line), the async task /
|
|
218
|
+
process inspectors and wait graph, the evaluate console's trailing-`?` help,
|
|
219
|
+
remote attach (`-r`), `--python`/`--pv`, `--no-subprocess`,
|
|
220
|
+
automatic child-process attachment, and the post-mortem / `tdb.breakpoint()`
|
|
221
|
+
hooks (those hooks live inside Python programs by nature). `--terminal` is
|
|
222
|
+
currently ignored for non-Python targets.
|
|
223
|
+
|
|
224
|
+
### C/C++ tips
|
|
225
|
+
|
|
226
|
+
- Compile with `-g` (ideally `-g -O0`). If no breakpoint in a file can be
|
|
227
|
+
bound, `tdb` prints a console warning suggesting the program may lack
|
|
228
|
+
debug info.
|
|
229
|
+
- Stack frames pointing into system libraries often have no source on disk;
|
|
230
|
+
the Code View shows a `<Could not read …>` placeholder while the stack,
|
|
231
|
+
variables, and evaluate console remain fully usable.
|
|
232
|
+
- GDB (the default adapter) has the most complete libstdc++
|
|
233
|
+
pretty-printing. `lldb-dap` (via `--adapter lldb-dap`) also debugs
|
|
234
|
+
GCC-built binaries fine — DWARF is compiler-neutral.
|
|
235
|
+
- **GDB evaluate-console quirk:** GDB's DAP treats REPL input as CLI
|
|
236
|
+
commands, so evaluate expressions with an explicit `print`, e.g.
|
|
237
|
+
`print x` rather than bare `x` (bare `x` collides with GDB's
|
|
238
|
+
examine-memory command). `lldb-dap` evaluates bare expressions directly.
|
|
239
|
+
|
|
143
240
|
## Layout
|
|
144
241
|
|
|
145
242
|
```
|
|
@@ -168,7 +265,7 @@ The footer shows the most relevant keybindings for the current mode.
|
|
|
168
265
|
### Navigation and Keybindings
|
|
169
266
|
|
|
170
267
|
|
|
171
|
-
The Code View shows syntax-highlighted
|
|
268
|
+
The Code View shows syntax-highlighted source (lexer chosen per language) with line numbers.
|
|
172
269
|
A cursor line (blue) tracks your position; the current execution line is highlighted in gold.
|
|
173
270
|
|
|
174
271
|
**View focus shortcuts (global):**
|
|
@@ -260,6 +357,9 @@ lands on `print(results)`, not on each interior sub-line of the `gather` call. S
|
|
|
260
357
|
stops on each physical line--useful for inspecting how a complex expression is built up.
|
|
261
358
|
The choice is saved to `~/.config/tdb/config.json`.
|
|
262
359
|
|
|
360
|
+
Statement mode requires a source-language model and is currently Python-only;
|
|
361
|
+
other languages always step per line (the Step Mode menu says so if you try).
|
|
362
|
+
|
|
263
363
|
### Breakpoints
|
|
264
364
|
|
|
265
365
|
Click the gutter in the Code View to toggle a breakpoint, or press `b` in Debug mode.
|
|
@@ -317,6 +417,15 @@ interactive evaluation of expressions in the current scope:
|
|
|
317
417
|
|
|
318
418
|
Variable values set here are reflected in the running code.
|
|
319
419
|
|
|
420
|
+
### Cut / Paste
|
|
421
|
+
|
|
422
|
+
Expression for the Evaluate Console are often copied from the Code View.
|
|
423
|
+
Doing this in `tdb` differs from traditional terminal behavior, because `textual` applications
|
|
424
|
+
capture mouse events for their own use.
|
|
425
|
+
|
|
426
|
+
Instead, hold the `Shift` key while performing your conventional cut/paste keystrokes or mouse
|
|
427
|
+
operation to get the expected behavior.
|
|
428
|
+
|
|
320
429
|
### Console Output
|
|
321
430
|
|
|
322
431
|
The Console View captures stdout (normal text) and stderr (red text) from the debuggee
|
|
@@ -376,6 +485,17 @@ Snapshot depth / breadth is capped (5 levels, 50 children per container) to keep
|
|
|
376
485
|
capture cheap even for pathological object graphs; cycles are handled via identity
|
|
377
486
|
memoization.
|
|
378
487
|
|
|
488
|
+
### Post-Mortem within a Docker Container
|
|
489
|
+
|
|
490
|
+
The `textual-debugger` GitHub repository's `examples/` directory has three files
|
|
491
|
+
that show how to run a `tdb`-enabled Python program under `tmux` in a Docker
|
|
492
|
+
container so that you can attach to the container and inspect the program
|
|
493
|
+
in `tdb` post-mortem analysis mode if the program hits an unhandled exception:
|
|
494
|
+
|
|
495
|
+
- [post_mortem_example.py](https://github.com/AlDanial/tdb/blob/main/examples/post_mortem_example.py)
|
|
496
|
+
- [post_mortem_entrypoint.sh](https://github.com/AlDanial/tdb/blob/main/examples/post_mortem_entrypoint.sh)
|
|
497
|
+
- [Dockerfile.post_mortem](https://github.com/AlDanial/tdb/blob/main/examples/Dockerfile.post_mortem)
|
|
498
|
+
|
|
379
499
|
### Live Breakpoint Hook
|
|
380
500
|
|
|
381
501
|
`tdb` has an improved implemenation of the standard `breakpoint()` function (or equivalently,
|
|
@@ -673,7 +793,7 @@ curl -s -X POST http://127.0.0.1:8150/rpc \
|
|
|
673
793
|
| `set_breakpoint` | `["file:line"]` or `["file:line", "condition", "hit_condition"]` | Set a breakpoint |
|
|
674
794
|
| `remove_breakpoint` | `["file:line"]` | Remove a breakpoint |
|
|
675
795
|
| `list_breakpoints` | `[]` | Show all breakpoints |
|
|
676
|
-
| `continue` | `[]` or `[timeout_s]` | Resume execution; on timeout returns `"still running
|
|
796
|
+
| `continue` | `[]` or `[timeout_s]` | Resume execution; on timeout returns `"still running--call pause or wait again"` (success) |
|
|
677
797
|
| `next` | `[]` or `[timeout_s]` | Step over |
|
|
678
798
|
| `step_in` | `[]` or `[timeout_s]` | Step into |
|
|
679
799
|
| `step_out` | `[]` or `[timeout_s]` | Step out |
|
|
@@ -712,7 +832,7 @@ Each is JSON with `event`, `data`, and `timestamp` fields.
|
|
|
712
832
|
tdb ships a Model Context Protocol (MCP) server (`tdb-mcp`) that exposes
|
|
713
833
|
the debugger as a curated set of tools an AI agent can call. The MCP
|
|
714
834
|
server is a third in-process consumer of the same dispatch handlers the
|
|
715
|
-
TUI and the HTTP server use
|
|
835
|
+
TUI and the HTTP server use so an agent gets the same lock semantics,
|
|
716
836
|
including the pause-during-continue bypass, and the same DAP-backed
|
|
717
837
|
inspection surface.
|
|
718
838
|
|
|
@@ -751,17 +871,24 @@ client expects to launch servers.
|
|
|
751
871
|
| Breakpoints | `set_breakpoint(spec, condition?, hit_condition?)`, `remove_breakpoint(spec)`, `list_breakpoints()` |
|
|
752
872
|
| Differentiators | `threads(thread_id?)`, `tasks(task_name?)`, `processes(name_or_pid?)`, `wait_graph()` |
|
|
753
873
|
|
|
754
|
-
`control` is intentionally one tool that takes an action enum
|
|
874
|
+
`control` is intentionally one tool that takes an action enum. The six
|
|
755
875
|
underlying RPC actions share a return shape, and agents perform
|
|
756
876
|
measurably better with a small surface than with one tool per action.
|
|
757
877
|
`threads` / `tasks` / `processes` overload list-vs-inspect via a
|
|
758
878
|
single optional argument for the same reason.
|
|
759
879
|
|
|
880
|
+
`debug_launch` accepts optional `lang` and `adapter` parameters mirroring the
|
|
881
|
+
CLI's `--lang`/`--adapter`; when omitted, the language is auto-detected from
|
|
882
|
+
`program`, so an agent can hand it a compiled binary directly. The
|
|
883
|
+
`tasks`/`processes`/`wait_graph` tools stay registered for every language but
|
|
884
|
+
return a structured "not supported when debugging C/C++"-style error for
|
|
885
|
+
non-Python debuggees.
|
|
886
|
+
|
|
760
887
|
### Agent flow for a long-running step
|
|
761
888
|
|
|
762
889
|
```
|
|
763
890
|
agent → control(action="continue", timeout_s=30)
|
|
764
|
-
mcp → "still running
|
|
891
|
+
mcp → "still running, call pause or wait again"
|
|
765
892
|
agent → control(action="pause") # OR: control(action="wait_for_stop", timeout_s=30)
|
|
766
893
|
mcp → "<file>:<line>"
|
|
767
894
|
agent → inspect(["x", "len(buf)"])
|
|
@@ -770,7 +897,7 @@ mcp → "x = 7\nlen(buf) = 1024"
|
|
|
770
897
|
|
|
771
898
|
`pause` bypasses the dispatch lock so it can interrupt a `continue`
|
|
772
899
|
that's still mid-flight (HTTP and MCP share the same `NO_LOCK_ACTIONS`
|
|
773
|
-
policy
|
|
900
|
+
policy; see `tdb/server/app.py`).
|
|
774
901
|
|
|
775
902
|
### Security caveat
|
|
776
903
|
|
|
@@ -779,22 +906,23 @@ execution in the debuggee process**. This is inherent to a debugger and
|
|
|
779
906
|
not a tdb-specific concern, but MCP clients (and the humans running
|
|
780
907
|
them) should apply appropriate permission models: don't auto-approve
|
|
781
908
|
`inspect` against untrusted expressions, and don't expose `tdb-mcp` on
|
|
782
|
-
a network
|
|
909
|
+
a network (stdio transport only by design).
|
|
783
910
|
|
|
784
911
|
### Deferred / out of scope (v1)
|
|
785
912
|
|
|
786
|
-
- SSE-style event push
|
|
913
|
+
- SSE-style event push: `control` and `wait_for_stop` make polling
|
|
787
914
|
efficient enough; events would also need uneven MCP-client support.
|
|
788
|
-
- HTTP / streamable-HTTP transports
|
|
915
|
+
- HTTP / streamable-HTTP transports: would require auth (which the
|
|
789
916
|
HTTP RPC server also currently lacks); stdio inherits the trust of
|
|
790
917
|
the process that spawned it.
|
|
791
|
-
- Multi-session
|
|
918
|
+
- Multi-session: one debug session per MCP process.
|
|
792
919
|
|
|
793
920
|
## CLI Reference
|
|
794
921
|
|
|
795
922
|
```
|
|
796
923
|
usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
797
924
|
[--no-just-my-code] [--no-subprocess] [--python PYTHON] [--pv]
|
|
925
|
+
[--lang LANGUAGE] [--adapter ADAPTER]
|
|
798
926
|
[--keybindings {default,vim,emacs}]
|
|
799
927
|
[--terminal {xterm,konsole,gnome-terminal,ghostty,kitty,iterm2,warp,wezterm,terminator}]
|
|
800
928
|
[--local-root PATH] [--remote-root PATH]
|
|
@@ -810,8 +938,10 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
810
938
|
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated). Passing `-k` implies `--no-stop-on-entry` so the program runs straight to the first breakpoint. |
|
|
811
939
|
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
812
940
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
813
|
-
| `--python PATH` | Python interpreter for the debuggee |
|
|
941
|
+
| `--python PATH` | Python interpreter for the debuggee (Python targets only) |
|
|
814
942
|
| `--pv` | Shorthand for --python .venv/bin/python |
|
|
943
|
+
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`); default: auto-detect from the target |
|
|
944
|
+
| `--adapter ADAPTER` | Debug adapter within the language (e.g. `--lang cpp --adapter lldb-dap`); default: the language's standard adapter |
|
|
815
945
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
816
946
|
(default: skipped). On uncaught exceptions, the crash modal always shows the full traceback
|
|
817
947
|
including library frames, regardless of this flag. |
|
|
@@ -831,9 +961,14 @@ On Windows, it uses `%APPDATA%\tdb\`.
|
|
|
831
961
|
|
|
832
962
|
| File | Contents |
|
|
833
963
|
|------|----------|
|
|
834
|
-
| `config.json` | User preferences (keybinding scheme, color theme, step mode) |
|
|
964
|
+
| `config.json` | User preferences (keybinding scheme, color theme, step mode, adapter overrides) |
|
|
835
965
|
| `breakpoints.json` | Breakpoints from previous sessions, keyed by project directory |
|
|
836
966
|
|
|
967
|
+
Adapter-related keys in `config.json`: `adapters` maps an adapter id to an
|
|
968
|
+
executable path (`{"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"}}`), and
|
|
969
|
+
`default_adapters` picks a language's default adapter
|
|
970
|
+
(`{"default_adapters": {"cpp": "lldb-dap"}}`).
|
|
971
|
+
|
|
837
972
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
838
973
|
directory. Each project's breakpoints are independent.
|
|
839
974
|
|
|
@@ -853,7 +988,8 @@ fires as expected.
|
|
|
853
988
|
## Tech Stack
|
|
854
989
|
|
|
855
990
|
- [textual](https://github.com/Textualize/textual) : TUI framework
|
|
856
|
-
- [debugpy](https://github.com/microsoft/debugpy) : Debug Adapter Protocol implementation
|
|
991
|
+
- [debugpy](https://github.com/microsoft/debugpy) : Debug Adapter Protocol implementation for Python
|
|
992
|
+
- [gdb](https://sourceware.org/gdb/) / [lldb-dap](https://lldb.llvm.org/resources/lldbdap.html) : optional, user-installed DAP adapters for C/C++
|
|
857
993
|
- [pygments](https://pygments.org/) : Syntax highlighting
|
|
858
994
|
- [FastAPI](https://fastapi.tiangolo.com/) + [uvicorn](https://www.uvicorn.org/) : JSON-RPC server
|
|
859
995
|
|