【免费下载链接】dmuxA dev agent multiplexer for git worktrees and coding agents.项目地址https://gitcode.com/gh_mirrors/dmu/dmux点击查看免费下载dmux 是一个用 Ink 5React 式终端 UI 框架dmux 的核心依赖构建的AI 编程 Agent 多路复用器它在 tmux 里并行运行 Claude Code、Codex、opencode 等 Agent每个 Agent 独占一个 git worktree 和一个 tmux 面板pane而左侧那条能实时显示每个面板状态Working / Done / 等待输入的侧边栏正是今天要拆解的对象。本文将深入 dmux 源码完整讲透两个核心子系统基于 Ink 的 TUI 布局计算——面板网格如何根据终端尺寸自动排布Pane 状态检测——dmux 如何在不修改 Agent 代码的前提下知道每个 Agent 是干活中、干完了、还是在等你做选择。架构总览Ink 渲染的 TUI 与职责分明的核心模块dmux 的 TUI 完全基于 Ink 5 React 18 构建。入口 src/index.ts 里只有一句关键调用把DmuxApp这个 React 组件通过render()挂到终端之后的一切界面更新都走 React 的 diff 机制终端只是渲染后端。真正聪明的逻辑全部放在少数几个模块里且职责切割得非常干净模块源码位置职责布局计算器src/layout/LayoutCalculator.ts纯函数算出最优网格列数/行数/窗口宽度占位面板管理器src/layout/SpacerManager.ts用填充面板避免末行面板被拉得过宽布局应用器src/layout/TmuxLayoutApplier.ts把计算结果真正写进 tmux含多级降级状态检测协调器src/services/StatusDetector.ts协调 worker、LLM 与通知映射最终状态面板分析器src/services/PaneAnalyzer.ts三级 LLM 流水线判断面板处于哪种状态单面板 Workersrc/workers/PaneWorker.ts每个 pane 一个线程轮询截图 启发式判断这种确定性计算优先、AI 兜底的分层是理解整套源码的钥匙——能用纯逻辑解决的绝不调 LLM。TUI 布局计算LayoutCalculator 的评分网格算法核心思路不依赖 tmux 内置布局自己算网格tmux 自带tiled、main-vertical等布局策略但它们不理解侧边栏必须固定 40 列宽单个面板宽度超过 80 列就不舒服这类 dmux 的排版约束。所以 dmux 选择完全自己计算网格再手动下发给 tmux。布局由四个参数约束见 src/constants/layout.ts 与 src/utils/layoutManager.ts参数默认值含义SIDEBAR_WIDTH40侧边栏固定宽度单元格MIN_COMFORTABLE_WIDTH50面板舒适最小宽度低于它宁可堆行MAX_COMFORTABLE_WIDTH80面板舒适最大宽度超过它窗口就封顶MIN_COMFORTABLE_HEIGHT15面板最小舒适高度前两项还可以在设置界面调整对应minPaneWidth/maxPaneWidth配置。枚举候选网格 三因子打分LayoutCalculator.calculateOptimalLayout() 的算法非常直白枚举从每个面板一列开始递减列数直到单列每个列数算出对应行数可行性过滤侧边栏 列数 × 最小舒适宽 边框 ≤ 终端宽度且高度同理不满足直接淘汰窗口封顶窗口宽度取侧边栏 列数 × MAX宽 边框与终端宽度的较小值——在超宽屏上网格会居中收窄面板绝不超过约 80 列保证阅读舒适度打分对每个可行网格计算 0–1 的评分见 scoreLayout()score 平衡分 × 高度分 × 宽度分 平衡分最后一行只有 1 个面板 → 0.5孤面板很难看满行 → 1.0 高度分面板高度 ÷ 终端高度越高越好 宽度分面板宽 ≤ MAX_COMFORTABLE_WIDTH → 1.0否则 0.8得分最高者胜出同分偏好列数更少的方案面板更宽、边框更少。如果终端实在太小最终兜底为单列堆叠。面板到列的分配用一个巧妙的余数算法 distributePanes()5 面板 ÷ 3 列 → [2, 2, 1]5 ÷ 4 → [2, 1, 1, 1]余数面板总是分给前面的列保证整体视觉均衡。应用到 tmux生成布局字符串与三级降级TmuxLayoutApplier.applyPaneLayout() 负责把计算结果写进 tmux整个流程是教科书式的永远有兜底主路径用 generateSidebarGridLayout() 生成 tmux 自定义布局字符串WxHX,Y[...]语法通过tmux select-layout一次性应用一级降级自定义布局应用失败 → 退回 tmux 内置main-vertical布局并把侧边栏设为主面板宽度最终兜底连主路径都抛异常 → 只把侧边栏resize-pane到 40 列保证界面不崩。细节上还有两个值得学习的点应用前会调用 setWindowDimensions() 把窗口window-size设为manual并锁定尺寸且只有尺寸真正变化时才 resize防止 tmux 的自动重排引发resize 循环高度计算时会减去 tmux 状态栏的高度避免底部被截断。占位面板Spacer Pane解决末行拉宽的经典技巧tmux 有个天性最后一行面板不足时会把它们水平拉满整行宽度。5 个面板排成 3 列最后一行 2 个面板会被拉到 140 列宽——完全没法读。SpacerManager 的解法很物理造一个只画灰色圆点的假面板运行 src/panes/spacer-pane.ts 脚本去填满多余空间并用 pane 标题dmux-spacer标记身份方便下次重建时先销毁旧的findSpacerPane()。needsSpacerPane() 的判定也全是算术末行不满 × 均分后单面板宽度超过 MAX → 需要 spacer但算出的 spacer 宽度小于 20 列时反而放弃tmux 会拒绝过窄的面板。创建时还会先保存当前焦点、从最后一个内容面板分屏、创建后恢复焦点用户几乎无感。整套重排流程的入口是 recalculateAndApplyLayout()它在初始化、新建面板、关闭面板、终端 resize四个时机被调用开头还有一道尺寸与面板数都没变就直接返回的短路判断——避免 Ink 不必要的重绘闪烁。Pane 状态检测截图 启发式 LLM 的三级流水线核心问题不碰 Agent 代码如何知道它在干什么dmux 不能要求每个 Agent 都输出标准状态字段所以状态检测走的是看屏幕路线定期抓终端截图 → 启发式规则先筛 → 拿不准的才交给 LLM 判断。目标是既准确又不烧 API 额度。每个 Pane 一个 Worker截图与指纹对比dmux 用 Node 的worker_threads给每个面板开一个独立线程PaneWorker主线程的 Ink 渲染永远不被阻塞。Worker 每 1 秒执行一次 captureAndAnalyze()截图调用 capturePaneContent() 执行tmux capture-pane -p -J抓最近 50 行真实内容行自动跳过尾部空行内容不足就回溯扩大抓取窗口。-J参数会合并折行——这是关键技巧纯窗口宽度变化不会制造假活动指纹对比把截图做指纹buildPaneActivityFingerprint滚动缓存最近 5 份快照至少 3 份采样且指纹不一致才判定有活动活动 → working一旦确认有活动面板立刻标记为working同时清空历史重新开始计时。启发式层词表 正则快而准内容有变化不一定代表 Agent 在干活可能只是你在打字。src/utils/paneAttentionHeuristics.ts 提供了一组零成本的判断规则工作指示器最近 20 行里出现spinner 字符⠋⣾⏳✶… 进行词working / thinking / building / loading… 共 30 余个词GENERIC_PROGRESS_WORDS或出现esc to interrupt→ 直接判working根本不用问 LLM用户输入识别isLikelyUserTyping结合 prompt 正则、$、❯等 16 种提示符PROMPT_PATTERNS区分变化来自人还是变化来自 Agent——人打字会触发 3.5 秒静置期防止误判。静态判定连续多帧内容指纹一致且越过两个静置窗口用户交互后 3.5s、Agent 活动后 1.5sWorker 才把这份稳定下来的截图发往主线程请求 LLM 分析。LLM 三级流水线PaneAnalyzerPaneAnalyzer 把一次面板分析拆成最多三级 LLM 调用temperature 低至 0.1只允许输出 JSON阶段方法输入输出1. 状态判断determineState()面板截图最近 50 行三态之一option_dialog/in_progress/open_prompt2. 选项提取extractOptions()仅当状态 1 为option_dialog问题文本、各选项按键、风险标记3. 摘要生成extractSummary()仅当状态 1 为open_prompt完成摘要 系统通知的标题/正文第一级的 system prompt第 155–189 行写得像验收标准明确要求只看底部 10 行、esc to interrupt出现即判进行中、拿不准一律返回open_prompt——用保守策略避免误报打扰用户。成本与防抖设计是这套流水线的精髓内容哈希缓存对截图内容做 MD5相同内容 5 秒内直接命中缓存setCache()上限 100 条Agent 空闲刷屏也不产生新调用并发去重同一 pane 同一内容的 in-flight 请求共享同一个 PromisependingRequests10 秒超时每个 LLM 请求挂一个AbortController超时即中止并降级为 idlehandleAnalysisRequest()新快照到达时旧的未决请求会被立即取消superseded保证永远只分析最新画面。协调层StatusDetector 把状态送进侧边栏StatusDetector 是状态检测的总调度基于EventEmitter与 Worker 之间的消息总线WorkerMessageBus协作Worker 上报status-change→ 更新内存状态表并向 UI 广播status-updated事件侧边栏的状态标签随之刷新Worker 上报analysis-needed→ 触发上面的 LLM 流水线LLM 三态映射为 UI 四态option_dialog → waiting、open_prompt → idle、in_progress → workingAutopilot自动巡航当面板处于waiting、用户开启了 autopilot、且 LLM 判定无风险时dmux 会自动向该面板发送第一个选项的按键继续执行一旦检测到风险如删除所有文件?立即拒绝自动操作handleAutopilot()waiting/idle状态还会携带通知文案触发桌面系统通知让你在别处也能看到某个 Agent 干完活等你了。两条加速通道Agent Hooks 与轮询兜底Hook 事件文件零延迟Claude / Codex / Grok 都支持生命周期 hooks。dmux 会安装 hooksrc/utils/claudeHooks.ts、codexHooks.tsAgent 的Stop、Notification、PreToolUse等事件会写成一个 JSON 事件文件如worktree/.claude/dmux/paneId.json。Worker 每轮先读这个文件maybeHandleAgentTurnStopped()命中即跳过截图等待直接切换状态——Agent 刚干完活状态标签几乎实时翻成 Done比任何轮询都快。轮询 Worker兜底tmux hooks 未安装时panePollingWorker.ts 在独立线程里每 5 秒执行tmux list-panes对比前后两份快照检测面板增删与焦点变化保证即使完全事件驱动失效侧边栏也最终会跟上真实状态。总结这套设计的三个可复用思想回看 src/layout/ 与 src/services/StatusDetector.ts 这套实现有三个思想值得任何 TUI 项目借鉴确定性优先布局用纯函数计算 评分选择状态检测用词表/正则先筛LLM 只处理最后 10% 的拿不准优雅降级布局三级 fallback、LLM 超时降级 idle、hooks 失效退回轮询——每个环节都有最差也不会崩的保底防抖无处不在布局的维度未变即跳过、截图指纹对比、MD5 内容缓存、10 秒超时取消、2 秒选项延迟确认处处都在抑制不必要的重绘与 API 消耗。想继续深入可以从这几处入手布局模块src/layout/LayoutCalculator.ts、src/layout/SpacerManager.ts状态检测src/services/StatusDetector.ts、src/workers/PaneWorker.ts面板捕获工具src/utils/paneCapture.ts官方文档context/LAYOUT.md理解了网格怎么算出来、状态怎么检测出来dmux 侧边栏上每一个跳动的状态标签对你来说就再没有黑盒了。赞分享【免费下载链接】dmuxA dev agent multiplexer for git worktrees and coding agents.项目地址https://gitcode.com/gh_mirrors/dmu/dmux点击查看免费下载相关推荐用 Ink 搭建向导式 TUI布局、Tab 导航、状态管理与设计配方全解析用 Ink 搭建向导式 TUI布局、Tab 导航、状态管理与设计配方全解析 导读 在 Node.js/TypeScript 生态里面向终端的交互界面TUI后端消息路由前端通信AI Agentwezterm cli zoom-pane在终端里精确控制 pane 缩放状态的完整指南wezterm cli zoom pane在终端里精确控制 pane 缩放状态的完整指南 wezterm cli zoom pane 是 WezTerm 提供桌面应用开发工具跨平台Continue CLI TUI 深度解析基于 Ink 的 React 终端界面与 cwd/git 状态栏设计Continue CLI TUI 深度解析基于 Ink 的 React 终端界面与 cwd/git 状态栏设计 Continue CLI仓库中命令行入口为人工智能AI Agent代码智能体开发工具工具调用RAG创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考