DAP 复用器:将您的编辑器、REPL、调试器(等)连接在一起,全部协同工作于一个单一调试会话中,即使在工具故障时也能保持持久
摘要
dap-mux 是一个 DAP 代理,允许您将多个 DAP 客户端(编辑器、REPL 等)连接到单个调试会话,从而实现从不同工具同时调试,具备会话持久性和延迟加入状态重放功能。
查看缓存全文
缓存时间: 2026/06/02 19:36
dap-mux/dap-mux
来源:https://github.com/dap-mux/dap-mux
dap-mux
每个终端调试器都迫使你做出选择:要么使用拥有完整求值能力但缺乏源码上下文的 REPL,要么使用带有可视化断点但调试控制台功能受限的编辑器。dap-mux 消除了这种选择的必要。将你的编辑器和 REPL 同时连接到同一个调试会话。在你的 REPL 中单步执行,编辑器同时跟踪当前行。在暂停的栈帧中求值任意表达式。从任意一侧设置断点。
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Helix │◄──DAP──►│ │◄──DAP──►│ debugpy │
│ 源码视图 │ │ dap-mux │ │ (或任意 │
│ 断点 │ │ │ │ DA 服务器) │
└──────────────┘ │ │ └──────────────┘
│ │
┌──────────────┐ │ │
│ 你的 REPL │◄──DAP──►│ │
│ 求值 │ └──────────────┘
│ 单步执行 │
└──────────────┘
dap-mux 是一个 DAP 代理。它位于调试适配器和多个客户端之间,路由请求,广播事件,并向延迟加入的客户端重放会话状态。你的编辑器和 REPL 都是通过多路复用器共享同一会话的一等 DAP 客户端。
附带的 REPL 前端是一个 IPython 扩展——一个调试控制界面,为 IPython 的 %magic 接口提供 DAP 连接能力。这是作者使用的 REPL。其他 REPL 也可以连接到多路复用器;只是目前它们还没有内置的前端。
目标
你的编辑器 + 你的语言 + 你的调试器 + 你的REPL——以及你想连接的任何其他工具。你的工具选择应该可以自由组合。dap-mux 是连接器;工具是你的。以下承诺由此而来:
每一层边界都使用标准 DAP。 任何支持 DAP 的编辑器、REPL 或工具都可以连接到面向客户端的接口,无需特殊插件或配置。任何标准 DAP 适配器都可以在上游工作。每个连接点都使用标准协议。
每个连接的客户端都是一等的。 所有客户端都可以执行任何标准 DAP 操作:设置断点、单步执行、求值表达式、检查调用栈、选择栈帧。没有客户端是只读的。
会话在客户端变化时仍能存活。 连接或断开客户端不会中断会话或重启适配器。在会话中途连接第二个编辑器。断开 REPL 再重新连接。会话继续执行。
延迟加入者能看到当前状态。 初始化后连接的客户端会收到已初始化的握手信号,如果当前处于暂停状态,还会收到当前的停止位置。中途加入的编辑器会立即显示正确的代码行。
状态
v0.9.0 是第一个公开发布版本——这是除作者以外的人第一次能够运行这个工具。在此之前,它都是在私有环境中开发和测试的。核心机制——协议帧封装、序列号重写、多客户端路由、事件广播、延迟加入状态重放——已经过实际测试,并有一个测试套件覆盖。它所实现的工作流是真实的:将 Helix 或 VS Code 和一个 IPython REPL 连接到同一个 debugpy 会话,并同时在两者中进行调试。这是两个编辑器、一个调试适配器、一个 REPL,在两个平台上。
目标要求支持任何编辑器、任何语言、任何适配器——而这个领域的大部分还没有被任何人接触过。有很多东西需要发现和修复。Bug 报告、测试其他组合的人提供的说明,以及拓宽经过验证的基础的贡献,正是这个项目目前所需要的。
要求
uv (https://docs.astral.sh/uv/) — 它自动管理 Python 运行时。
debugpy 必须在目标环境中可用。dap-mux 通过 TCP 连接到它,从不直接导入它:
pip install debugpy # 在你的项目的虚拟环境中
安装
uv tool install dap-mux
用于开发:
git clone https://github.com/dap-mux/dap-mux
cd dap-mux
uv sync --group dev
快速入门
此示例使用 Helix 和内置的 IPython 前端。任何支持 DAP 的编辑器都可以工作——参见编辑器设置。
1. 启动会话
dmux script.py
dap-mux 启动 debugpy,连接多路复用器,并打开一个 IPython REPL:
dap-mux listening on 127.0.0.1:5679
Connect your editor to 127.0.0.1:5679
IPython 提示符出现。脚本已暂停——在编辑器客户端发送 configurationDone 之前不会开始运行。
2. 在 Helix 中设置断点,然后连接
在 Helix 中打开脚本,在你想要暂停的行上设置断点(b 或你配置的按键)。然后连接:
:debug-remote 127.0.0.1:5679 attach
在连接之前设置好断点。 当 Helix 连接时,它会发送
configurationDone,这会启动脚本。如果没有断点,脚本会在你做任何事之前运行完成。
执行开始并在你的断点处暂停。Helix 高亮当前行。IPython 打印暂停位置。
3. 从 IPython 调试
python
%bt # 调用栈
%eval results # 在暂停的栈帧中求值表达式
%frame 2 # 切换到另一个栈帧(%eval 会跟随)
%n # 单步跳过
%s # 单步进入
%c # 继续
%finish # 跳出当前函数
%break script.py:42 # 设置断点
IPython 提示符下的裸 Python 会在本地执行。%eval 在调试目标帧中求值。
使用
启动模式
dmux script.py
启动 debugpy 并附加到 script.py,启动多路复用器,打开 IPython REPL。一个命令全部搞定。
附加模式
当 debugpy 已经在运行时:
dmux --attach 5678
dmux --attach 192.168.1.10:5678
IPython REPL 连接到现有会话。如果在你加入时会话已经暂停,使用 %sync 来发现当前的暂停状态。
无头模式
使用 --headless 启动多路复用器而不启动 IPython REPL。连接你自己的工具——任何编辑器、任何支持 DAP 的 REPL 前端。
dmux script.py --headless
dmux --attach 5678 --headless
什么启动什么:
在启动模式(dmux script.py --headless)下,dap-mux 启动 debugpy 并附加到 Python 脚本,启动多路复用器,然后等待。你可以连接你自己的客户端。
在附加模式(dmux --attach host:port --headless)下,dap-mux 连接到一个已经运行的调试适配器——任何语言、任何适配器。你负责先启动适配器。
将 dap-mux 用于其他语言
多路复用器使用标准 DAP,可以与任何调试适配器一起工作。以下是一个使用 rdbg (https://github.com/ruby/debug) 的 Ruby 示例:
# 终端 1 — 启动 Ruby 调试适配器
rdbg --open --port 5678 script.rb
# 终端 2 — 启动多路复用器
dmux --attach 5678 --headless
# dap-mux listening on 127.0.0.1:5679
# 现在将你的编辑器连接到 127.0.0.1:5679 作为 DAP 服务器
任何支持 DAP 的编辑器都能立即连接。一个 REPL 前端——相当于为 Ruby、Julia 或其他语言提供的 IPython 扩展——目前还不存在,需要构建。多路复用器已经就绪;前端是贡献的所在。
CLI 参考
dmux [TARGET] [OPTIONS]
Arguments:
TARGET 要调试的 Python 脚本(启动模式)
Options:
--attach, -a TEXT 附加到正在运行的调试适配器([host:]port)
--mux-port, -p INT 客户端连接端口(0 = 自动)[default: 0]
--log-level, -l TEXT 日志级别:DEBUG, INFO, WARNING, ERROR [default: WARNING]
--log-file TEXT 同时将日志写入此文件
--headless 启动时不启动 IPython REPL
--version, -V 显示版本并退出
编辑器设置
Helix
添加到 ~/.config/helix/languages.toml:
[[language]]
name = "python"
[language.debugger]
name = "debugpy"
transport = "tcp"
command = "python3"
args = ["-m", "debugpy"]
port-arg = "--listen=127.0.0.1:{}"
[[language.debugger.templates]]
name = "launch"
request = "launch"
completion = [{ name = "script", completion = "filename" }]
args = { mode = "debug", program = "{0}" }
[[language.debugger.templates]]
name = "attach"
request = "attach"
completion = []
args = {}
使用 :debug-remote host:port attach 连接到正在运行的 dap-mux。此配置的工作副本位于 demos/helix/。
VS Code
安装 Python Debugger (https://marketplace.visualstudio.com/items?itemName=ms-python.debugpy) 扩展 (ms-python.debugpy),然后添加到 .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Connect to dap-mux",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "127.0.0.1",
"port": 5679
}
}
]
}
使用固定端口启动 dap-mux(dmux script.py -p 5679),以便启动配置可以硬编码端口。在运行配置之前在 VS Code 中设置断点——启动配置会发送 configurationDone 并开始执行。此配置的工作副本位于 demos/vscode/。
Neovim
配置 nvim-dap 连接到 mux 端口作为 DAP 服务器。将 dap.adapters 指向 127.0.0.1:,类型为 "server"。
其他编辑器
任何带有 DAP 客户端的编辑器都可以工作。将其配置为连接到 127.0.0.1: 作为现有的 DAP 服务器——dap-mux 使用标准 DAP,无需特殊配置。
IPython 扩展
dap-mux 附带一个 IPython 扩展,将 IPython 变为调试控制界面。使用 %load_ext dap_mux 加载它,或者使用 dmux(它会自动加载)。
| 魔法命令 | 别名 | 描述 |
|---|---|---|
%connect [host:]port | 连接到多路复用器 | |
%disconnect | 断开连接 | |
%sync | 发现当前暂停状态(在延迟加入一个已暂停的会话后很有用) | |
%bt | 调用栈 | |
%frame N | 选择栈帧;随后的 %eval 在该帧的作用域中求值 | |
%eval expr | 在当前帧中求值表达式 | |
%step | %s | 单步进入 |
%next | %n | 单步跳过 |
%continue_ | %c | 继续执行 |
%finish | 跳出当前函数 | |
%break file:line [cond] | 设置断点(可选条件) | |
%clear file:line | 移除文件中的所有断点 |
%eval 在调试目标帧中求值——它可以访问当前暂停点的局部和全局变量。常规的 IPython 表达式中求值是在本地作用域。
工作原理
每个 DAP 客户端(编辑器、REPL)通过 TCP 连接到 dap-mux。多路复用器重写序列号,使所有客户端共享一个到调试适配器的上游连接。响应会路由回发出请求的客户端。事件广播给所有连接的客户端。
当一个客户端在会话已经初始化后加入时,dap-mux 会重放缓存的 initialized 事件,如果当前会话处于暂停状态,还会重放最后一个 stopped 事件——这样延迟加入者无需重启适配器就能立即看到当前状态。
dap-mux 使用 Python 编写。该工具是一个网络 I/O 路由器——它从一个 TCP 连接读取 JSON 并写入其他连接——而 Python 的 asyncio 正是为此目的而构建的。实际性能上限是人类的按键速度;多路复用器永远不会成为 CPU 瓶颈。
IPython 集成是另一个原因:它在同一个进程中运行,可以直接访问 IPython 的内部。Go 或 Rust 实现必须通过 Python 壳程序并进行 IPC 才能实现同样的效果,这将用一个混乱的进程外设计来换取干净的进程内设计。
适合人群
- 终端优先的开发者,使用 Helix、Neovim、Emacs 或任何支持 DAP 的编辑器,希望在不离开终端的情况下获得 IDE 级别的调试体验
- 数据科学家,他们依赖 IPython,并希望在调试时获得可视化的源码跟踪
- 远程开发者,通过 SSH 进行调试,图形化 IDE 不切实际
- 任何人,曾希望自己的调试 REPL 有 tab 补全、历史记录和
import功能
兼容性
编辑器
任何支持 DAP 的编辑器都可以用作显示客户端——将其连接到 mux 端口,就像连接任何其他 DAP 服务器一样。
| 编辑器 | DAP 集成 | 状态 |
|---|---|---|
| Helix | 内置 | 已测试 |
| VS Code | 内置 | 已测试 |
| Neovim | nvim-dap (https://github.com/mfussenegger/nvim-dap) | 未测试 |
| Emacs | dap-mode (https://github.com/emacs-lsp/dap-mode) | 未测试 |
| Vim | Vimspector (https://github.com/puremourning/vimspector) | 未测试 |
语言
对于拥有功能强大的交互式 REPL 的语言来说,REPL + 编辑器工作流最为丰富。多路复用器本身可以与任何 DAP 适配器一起工作。
| 语言 | 调试适配器 | REPL |
|---|---|---|
| Python | debugpy (https://github.com/microsoft/debugpy) | IPython ← 已测试 |
| Ruby | debug (https://github.com/ruby/debug) gem | IRB, Pry |
| Julia | DebugAdapter.jl (https://github.com/julia-vscode/DebugAdapter.jl) | Julia REPL |
| Elixir | ElixirLS (https://github.com/elixir-lsp/elixir-ls) | IEx |
| JavaScript | js-debug (https://github.com/microsoft/vscode-js-debug) | Node.js REPL |
对于 DAP 支持强大但缺乏有意义 REPL 的语言——Go (Delve)、Rust (codelldb)、C/C++ (lldb-dap)——仍然可以通过 dap-mux 受益于多编辑器会话和不重启断线重连。
dap-mux 针对 debugpy 进行了测试。其他适配器应该也能工作(DAP 是标准协议),但尚未验证。
平台
| 平台 | 状态 |
|---|---|
| Linux | 已测试 |
| macOS | 已测试 |
| Windows | 预期可用;尚未验证 |
这不是什么
dap-mux 是一个路由器,而不是调试器。 它在你的工具和你的调试适配器之间转发 DAP 消息。它不执行代码、不检查内存、也不理解你的程序状态。它所连接的一切已经具备这些功能——dap-mux 提供的是连接性,而不是功能。
它不会添加你的适配器本身没有的调试功能。 如果你的调试适配器不支持某些功能,dap-mux 不会提供它们。能力来自你带来的工具。dap-mux 负责连接它们。
终端优先设计。 没有 GUI,也不会有——在命令行中,唯一的实际交互就是启动它。之后,你就在你的编辑器和 REPL 中工作,而不是在 dap-mux 中。
IPython 扩展是 Python 专有的。 多路复用器适用于任何拥有 DAP 适配器的语言。附带的 REPL 集成构建在 IPython 之上,仅限 Python。其他语言的 REPL 可以是潜在的前端,但它们尚未构建。
dap-mux 是管道中的一个组件,而不是一体化工具。 如果你想要一个带有自己 UI 的自包含 TUI 调试器,pudb (https://github.com/inducer/pudb) 非常出色且积极维护。dap-mux 适用于另一种工作方式:你的编辑器擅长一件事,你的 REPL 擅长一件事,你的调试适配器擅长一件事——dap-mux 将它们连接起来。Unix 一直是这样工作的。
限制
- 仅针对 debugpy 进行了测试。 其他调试适配器应该可以工作,但尚未验证。
- Windows 支持未经测试。 代码没有已知的平台特定依赖,但尚未在 Windows 上验证。
许可证
贡献
欢迎提交问题和反馈。该项目还很年轻——你测试过的适配器或编辑器的错误报告和说明尤其有用。请参阅 CONTRIBUTING.md 了解如何设置开发环境、什么是有价值的 PR、以及项目会接受和不会接受什么。请参阅 CHANGELOG.md 了解变更记录。
相似文章
Show HN: Rmux – 一款可编程终端复用器,带有 Playwright 风格 SDK
Rmux 是一款用 Rust 编写的新式可编程终端复用器,提供与 tmux 兼容的命令行接口、类型化 SDK 以及面向智能体工作流的功能,支持在 Linux、macOS 和 Windows 上创建可分离、可脚本化的终端会话。
@dzhng: 你应该试试 duet agent 的 /relay:
duet-agent 是一个用于持久化 AI 代理任务的框架,这些任务可以跨越单个聊天会话,实现长时间运行、可恢复的任务,具有跨会话记忆和通过 relay 轮次观察到的状态。
@dzhng: 推出: Duet Agent — 我们正在 @duetchat 上构建的一种新型工具,适合无法在单个聊天中完成的任务:…
Duetchat 推出 Duet Agent,一种用于运行长时间AI代理任务的新型工具,具备状态机中继、内存压缩以及用于沙盒的无状态运行器。
ChromeDevTools/chrome-devtools-mcp
Chrome DevTools MCP 是一个开源的模型上下文协议服务器,允许 AI 编程助手(Gemini、Claude、Cursor、Copilot)控制并检查实时 Chrome 浏览器,用于自动化、调试和性能分析。它将 Chrome DevTools 与 Puppeteer 集成,为 AI 助手提供完整的浏览器检查和自动化能力。
@dingyi: 我现在都懒得用 tmux 了,直接用 https://herdr.dev 或 https://muxy.app 更方便,适合懒人。
Herdr 是一款基于终端的代理多路复用器,提供持久会话、代理感知以及原生的鼠标 TUI,定位为 tmux 的便捷替代方案。该推文还推荐了 muxy.app,适用于寻求更简单终端会话管理的用户。