textual-debugger 0.2.10__tar.gz → 0.2.12__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.
Files changed (159) hide show
  1. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/PKG-INFO +128 -41
  2. {textual_debugger-0.2.10/src/tdb → textual_debugger-0.2.12}/README.md +126 -39
  3. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/pyproject.toml +2 -2
  4. {textual_debugger-0.2.10 → textual_debugger-0.2.12/src/tdb}/README.md +126 -39
  5. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/__init__.py +1 -1
  6. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/_timeouts.py +7 -0
  7. textual_debugger-0.2.12/src/tdb/adapters/perl/padwalker.py +286 -0
  8. textual_debugger-0.2.12/src/tdb/adapters/perl/padwalker_src/Makefile.PL +38 -0
  9. textual_debugger-0.2.12/src/tdb/adapters/perl/padwalker_src/PadWalker.pm +160 -0
  10. textual_debugger-0.2.12/src/tdb/adapters/perl/padwalker_src/PadWalker.xs +645 -0
  11. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/perl/session.py +15 -0
  12. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/app.py +28 -16
  13. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/app_handlers/dap_events.py +3 -0
  14. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/app_helpers.py +51 -0
  15. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/cli.py +183 -11
  16. textual_debugger-0.2.12/src/tdb/examine.py +302 -0
  17. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/mcp/server.py +12 -9
  18. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/mcp/session.py +1 -1
  19. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/replay.py +28 -8
  20. textual_debugger-0.2.12/src/tdb/replay_tui.py +311 -0
  21. textual_debugger-0.2.12/src/tdb/run_mode.py +514 -0
  22. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/server/handlers.py +3 -3
  23. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/controller.py +90 -16
  24. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/evaluate_console.py +12 -7
  25. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/textual_debugger.egg-info/PKG-INFO +128 -41
  26. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/textual_debugger.egg-info/SOURCES.txt +6 -0
  27. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/textual_debugger.egg-info/requires.txt +1 -1
  28. textual_debugger-0.2.10/src/tdb/run_mode.py +0 -305
  29. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/LICENSE +0 -0
  30. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/setup.cfg +0 -0
  31. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/__main__.py +0 -0
  32. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/__init__.py +0 -0
  33. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/bash/__init__.py +0 -0
  34. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/bash/__main__.py +0 -0
  35. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/bash/declares.py +0 -0
  36. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/bash/server.py +0 -0
  37. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/bash/session.py +0 -0
  38. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/bash/tdb_harness.sh +0 -0
  39. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/ocaml/__init__.py +0 -0
  40. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/ocaml/lldb_formatters.py +0 -0
  41. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/perl/Devel/TdbCompile.pm +0 -0
  42. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/perl/Devel/TdbRemote.pm +0 -0
  43. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/perl/__init__.py +0 -0
  44. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/perl/__main__.py +0 -0
  45. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/perl/helpers.pl +0 -0
  46. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/perl/protocol.py +0 -0
  47. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/perl/refs.py +0 -0
  48. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/perl/server.py +0 -0
  49. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/powershell/__init__.py +0 -0
  50. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/powershell/__main__.py +0 -0
  51. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/powershell/locate.py +0 -0
  52. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/powershell/output.py +0 -0
  53. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/powershell/server.py +0 -0
  54. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/powershell/tdb_launch.ps1 +0 -0
  55. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/ruby/__init__.py +0 -0
  56. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/ruby/__main__.py +0 -0
  57. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/ruby/server.py +0 -0
  58. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/seqs.py +0 -0
  59. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/__init__.py +0 -0
  60. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/__main__.py +0 -0
  61. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/breakpoints.py +0 -0
  62. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/cli.py +0 -0
  63. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/guardian.py +0 -0
  64. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/inspect.py +0 -0
  65. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/instrumenter.py +0 -0
  66. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/models.py +0 -0
  67. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/protocol.py +0 -0
  68. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/runtime.py +0 -0
  69. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/scanner.py +0 -0
  70. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/server.py +0 -0
  71. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/session.py +0 -0
  72. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/adapters/tcsh/transport.py +0 -0
  73. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/app_handlers/__init__.py +0 -0
  74. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/app_handlers/inspection.py +0 -0
  75. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/app_handlers/routing.py +0 -0
  76. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/app_handlers/ui_panels.py +0 -0
  77. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/breakpoint_hook.py +0 -0
  78. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/dap/__init__.py +0 -0
  79. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/dap/client.py +0 -0
  80. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/dap/messages.py +0 -0
  81. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/dap/protocol.py +0 -0
  82. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/dap/reverse.py +0 -0
  83. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/dap/types.py +0 -0
  84. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/eval_mode.py +0 -0
  85. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/go_concurrency/__init__.py +0 -0
  86. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/go_concurrency/analyzer.py +0 -0
  87. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/go_concurrency/classifier.py +0 -0
  88. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/go_concurrency/collector.py +0 -0
  89. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/go_concurrency/models.py +0 -0
  90. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/inspection.py +0 -0
  91. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/inspection_full.py +0 -0
  92. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/keybindings/__init__.py +0 -0
  93. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/__init__.py +0 -0
  94. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/base.py +0 -0
  95. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/bash.py +0 -0
  96. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/cpp.py +0 -0
  97. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/errors.py +0 -0
  98. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/go.py +0 -0
  99. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/ocaml.py +0 -0
  100. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/perl.py +0 -0
  101. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/powershell.py +0 -0
  102. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/python.py +0 -0
  103. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/registry.py +0 -0
  104. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/ruby.py +0 -0
  105. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/rust.py +0 -0
  106. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/languages/tcsh.py +0 -0
  107. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/mcp/__init__.py +0 -0
  108. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/mcp/__main__.py +0 -0
  109. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/persist.py +0 -0
  110. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/post_mortem.py +0 -0
  111. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/processes_cache.py +0 -0
  112. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/__init__.py +0 -0
  113. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/analyzer.py +0 -0
  114. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/classifier.py +0 -0
  115. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/collector.py +0 -0
  116. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/models.py +0 -0
  117. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/probes/__init__.py +0 -0
  118. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/probes/base.py +0 -0
  119. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/probes/gdb.py +0 -0
  120. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/probes/gdb_script.py +0 -0
  121. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/probes/lldb.py +0 -0
  122. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/rust_concurrency/probes/lldb_script.py +0 -0
  123. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/server/__init__.py +0 -0
  124. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/server/app.py +0 -0
  125. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/server/event_handler.py +0 -0
  126. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/server/rpc_types.py +0 -0
  127. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/server/runner.py +0 -0
  128. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/__init__.py +0 -0
  129. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/child_processes.py +0 -0
  130. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/errors.py +0 -0
  131. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/event_bus.py +0 -0
  132. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/inspect_service.py +0 -0
  133. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/messages.py +0 -0
  134. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/post_mortem_loader.py +0 -0
  135. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/recorder.py +0 -0
  136. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/state.py +0 -0
  137. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/statement_stepper.py +0 -0
  138. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/terminal.py +0 -0
  139. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/session/textual_handler.py +0 -0
  140. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/source_analysis.py +0 -0
  141. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/__init__.py +0 -0
  142. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/_inspection_modal.py +0 -0
  143. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/async_tasks_modal.py +0 -0
  144. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/breakpoint_view.py +0 -0
  145. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/code_view.py +0 -0
  146. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/console_view.py +0 -0
  147. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/full_contents_modal.py +0 -0
  148. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/goroutines_modal.py +0 -0
  149. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/menu_bar.py +0 -0
  150. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/modals.py +0 -0
  151. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/processes_modal.py +0 -0
  152. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/rust_concurrency_modal.py +0 -0
  153. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/stack_view.py +0 -0
  154. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/status_bar.py +0 -0
  155. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/threads_modal.py +0 -0
  156. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/tdb/widgets/variable_view.py +0 -0
  157. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
  158. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/src/textual_debugger.egg-info/entry_points.txt +0 -0
  159. {textual_debugger-0.2.10 → textual_debugger-0.2.12}/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.2.10
3
+ Version: 0.2.12
4
4
  Summary: A TUI debugger for Python, Perl, and other languages. Based on textual.
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:
@@ -53,7 +53,7 @@ Requires-Dist: debugpy>=1.8.12
53
53
  Requires-Dist: pygments>=2.17.0
54
54
  Requires-Dist: fastapi>=0.115.0
55
55
  Requires-Dist: uvicorn>=0.30.0
56
- Requires-Dist: mcp<2.0.0,>=1.28.0
56
+ Requires-Dist: mcp<3.0.0,>=2.0.0
57
57
  Provides-Extra: dev
58
58
  Requires-Dist: pytest; extra == "dev"
59
59
  Requires-Dist: pytest-cov; extra == "dev"
@@ -115,7 +115,7 @@ It specifically supports modules
115
115
 
116
116
  - supports remote attachment to Python, Perl, Ruby, Rust, C/C++, and Go programs
117
117
 
118
- - includes a JSON-RPC server mode, an MCP mode, and a `SKILL.md` file that enable
118
+ - includes a JSON-RPC server mode, an MCP (v2) mode, and a `SKILL.md` file that enable
119
119
  programmatic debug control, making it suitable for
120
120
  automated, headless debugging workflows and AI-assisted debugging
121
121
 
@@ -129,28 +129,6 @@ to have `tdb` pop open automatically at the first uncaught exception
129
129
  making it suitable for operation in non-graphical environments (mouse support is
130
130
  available in graphical environments)
131
131
 
132
- ## Acknowledgments
133
-
134
- Thank you:
135
-
136
- - Will McGugan for the amazing `textual` module.
137
- `tdb` would be a pale shadow of itself had I used any other TUI framework.
138
- Fantastic work, Will.
139
-
140
- - Microsoft for the Debug Adapter Protocol (DAP) and releasing
141
- its implementation in `debugpy` and the Python Debugger extension for Visual Studio Code
142
- as open source.
143
-
144
- - Anthropic, for providing access to Claude Code through the
145
- [Claude for Open Source](https://claude.com/contact-sales/claude-for-oss) program.
146
- `tdb` was made almost entirely with Claude Code.
147
-
148
- - OpenAI, for providing access to Codex through the
149
- [Codex for Open Source](https://developers.openai.com/community/codex-for-oss) program.
150
-
151
- This project was inspired by Andreas Klöckner's excellent [pudb](https://pypi.org/project/pudb/)
152
- Python debugger.
153
-
154
132
  ## Gallery
155
133
  <p align="center">
156
134
  <img src="https://github.com/AlDanial/tdb/blob/main/gallery/async_breakpoint.png" alt="at breakpoint" width="300">
@@ -190,6 +168,10 @@ uvx --from textual-debugger tdb my_program.py
190
168
  # show comprehensive documentation in a terminal-based Markdown viewer
191
169
  tdb --doc
192
170
 
171
+ # show where tdb is installed, where its bundled Perl PadWalker module
172
+ # lives, and the Help > About text
173
+ tdb --info
174
+
193
175
  # debug a script (stops at first line by default)
194
176
  tdb my_program.py
195
177
 
@@ -337,7 +319,7 @@ non-standard location, or change a language's default adapter, add to
337
319
  Core debugging works identically for every language: breakpoints (incl.
338
320
  conditions and persistence), stepping, continue/pause, run-to-cursor, stack
339
321
  navigation, variable inspection, the evaluate console, syntax highlighting,
340
- and the JSON-RPC / MCP programmatic modes.
322
+ and the JSON-RPC / MCP (v2) programmatic modes.
341
323
 
342
324
  Python-specific features are hidden or return "not supported for this
343
325
  language" message when debugging other languages: statement-granularity
@@ -541,6 +523,24 @@ metadata for broader primitives and stronger ownership evidence.
541
523
  `perl` ≥ 5.18 on `PATH`. It drives stock `perl5db` under the
542
524
  hood, so it works with any Perl already on the system.
543
525
 
526
+ The [PadWalker](https://metacpan.org/pod/PadWalker) module v2.5, by Robin Houston,
527
+ is bundled with `tdb`. PadWalker provides a more complete view of lexical variables
528
+ in outer/caller frames and therefore provides a richer debugging experience.
529
+ PadWalker is an XS (compiled) module, so the bundled copy has to be built
530
+ against the exact perl that runs your program. `tdb` does this for you on the
531
+ first Perl launch: if the perl in use cannot already load PadWalker (from CPAN
532
+ or a distro package), `tdb` compiles the bundled sources, caches the result
533
+ per interpreter under its config directory (`~/.config/tdb/padwalker/` on
534
+ Linux/macOS, `%APPDATA%\\tdb\\padwalker\\` on Windows), and prepends that
535
+ directory to the debuggee's `PERL5LIB`. The build takes about a second and
536
+ needs perl's headers (`libperl-dev` on Debian/Ubuntu, `perl-devel` on
537
+ Fedora/RHEL) plus a C compiler; Strawberry Perl on Windows ships both. When
538
+ the build is not possible, `tdb` prints a one-line notice on the console and
539
+ falls back to a read-only pad walk, so outer-frame lexicals degrade but
540
+ debugging otherwise proceeds. `tdb --info` reports the source directory, the
541
+ cache directory, and whether a build exists for the `perl` on your `PATH`.
542
+ `TDB_PADWALKER_CACHE` overrides the cache location.
543
+
544
544
  **Launching a script:**
545
545
 
546
546
  ```bash
@@ -637,13 +637,6 @@ export PERL5LIB=/opt/tdb-perl:$PERL5LIB
637
637
  the two files in the same relative layout shown above; `helpers.pl` is a
638
638
  sibling of the `Devel/` directory, not inside it.)
639
639
 
640
- **PadWalker (optional but recommended):** inspecting lexical (`my`)
641
- variables in the *current* frame always works. Lexicals in outer/caller
642
- frames need the `PadWalker` module installed on the debuggee's Perl; without
643
- it, tdb falls back to a read-only pad walk that can't reach fully into
644
- enclosing scopes, and outer-frame variable listings degrade accordingly.
645
- Install with `cpanm PadWalker` (or your distro's package) for full fidelity.
646
-
647
640
  **Pause is unavailable in attach mode.** Launch-mode sessions (`tdb
648
641
  script.pl`) support pausing a running program at any time. Remote-attach
649
642
  sessions don't. Asynchronous pause (as Python gets via `debugpy`) needs a control channel
@@ -1517,6 +1510,54 @@ available (breakpoints, stepping, variable inspection, the evaluate console). Th
1517
1510
  debuggee itself never receives the signal (`tdb`'s adapter runs in its own process
1518
1511
  group), so its own `SIGINT` handling is undisturbed.
1519
1512
 
1513
+ **Examining without opening the TUI:** press `Ctrl-\` in the terminal (`Ctrl-Break` on
1514
+ Windows), or, on Unix, send `SIGUSR2` to `tdb`'s pid: `kill -USR2 <tdb pid>`.
1515
+
1516
+ **Windows caveat:** the Ctrl-Break trigger is untested. Unlike Ctrl-C, a console
1517
+ Ctrl-Break is delivered to every process attached to the console, including the debug
1518
+ adapter and the program itself, so it may terminate the program instead of snapshotting
1519
+ it. There is no signal-based alternative on Windows.
1520
+
1521
+ `tdb` pauses the program, writes one JSON line describing the call stack of every thread
1522
+ (plus asyncio tasks and multiprocessing children for Python, goroutines for Go, and
1523
+ the concurrency snapshot for Rust), and resumes the program. Ctrl-C behavior is
1524
+ unchanged. By default the line goes to stdout; `--examine-log DEST` sends it to a file
1525
+ instead (`-` means stdout; repeat the flag to write to several places):
1526
+
1527
+ ```bash
1528
+ tdb --run --examine-log hang.jsonl my_program.py # file only, appended
1529
+ tdb --run --examine-log - --examine-log hang.jsonl my_program.py # both
1530
+ ```
1531
+
1532
+ Each record looks like (abridged):
1533
+
1534
+ ```json
1535
+ {"schema":1,"seq":1,"trigger":"SIGQUIT","status":"ok",
1536
+ "requested_at":"2026-09-07T14:02:11.482-07:00","landed_at":"2026-09-07T14:02:11.511-07:00",
1537
+ "elapsed_s":87.3,"language":"python","program":"/home/al/work/app.py",
1538
+ "processes":[{"pid":41213,"role":"parent","name":null,
1539
+ "threads":[{"id":1,"name":"MainThread","frames":[
1540
+ {"function":"wait","file":"/usr/lib/python3.13/threading.py","line":359},
1541
+ {"function":"main","file":"/home/al/work/app.py","line":42}]}],
1542
+ "tasks":[{"name":"worker-2","state":"PENDING","awaiting":"Lock.acquire","frames":["run (/home/al/work/app.py:18)"]}]}],
1543
+ "errors":[]}
1544
+ ```
1545
+
1546
+ Frames are innermost first. `tasks` appears only for Python programs with live asyncio
1547
+ tasks; `goroutines` only for Go; `rust_concurrency` only for Rust. `status` is
1548
+ `"pending"` when the pause could not land within a few seconds (the program is blocked
1549
+ inside a single call) -- a second record with the same `seq` and `status: "ok"` follows
1550
+ when it does land. If you press Ctrl-C or the program exits before it lands, no
1551
+ completing record is written. `errors` lists any sub-collector that failed, so a partial
1552
+ record is explicit about what is missing. A stderr line confirms each capture and where
1553
+ it went.
1554
+
1555
+ Narrow a long capture with `jq`, for example only threads with a frame in your own code:
1556
+
1557
+ ```bash
1558
+ jq -c '.processes[].threads[] | select(any(.frames[]; .file != null and (.file|test("/work/"))))' hang.jsonl
1559
+ ```
1560
+
1520
1561
  **Quitting an adopted session** adds a third choice to the usual quit dialog:
1521
1562
  - `d` (or `q`) -- detach and resume: the program keeps running headlessly; interrupt it
1522
1563
  again later the same way.
@@ -1541,7 +1582,7 @@ language.
1541
1582
  blocking external call or syscall, the pause can't land until that call returns --
1542
1583
  `tdb` prints a notice and opens the TUI once the stop actually arrives.
1543
1584
 
1544
- **Incompatible flags:** `-r`, `-k`/`-t`, `--record`, `--replay`, `--server`,
1585
+ **Incompatible flags:** `-r`, `-k`/`-t`, `--record`, `--replay`, `--replay-tui`, `--server`,
1545
1586
  `--headless`, `--mcp`, `--terminal`.
1546
1587
 
1547
1588
  ### Eval Mode (`-e`/`--eval`)
@@ -1584,7 +1625,7 @@ evaluated in each child process that reaches it.
1584
1625
  the eval point matches that bound line, so the expression still runs.
1585
1626
 
1586
1627
  **Incompatible flags:** `--run`, `-r`, `-a`, `-k`/`-t`, `--record`,
1587
- `--replay`, `--server`, `--headless`, `--mcp`, `--terminal`.
1628
+ `--replay`, `--replay-tui`, `--server`, `--headless`, `--mcp`, `--terminal`.
1588
1629
 
1589
1630
  ### Keybinding Schemes
1590
1631
 
@@ -1706,14 +1747,29 @@ written to `session.jsonl` as
1706
1747
  JSON-RPC commands. Works with launch mode (any language) and `-r`
1707
1748
  remote attach.
1708
1749
 
1709
- Replay it two ways:
1710
-
1750
+ Replay it three ways:
1751
+
1752
+ - `tdb --replay-tui session.jsonl` opens the normal TUI on the recorded
1753
+ program and performs every recorded action in front of you, at the
1754
+ recorded pace: breakpoints appear in the Code View, steps and continues
1755
+ move the cursor, Evaluate entries echo into the console with their
1756
+ results, stack navigation and variable expansion play out in their
1757
+ panels. The title bar shows progress (`tdb ▶ session.jsonl 3/11`) and a
1758
+ toast announces each action (`--replay-quiet` turns those toasts off).
1759
+ A failed action raises an error toast and replay continues. When the recording does not end with `quit`, the
1760
+ debugger stays open at the final stop for you to carry on by hand.
1761
+ `--replay-interval S` waits a fixed S seconds before each action
1762
+ instead of reproducing the recorded gaps. `--replay-timeout S` bounds
1763
+ each stop-wait (default 30 s). Exit code 0
1764
+ iff every action succeeded. Don't type into the TUI while it is
1765
+ replaying: stray keystrokes interleave with the recorded actions.
1711
1766
  - `tdb --replay session.jsonl` launches the recorded
1712
1767
  program headless, feeds every recorded command through the same RPC
1713
1768
  dispatch `tdb --server` uses, and prints a transcript (recorded time,
1714
1769
  command, verbatim result, interleaved program output). Exit code 0 iff
1715
1770
  every command succeeded. Add `--timing` to reproduce the original
1716
- pacing, `--replay-timeout S` to bound each stop-wait (default 30 s).
1771
+ pacing or `--replay-interval S` for a fixed delay before each command,
1772
+ `--replay-timeout S` to bound each stop-wait (default 30 s).
1717
1773
  - Against a live server: start `tdb --server prog.py`, then feed line 2
1718
1774
  onward of the file to `POST /rpc` . Each line is a valid request body:
1719
1775
 
@@ -1730,9 +1786,10 @@ lists), breakpoint enable/disable toggles, variable expansions when the
1730
1786
  adapter reports no `evaluateName` (currently the Perl adapter), and
1731
1787
  File > Open program switches.
1732
1788
 
1733
- ## MCP Integration
1789
+ ## MCP v2 Integration
1734
1790
 
1735
- tdb ships a Model Context Protocol (MCP) server (`tdb-mcp`) that exposes
1791
+ tdb ships a Model Context Protocol (MCP), version 2,
1792
+ server (`tdb-mcp`) that exposes
1736
1793
  the debugger as a curated set of tools an AI agent can call. The MCP
1737
1794
  server is a third in-process consumer of the same dispatch handlers the
1738
1795
  TUI and the HTTP server use so an agent gets the same lock semantics,
@@ -1830,7 +1887,7 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
1830
1887
  [--keybindings {default,vim,emacs}]
1831
1888
  [--terminal {xterm,konsole,gnome-terminal,ghostty,kitty,iterm2,warp,wezterm,terminator}]
1832
1889
  [--local-root PATH] [--remote-root PATH]
1833
- [--server] [--headless] [-k FILE:LINE|LINE] [--server-port SERVER_PORT] [-d] [--doc-text]
1890
+ [--server] [--headless] [-k FILE:LINE|LINE] [--server-port SERVER_PORT] [-d] [--doc-text] [--info]
1834
1891
  [program] [args ...]
1835
1892
  ```
1836
1893
 
@@ -1857,6 +1914,14 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
1857
1914
  | `--server` | Enable JSON-RPC server alongside TUI |
1858
1915
  | `--headless` | JSON-RPC server only, no TUI |
1859
1916
  | `--server-port PORT` | Server port (default: 8150) |
1917
+ | `--record FILE` | Record this TUI session's debugging actions to FILE (JSON-RPC lines) |
1918
+ | `--replay FILE` | Replay a recording headless, printing a transcript (no program argument) |
1919
+ | `--replay-tui FILE` | Replay a recording inside the TUI at the recorded pace, so you can watch it |
1920
+ | `--replay-quiet` | With `--replay-tui`: no per-action toasts (errors and the final summary still show) |
1921
+ | `--timing` | With `--replay`: reproduce the recorded pacing (`--replay-tui` always does) |
1922
+ | `--replay-interval S` | With `--replay`/`--replay-tui`: fixed S-second delay before each action instead of the recorded gaps |
1923
+ | `--replay-timeout S` | With `--replay`/`--replay-tui`: per-action stop-wait timeout (default 30) |
1924
+ | `--examine-log DEST` | With --run: write each Ctrl-\ / SIGUSR2 stack snapshot to DEST (- = stdout; repeatable) |
1860
1925
 
1861
1926
  ## Configuration
1862
1927
 
@@ -1917,6 +1982,28 @@ fires as expected.
1917
1982
 
1918
1983
  MIT
1919
1984
 
1985
+ ## Acknowledgments
1986
+
1987
+ Thank you:
1988
+
1989
+ - Will McGugan for the amazing `textual` module.
1990
+ `tdb` would be a pale shadow of itself had I used any other TUI framework.
1991
+ Fantastic work, Will.
1992
+
1993
+ - Microsoft for the Debug Adapter Protocol (DAP) and releasing
1994
+ its implementation in `debugpy` and the Python Debugger extension for Visual Studio Code
1995
+ as open source.
1996
+
1997
+ - Anthropic, for providing access to Claude Code through the
1998
+ [Claude for Open Source](https://claude.com/contact-sales/claude-for-oss) program.
1999
+ `tdb` was made almost entirely with Claude Code.
2000
+
2001
+ - OpenAI, for providing access to Codex through the
2002
+ [Codex for Open Source](https://developers.openai.com/community/codex-for-oss) program.
2003
+
2004
+ This project was inspired by Andreas Klöckner's excellent [pudb](https://pypi.org/project/pudb/)
2005
+ Python debugger.
2006
+
1920
2007
 
1921
2008
  ## Known Problems
1922
2009
 
@@ -47,7 +47,7 @@ It specifically supports modules
47
47
 
48
48
  - supports remote attachment to Python, Perl, Ruby, Rust, C/C++, and Go programs
49
49
 
50
- - includes a JSON-RPC server mode, an MCP mode, and a `SKILL.md` file that enable
50
+ - includes a JSON-RPC server mode, an MCP (v2) mode, and a `SKILL.md` file that enable
51
51
  programmatic debug control, making it suitable for
52
52
  automated, headless debugging workflows and AI-assisted debugging
53
53
 
@@ -61,28 +61,6 @@ to have `tdb` pop open automatically at the first uncaught exception
61
61
  making it suitable for operation in non-graphical environments (mouse support is
62
62
  available in graphical environments)
63
63
 
64
- ## Acknowledgments
65
-
66
- Thank you:
67
-
68
- - Will McGugan for the amazing `textual` module.
69
- `tdb` would be a pale shadow of itself had I used any other TUI framework.
70
- Fantastic work, Will.
71
-
72
- - Microsoft for the Debug Adapter Protocol (DAP) and releasing
73
- its implementation in `debugpy` and the Python Debugger extension for Visual Studio Code
74
- as open source.
75
-
76
- - Anthropic, for providing access to Claude Code through the
77
- [Claude for Open Source](https://claude.com/contact-sales/claude-for-oss) program.
78
- `tdb` was made almost entirely with Claude Code.
79
-
80
- - OpenAI, for providing access to Codex through the
81
- [Codex for Open Source](https://developers.openai.com/community/codex-for-oss) program.
82
-
83
- This project was inspired by Andreas Klöckner's excellent [pudb](https://pypi.org/project/pudb/)
84
- Python debugger.
85
-
86
64
  ## Gallery
87
65
  <p align="center">
88
66
  <img src="https://github.com/AlDanial/tdb/blob/main/gallery/async_breakpoint.png" alt="at breakpoint" width="300">
@@ -122,6 +100,10 @@ uvx --from textual-debugger tdb my_program.py
122
100
  # show comprehensive documentation in a terminal-based Markdown viewer
123
101
  tdb --doc
124
102
 
103
+ # show where tdb is installed, where its bundled Perl PadWalker module
104
+ # lives, and the Help > About text
105
+ tdb --info
106
+
125
107
  # debug a script (stops at first line by default)
126
108
  tdb my_program.py
127
109
 
@@ -269,7 +251,7 @@ non-standard location, or change a language's default adapter, add to
269
251
  Core debugging works identically for every language: breakpoints (incl.
270
252
  conditions and persistence), stepping, continue/pause, run-to-cursor, stack
271
253
  navigation, variable inspection, the evaluate console, syntax highlighting,
272
- and the JSON-RPC / MCP programmatic modes.
254
+ and the JSON-RPC / MCP (v2) programmatic modes.
273
255
 
274
256
  Python-specific features are hidden or return "not supported for this
275
257
  language" message when debugging other languages: statement-granularity
@@ -473,6 +455,24 @@ metadata for broader primitives and stronger ownership evidence.
473
455
  `perl` ≥ 5.18 on `PATH`. It drives stock `perl5db` under the
474
456
  hood, so it works with any Perl already on the system.
475
457
 
458
+ The [PadWalker](https://metacpan.org/pod/PadWalker) module v2.5, by Robin Houston,
459
+ is bundled with `tdb`. PadWalker provides a more complete view of lexical variables
460
+ in outer/caller frames and therefore provides a richer debugging experience.
461
+ PadWalker is an XS (compiled) module, so the bundled copy has to be built
462
+ against the exact perl that runs your program. `tdb` does this for you on the
463
+ first Perl launch: if the perl in use cannot already load PadWalker (from CPAN
464
+ or a distro package), `tdb` compiles the bundled sources, caches the result
465
+ per interpreter under its config directory (`~/.config/tdb/padwalker/` on
466
+ Linux/macOS, `%APPDATA%\\tdb\\padwalker\\` on Windows), and prepends that
467
+ directory to the debuggee's `PERL5LIB`. The build takes about a second and
468
+ needs perl's headers (`libperl-dev` on Debian/Ubuntu, `perl-devel` on
469
+ Fedora/RHEL) plus a C compiler; Strawberry Perl on Windows ships both. When
470
+ the build is not possible, `tdb` prints a one-line notice on the console and
471
+ falls back to a read-only pad walk, so outer-frame lexicals degrade but
472
+ debugging otherwise proceeds. `tdb --info` reports the source directory, the
473
+ cache directory, and whether a build exists for the `perl` on your `PATH`.
474
+ `TDB_PADWALKER_CACHE` overrides the cache location.
475
+
476
476
  **Launching a script:**
477
477
 
478
478
  ```bash
@@ -569,13 +569,6 @@ export PERL5LIB=/opt/tdb-perl:$PERL5LIB
569
569
  the two files in the same relative layout shown above; `helpers.pl` is a
570
570
  sibling of the `Devel/` directory, not inside it.)
571
571
 
572
- **PadWalker (optional but recommended):** inspecting lexical (`my`)
573
- variables in the *current* frame always works. Lexicals in outer/caller
574
- frames need the `PadWalker` module installed on the debuggee's Perl; without
575
- it, tdb falls back to a read-only pad walk that can't reach fully into
576
- enclosing scopes, and outer-frame variable listings degrade accordingly.
577
- Install with `cpanm PadWalker` (or your distro's package) for full fidelity.
578
-
579
572
  **Pause is unavailable in attach mode.** Launch-mode sessions (`tdb
580
573
  script.pl`) support pausing a running program at any time. Remote-attach
581
574
  sessions don't. Asynchronous pause (as Python gets via `debugpy`) needs a control channel
@@ -1449,6 +1442,54 @@ available (breakpoints, stepping, variable inspection, the evaluate console). Th
1449
1442
  debuggee itself never receives the signal (`tdb`'s adapter runs in its own process
1450
1443
  group), so its own `SIGINT` handling is undisturbed.
1451
1444
 
1445
+ **Examining without opening the TUI:** press `Ctrl-\` in the terminal (`Ctrl-Break` on
1446
+ Windows), or, on Unix, send `SIGUSR2` to `tdb`'s pid: `kill -USR2 <tdb pid>`.
1447
+
1448
+ **Windows caveat:** the Ctrl-Break trigger is untested. Unlike Ctrl-C, a console
1449
+ Ctrl-Break is delivered to every process attached to the console, including the debug
1450
+ adapter and the program itself, so it may terminate the program instead of snapshotting
1451
+ it. There is no signal-based alternative on Windows.
1452
+
1453
+ `tdb` pauses the program, writes one JSON line describing the call stack of every thread
1454
+ (plus asyncio tasks and multiprocessing children for Python, goroutines for Go, and
1455
+ the concurrency snapshot for Rust), and resumes the program. Ctrl-C behavior is
1456
+ unchanged. By default the line goes to stdout; `--examine-log DEST` sends it to a file
1457
+ instead (`-` means stdout; repeat the flag to write to several places):
1458
+
1459
+ ```bash
1460
+ tdb --run --examine-log hang.jsonl my_program.py # file only, appended
1461
+ tdb --run --examine-log - --examine-log hang.jsonl my_program.py # both
1462
+ ```
1463
+
1464
+ Each record looks like (abridged):
1465
+
1466
+ ```json
1467
+ {"schema":1,"seq":1,"trigger":"SIGQUIT","status":"ok",
1468
+ "requested_at":"2026-09-07T14:02:11.482-07:00","landed_at":"2026-09-07T14:02:11.511-07:00",
1469
+ "elapsed_s":87.3,"language":"python","program":"/home/al/work/app.py",
1470
+ "processes":[{"pid":41213,"role":"parent","name":null,
1471
+ "threads":[{"id":1,"name":"MainThread","frames":[
1472
+ {"function":"wait","file":"/usr/lib/python3.13/threading.py","line":359},
1473
+ {"function":"main","file":"/home/al/work/app.py","line":42}]}],
1474
+ "tasks":[{"name":"worker-2","state":"PENDING","awaiting":"Lock.acquire","frames":["run (/home/al/work/app.py:18)"]}]}],
1475
+ "errors":[]}
1476
+ ```
1477
+
1478
+ Frames are innermost first. `tasks` appears only for Python programs with live asyncio
1479
+ tasks; `goroutines` only for Go; `rust_concurrency` only for Rust. `status` is
1480
+ `"pending"` when the pause could not land within a few seconds (the program is blocked
1481
+ inside a single call) -- a second record with the same `seq` and `status: "ok"` follows
1482
+ when it does land. If you press Ctrl-C or the program exits before it lands, no
1483
+ completing record is written. `errors` lists any sub-collector that failed, so a partial
1484
+ record is explicit about what is missing. A stderr line confirms each capture and where
1485
+ it went.
1486
+
1487
+ Narrow a long capture with `jq`, for example only threads with a frame in your own code:
1488
+
1489
+ ```bash
1490
+ jq -c '.processes[].threads[] | select(any(.frames[]; .file != null and (.file|test("/work/"))))' hang.jsonl
1491
+ ```
1492
+
1452
1493
  **Quitting an adopted session** adds a third choice to the usual quit dialog:
1453
1494
  - `d` (or `q`) -- detach and resume: the program keeps running headlessly; interrupt it
1454
1495
  again later the same way.
@@ -1473,7 +1514,7 @@ language.
1473
1514
  blocking external call or syscall, the pause can't land until that call returns --
1474
1515
  `tdb` prints a notice and opens the TUI once the stop actually arrives.
1475
1516
 
1476
- **Incompatible flags:** `-r`, `-k`/`-t`, `--record`, `--replay`, `--server`,
1517
+ **Incompatible flags:** `-r`, `-k`/`-t`, `--record`, `--replay`, `--replay-tui`, `--server`,
1477
1518
  `--headless`, `--mcp`, `--terminal`.
1478
1519
 
1479
1520
  ### Eval Mode (`-e`/`--eval`)
@@ -1516,7 +1557,7 @@ evaluated in each child process that reaches it.
1516
1557
  the eval point matches that bound line, so the expression still runs.
1517
1558
 
1518
1559
  **Incompatible flags:** `--run`, `-r`, `-a`, `-k`/`-t`, `--record`,
1519
- `--replay`, `--server`, `--headless`, `--mcp`, `--terminal`.
1560
+ `--replay`, `--replay-tui`, `--server`, `--headless`, `--mcp`, `--terminal`.
1520
1561
 
1521
1562
  ### Keybinding Schemes
1522
1563
 
@@ -1638,14 +1679,29 @@ written to `session.jsonl` as
1638
1679
  JSON-RPC commands. Works with launch mode (any language) and `-r`
1639
1680
  remote attach.
1640
1681
 
1641
- Replay it two ways:
1642
-
1682
+ Replay it three ways:
1683
+
1684
+ - `tdb --replay-tui session.jsonl` opens the normal TUI on the recorded
1685
+ program and performs every recorded action in front of you, at the
1686
+ recorded pace: breakpoints appear in the Code View, steps and continues
1687
+ move the cursor, Evaluate entries echo into the console with their
1688
+ results, stack navigation and variable expansion play out in their
1689
+ panels. The title bar shows progress (`tdb ▶ session.jsonl 3/11`) and a
1690
+ toast announces each action (`--replay-quiet` turns those toasts off).
1691
+ A failed action raises an error toast and replay continues. When the recording does not end with `quit`, the
1692
+ debugger stays open at the final stop for you to carry on by hand.
1693
+ `--replay-interval S` waits a fixed S seconds before each action
1694
+ instead of reproducing the recorded gaps. `--replay-timeout S` bounds
1695
+ each stop-wait (default 30 s). Exit code 0
1696
+ iff every action succeeded. Don't type into the TUI while it is
1697
+ replaying: stray keystrokes interleave with the recorded actions.
1643
1698
  - `tdb --replay session.jsonl` launches the recorded
1644
1699
  program headless, feeds every recorded command through the same RPC
1645
1700
  dispatch `tdb --server` uses, and prints a transcript (recorded time,
1646
1701
  command, verbatim result, interleaved program output). Exit code 0 iff
1647
1702
  every command succeeded. Add `--timing` to reproduce the original
1648
- pacing, `--replay-timeout S` to bound each stop-wait (default 30 s).
1703
+ pacing or `--replay-interval S` for a fixed delay before each command,
1704
+ `--replay-timeout S` to bound each stop-wait (default 30 s).
1649
1705
  - Against a live server: start `tdb --server prog.py`, then feed line 2
1650
1706
  onward of the file to `POST /rpc` . Each line is a valid request body:
1651
1707
 
@@ -1662,9 +1718,10 @@ lists), breakpoint enable/disable toggles, variable expansions when the
1662
1718
  adapter reports no `evaluateName` (currently the Perl adapter), and
1663
1719
  File > Open program switches.
1664
1720
 
1665
- ## MCP Integration
1721
+ ## MCP v2 Integration
1666
1722
 
1667
- tdb ships a Model Context Protocol (MCP) server (`tdb-mcp`) that exposes
1723
+ tdb ships a Model Context Protocol (MCP), version 2,
1724
+ server (`tdb-mcp`) that exposes
1668
1725
  the debugger as a curated set of tools an AI agent can call. The MCP
1669
1726
  server is a third in-process consumer of the same dispatch handlers the
1670
1727
  TUI and the HTTP server use so an agent gets the same lock semantics,
@@ -1762,7 +1819,7 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
1762
1819
  [--keybindings {default,vim,emacs}]
1763
1820
  [--terminal {xterm,konsole,gnome-terminal,ghostty,kitty,iterm2,warp,wezterm,terminator}]
1764
1821
  [--local-root PATH] [--remote-root PATH]
1765
- [--server] [--headless] [-k FILE:LINE|LINE] [--server-port SERVER_PORT] [-d] [--doc-text]
1822
+ [--server] [--headless] [-k FILE:LINE|LINE] [--server-port SERVER_PORT] [-d] [--doc-text] [--info]
1766
1823
  [program] [args ...]
1767
1824
  ```
1768
1825
 
@@ -1789,6 +1846,14 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
1789
1846
  | `--server` | Enable JSON-RPC server alongside TUI |
1790
1847
  | `--headless` | JSON-RPC server only, no TUI |
1791
1848
  | `--server-port PORT` | Server port (default: 8150) |
1849
+ | `--record FILE` | Record this TUI session's debugging actions to FILE (JSON-RPC lines) |
1850
+ | `--replay FILE` | Replay a recording headless, printing a transcript (no program argument) |
1851
+ | `--replay-tui FILE` | Replay a recording inside the TUI at the recorded pace, so you can watch it |
1852
+ | `--replay-quiet` | With `--replay-tui`: no per-action toasts (errors and the final summary still show) |
1853
+ | `--timing` | With `--replay`: reproduce the recorded pacing (`--replay-tui` always does) |
1854
+ | `--replay-interval S` | With `--replay`/`--replay-tui`: fixed S-second delay before each action instead of the recorded gaps |
1855
+ | `--replay-timeout S` | With `--replay`/`--replay-tui`: per-action stop-wait timeout (default 30) |
1856
+ | `--examine-log DEST` | With --run: write each Ctrl-\ / SIGUSR2 stack snapshot to DEST (- = stdout; repeatable) |
1792
1857
 
1793
1858
  ## Configuration
1794
1859
 
@@ -1849,6 +1914,28 @@ fires as expected.
1849
1914
 
1850
1915
  MIT
1851
1916
 
1917
+ ## Acknowledgments
1918
+
1919
+ Thank you:
1920
+
1921
+ - Will McGugan for the amazing `textual` module.
1922
+ `tdb` would be a pale shadow of itself had I used any other TUI framework.
1923
+ Fantastic work, Will.
1924
+
1925
+ - Microsoft for the Debug Adapter Protocol (DAP) and releasing
1926
+ its implementation in `debugpy` and the Python Debugger extension for Visual Studio Code
1927
+ as open source.
1928
+
1929
+ - Anthropic, for providing access to Claude Code through the
1930
+ [Claude for Open Source](https://claude.com/contact-sales/claude-for-oss) program.
1931
+ `tdb` was made almost entirely with Claude Code.
1932
+
1933
+ - OpenAI, for providing access to Codex through the
1934
+ [Codex for Open Source](https://developers.openai.com/community/codex-for-oss) program.
1935
+
1936
+ This project was inspired by Andreas Klöckner's excellent [pudb](https://pypi.org/project/pudb/)
1937
+ Python debugger.
1938
+
1852
1939
 
1853
1940
  ## Known Problems
1854
1941
 
@@ -27,7 +27,7 @@
27
27
  "pygments>=2.17.0",
28
28
  "fastapi>=0.115.0",
29
29
  "uvicorn>=0.30.0",
30
- "mcp>=1.28.0,<2.0.0",
30
+ "mcp>=2.0.0,<3.0.0",
31
31
  ]
32
32
 
33
33
  # extras needed to run the examples and tests
@@ -60,7 +60,7 @@
60
60
  include = ["tdb", "tdb.*"]
61
61
 
62
62
  [tool.setuptools.package-data]
63
- tdb = ["README.md", "adapters/perl/helpers.pl", "adapters/perl/Devel/TdbRemote.pm", "adapters/perl/Devel/TdbCompile.pm", "adapters/bash/tdb_harness.sh", "adapters/powershell/tdb_launch.ps1", "rust_concurrency/probes/gdb_script.py", "rust_concurrency/probes/lldb_script.py"]
63
+ tdb = ["README.md", "adapters/perl/helpers.pl", "adapters/perl/padwalker_src/PadWalker.pm", "adapters/perl/padwalker_src/PadWalker.xs", "adapters/perl/padwalker_src/Makefile.PL", "adapters/perl/Devel/TdbRemote.pm", "adapters/perl/Devel/TdbCompile.pm", "adapters/bash/tdb_harness.sh", "adapters/powershell/tdb_launch.ps1", "rust_concurrency/probes/gdb_script.py", "rust_concurrency/probes/lldb_script.py"]
64
64
 
65
65
  [tool.pytest.ini_options]
66
66
  testpaths = ["tests"]