
Roo Code CLI 调试指南用文件日志替代 console.log 排查 TUI 问题【免费下载链接】Roo-CodeRoo Code gives you a whole dev team of AI agents in your code editor.项目地址: https://gitcode.com/GitHub_Trending/ro/Roo-CodeRoo Code CLI 在终端中以 TUITerminal User Interface方式交互运行时直接调用console.log会与界面渲染抢占终端输出、打乱布局甚至导致界面无法正常刷新。本文基于仓库中的调试规则文档系统讲解“文件日志File-Based Logging”调试方法把调试信息写入临时日志文件而非控制台并配合一套可复现的迭代调试闭环快速定位 CLI 运行时的执行流程、状态变化与错误根因。读完本文你将掌握一套不依赖 IDE 断点、可在任何终端环境下稳定运行的 CLI 调试实战方案并了解 Roo Code 仓库内建的文件日志设施--debug与~/.roo/cli-debug.log的底层实现原理。为什么 CLI 调试不能直接使用 console.logRoo Code CLI 默认以交互式 TUI 模式运行apps/cli/README.md终端界面由 Ink 之类的全屏渲染框架驱动整个屏幕的绘制、刷新都建立在“输出流完全受控”的前提之上。此时任何突发的console.log输出都会混入 TUI 正在渲染的区域破坏布局打乱光标与滚动位置导致界面闪烁或显示错乱使调试信息本身也无法被正常阅读形成“既看不清界面、也看不清日志”的双输局面。更关键的是从源码看这种冲突是有意为之ExtensionHost在加载扩展时就会进入“安静模式quiet mode”直接把console.log、console.warn、console.debug、console.info等全部替换为空操作见 extension-host.ts只有console.error等个别输出在特定时机如向用户提问前才会被临时恢复。也就是说在 CLI 运行期间你即使写了console.log多数时候也根本看不到输出——这正是规则文档要求“将日志写入文件而不是控制台”的根本原因。// 来自 extension-host.ts 的 setupQuietMode 实现示意 console.log () {} console.warn () {} console.debug () {} console.info () {}因此调试 CLI 的第一原则是永远把调试信息重定向到文件让 TUI 独占终端输出。文件日志策略最小可用的日志工具规则文档推荐的核心做法非常直接写一个带时间戳的文件追加日志函数所有调试信息都经由它落盘。选择一个已知的日志文件路径例如/tmp/roo-cli-debug.log临时目录便于随时查看与清理使用fs.appendFileSync()同步追加日志条目——同步写入可以避免异步竞态导致日志顺序错乱在调试场景下性能开销完全可以接受每条日志携带ISO 时间戳数据对象用JSON.stringify(data, null, 2)格式化保证可读性。import fs from fs const DEBUG_LOG /tmp/roo-cli-debug.log function debugLog(message: string, data?: unknown) { const timestamp new Date().toISOString() const entry data ? [${timestamp}] ${message}: ${JSON.stringify(data, null, 2)}\n : [${timestamp}] ${message}\n fs.appendFileSync(DEBUG_LOG, entry) }这条工具函数是整个调试方案的基础调用点只需要写一行debugLog(..., {...})就能获得带时间、带结构化数据的持久化记录。值得注意的是仓库内建的调试设施采用了完全一致的设计理念——packages/core/src/debug-log/index.ts中的debugLog同样基于fs.appendFileSync同样输出[${timestamp}] ${message}: ${JSON.stringify(data, null, 2)}格式见 debug-log/index.ts只是官方实现把日志落到了~/.roo/cli-debug.log并由setDebugLogEnabled()控制开关。你可以把本节的DEBUG_LOG常量换成任何你方便读取的路径机制完全相同。每次调试会话前先清空日志由于日志是持续追加的旧会话的残留会干扰新一轮分析。规则文档要求每次调试前清空日志文件echo /tmp/roo-cli-debug.log或者在应用启动处于调试模式时用代码清空fs.writeFileSync(DEBUG_LOG, )这样每一轮日志只包含当前会话的内容文件末尾即最新状态配合cat/tail查看时不会与历史噪音混淆。迭代调试工作流把“猜测”变成“闭环验证”文件日志的价值不只在于“能看到输出”更在于它能支撑一套系统化的迭代排查流程。规则文档给出了清晰的 7 步反馈闭环在怀疑的问题区域添加针对性日志——基于你的假设在关键代码路径埋点让用户用 CLI 正常复现问题——保持操作环境干净不要在调试进程里人为干扰测试完成后读取日志文件cat /tmp/roo-cli-debug.log分析日志输出重点寻找四类线索执行流程与时间顺序哪些分支先走、哪些后走、耗时如何关键节点的变量值当前值是否符合预期实际走通的代码路径你的假设路径是否被命中错误条件或异常状态抛出点、失败分支。根据发现精炼日志——需要更多细节的地方补日志产生噪音的地方移除让用户使用更新后的日志再次测试重复上述循环直到根因被定位。这个闭环的核心思想是每一步都用“上一轮日志的新证据”驱动下一轮的埋点而不是盲目地到处加日志碰运气。它把调试从一个一次性的动作变成一个有收敛方向的循环过程非常适合 CLI 这种“难以打断、依赖复现”的场景。日志最佳实践为了让日志既充分又有序规则文档总结了如下要点记录被调查函数的入口与出口——入口记参数出口记返回值形成完整的调用轨迹包含相关的变量值与状态信息——仅记录“进入了函数”没有意义要记录当时的关键数据使用描述性前缀分类日志例如[STATE]、[EVENT]、[ERROR]、[FLOW]便于grep快速过滤debugLog([STATE] Current selection state, { currentValue, isOpen }) debugLog([ERROR] fetchOptions failed, { error: error.message })同时记录“正常路径”与“错误处理分支”——两条路径都要有日志否则无法确认错误分支是否被触发处理异步操作时在await前后各记一条——异步是最容易丢失信息的地方前后对照才能还原时序debugLog([FLOW] fetchOptions started, { query }) const result await fetchOptions() debugLog([FLOW] fetchOptions completed, { resultCount: result.length })对用户交互记录“收到的输入”和“随后触发的动作”——这是排查交互类问题如下拉选择、按键响应的关键证据链。示例调试会话排查 Picker 选择问题以 CLI 界面中常见的下拉选择组件PickerSelect见 PickerSelect.tsx为例规则文档给出了一个完整的埋点示范// 为排查一个选择器picker选中异常的问题添加日志 debugLog([FLOW] PickerSelect onSelect called, { selectedIndex, item }) debugLog([STATE] Current selection state, { currentValue, isOpen }) // 异步操作完成后 const result await fetchOptions() debugLog([FLOW] fetchOptions completed, { resultCount: result.length })埋点完成后引导用户复现“请按以下步骤复现该问题[具体操作步骤]。完成后告诉我我会分析调试日志。”随后用cat /tmp/roo-cli-debug.log拉取日志通过[FLOW]前缀确认回调是否被触发、通过[STATE]对照选择状态是否符合预期、通过fetchOptions completed的resultCount判断数据层是否正常——三条日志即可把“界面回调”“组件状态”“数据获取”三个嫌疑点全部覆盖。仓库内建的文件日志设施--debug 与 ~/.roo/cli-debug.log如果你在使用 Roo Code CLI 时遇到了问题仓库本身已经内置了与规则文档同理念的文件日志能力无需自己埋点即可先查看官方日志开启方式在启动命令中追加-d/--debug标志选项定义见 index.ts。默认情况下文件日志是关闭的只有传入该标志时才会启用——这一点在 apps/cli/CHANGELOG.md 中有明确记录“Debug log file is now disabled by default unless--debugflag is passed”。落盘位置~/.roo/cli-debug.log。ExtensionHost构造时会调用setDebugLogEnabled(true)打开开关见 extension-host.tsDebugLogger内部通过fs.appendFileSync以带时间戳的 JSON 行格式追加写入见 debug-log/index.ts。实时查看tail -f ~/.roo/cli-debug.log官方日志的典型输出日志按组件命名如CLI、MessageProcessor同时记录了消息流与状态机迁移例如 AGENT_LOOP.md 中给出的片段[MessageProcessor] State update: { messageCount: 5, lastMessage: { msgType: ask:completion_result }, stateTransition: running → idle, currentAsk: completion_result, isWaitingForInput: true } [MessageProcessor] EMIT waitingForInput: { ask: completion_result } [MessageProcessor] EMIT taskCompleted: { success: true }官方日志与规则文档方案的取舍两者遵循完全相同的“写入文件而非终端”原则可以互为补充维度规则文档方案自建 debugLog仓库内建方案-d / --debug日志位置自行指定如/tmp/roo-cli-debug.log固定为~/.roo/cli-debug.log开启方式代码内主动调用CLI 参数-d/--debug全局开启适用场景定位自己新增代码的逻辑问题快速了解 CLI 内部消息流与状态机行为写入方式fs.appendFileSync 时间戳 JSON同上由DebugLogger统一封装排查自己写的功能时优先用自建debugLog精准埋点怀疑是 CLI 框架本身的问题时直接开-d看官方日志。两者结合即可覆盖从“业务逻辑”到“框架行为”的完整排查面。总结Roo Code CLI 的 TUI 特性决定了调试必须走“文件日志”路线终端输出留给界面诊断信息落盘为文件。本文围绕这一核心策略展开你可以按以下要点落地实践不要用console.log调试 TUI——它会被 ExtensionHost 的安静模式吞掉即便侥幸输出也会破坏界面建立带时间戳的fs.appendFileSync日志函数统一写入已知路径如/tmp/roo-cli-debug.log每次调试前清空日志保证会话隔离走完“埋点 → 让用户复现 → cat 日志 → 分析 → 精炼 → 再测”的迭代闭环用证据收敛根因善用前缀分类、入口/出口埋点、await 前后成对日志等实践让日志可检索、时序可还原需要快速了解框架行为时直接使用内建的-d/--debug与~/.roo/cli-debug.log。这套方法不依赖特定调试器或 IDE在任何终端环境、任何语言编写的 CLI 项目中都可以直接复用。【免费下载链接】Roo-CodeRoo Code gives you a whole dev team of AI agents in your code editor.项目地址: https://gitcode.com/GitHub_Trending/ro/Roo-Code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考