Skip to content

Plannotator 故障排查 ​

学完你能做什么 ​

遇到问题时,你将能够:

  • 快速定位问题来源(端口占用、Hook event 解析、Git 配置等)
  • 通过日志输出诊断错误
  • 针对不同错误类型采取正确的解决方法
  • 在远程/Devcontainer 模式下调试连接问题

你现在的困境 ​

Plannotator 突然不工作了,浏览器没有打开,或者 Hook 输出了错误信息。你不知道如何查看日志,也不确定是哪个环节出了问题。你可能尝试过重启,但问题依然存在。

什么时候用这一招 ​

以下情况需要故障排查:

  • 浏览器没有自动打开
  • Hook 输出错误信息
  • 端口占用导致无法启动
  • 计划或代码评审页面显示异常
  • Obsidian/Bear 集成失败
  • Git diff 显示为空

核心思路 ​

Plannotator 的问题通常分为三类:

  1. 环境问题:端口占用、环境变量配置错误、浏览器路径问题
  2. 数据问题:Hook event 解析失败、计划内容为空、Git 仓库状态异常
  3. 集成问题:Obsidian/Bear 保存失败、远程模式连接问题

调试的核心是查看日志输出。Plannotator 使用 console.error 输出错误到 stderr,用 console.log 输出正常信息到 stdout。区分这两者能帮你快速定位问题类型。


🎒 开始前的准备 ​

  • ✅ 已安装 Plannotator(Claude Code 或 OpenCode 插件)
  • ✅ 了解基本的命令行操作
  • ✅ 熟悉你的项目目录和 Git 仓库状态

跟我做 ​

第 1 步:检查日志输出 ​

为什么

Plannotator 的所有错误都会输出到 stderr。查看日志是诊断问题的第一步。

操作方法

在 Claude Code 中 ​

当 Hook 触发 Plannotator 时,错误信息会显示在 Claude Code 的终端输出中:

bash
# 你可能看到的错误示例
Error: Port 54321 in use after 5 retries (set PLANNOTATOR_PORT to use different port)

在 OpenCode 中 ​

OpenCode 会捕获 CLI 的 stderr 并显示在界面中:

[stderr] Failed to parse hook event from stdin
[stderr] No plan content in hook event

你应该看到:

  • 如果没有错误,stderr 应该为空或仅有预期的提示信息
  • 如果有错误,会包含错误类型(如 EADDRINUSE)、错误消息和堆栈信息(如果有)

第 2 步:处理端口占用问题 ​

为什么

Plannotator 默认在随机端口启动服务器。如果固定端口被占用,服务器会尝试重试 5 次(每次延迟 500ms),失败后报错。

错误信息:

Error: Port 54321 in use after 5 retries (set PLANNOTATOR_PORT to use different port)

解决方案

方案 A:让 Plannotator 自动选择端口(推荐) ​

不要设置 PLANNOTATOR_PORT 环境变量,Plannotator 会自动选择可用端口。

方案 B:使用固定端口并解决占用 ​

如果必须使用固定端口(如远程模式),需要解决端口占用:

bash
# macOS/Linux
lsof -ti:54321 | xargs kill -9

# Windows PowerShell
Get-NetTCPConnection -LocalPort 54321 | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }

然后重新设置端口:

bash
# macOS/Linux/WSL
export PLANNOTATOR_PORT=54322

# Windows PowerShell
$env:PLANNOTATOR_PORT = "54322"

检查点 ✅:

  • 再次触发 Plannotator,浏览器应该能正常打开
  • 如果仍然报错,尝试换一个端口号

第 3 步:调试 Hook event 解析失败 ​

为什么

Hook event 是从 stdin 读取的 JSON 数据。如果解析失败,Plannotator 无法继续。

错误信息:

Failed to parse hook event from stdin
No plan content in hook event

可能原因:

  1. Hook event 不是有效的 JSON
  2. Hook event 缺少 tool_input.plan 字段
  3. Hook 版本不兼容

调试方法

查看 Hook event 内容 ​

在 Hook server 启动前,打印 stdin 内容:

bash
# 暂时修改 hook/server/index.ts
# 在第 91 行后添加:
console.error("[DEBUG] Hook event:", eventJson);

你应该看到:

json
{
  "tool_input": {
    "plan": "# Implementation Plan\n\n## Task 1\n..."
  },
  "permission_mode": "default"
}

解决方案:

  • 如果 tool_input.plan 为空或缺失,检查 AI Agent 是否正确生成了计划
  • 如果 JSON 格式错误,检查 Hook 配置是否正确
  • 如果 Hook 版本不兼容,更新 Plannotator 到最新版本

第 4 步:解决浏览器未打开问题 ​

为什么

Plannotator 使用 openBrowser 函数自动打开浏览器。如果失败,可能是跨平台兼容性问题或浏览器路径错误。

可能原因:

  1. 系统默认浏览器未设置
  2. 自定义浏览器路径无效
  3. WSL 环境下的特殊处理问题
  4. 远程模式下不会自动打开浏览器(这是正常的)

调试方法

检查是否在远程模式 ​

bash
# 查看环境变量
echo $PLANNOTATOR_REMOTE

# Windows PowerShell
echo $env:PLANNOTATOR_REMOTE

如果输出为 1 或 true,说明是远程模式,浏览器不会自动打开,这是预期行为。

手动测试浏览器打开 ​

bash
# macOS
open "http://localhost:54321"

# Linux
xdg-open "http://localhost:54321"

# Windows
start http://localhost:54321

你应该看到:

  • 如果手动打开成功,说明 Plannotator 服务器正常运行,问题出在自动打开逻辑
  • 如果手动打开失败,检查 URL 是否正确(端口可能不同)

解决方案:

方案 A:设置自定义浏览器(macOS) ​

bash
export PLANNOTATOR_BROWSER="Google Chrome"

# 或使用完整路径
export PLANNOTATOR_BROWSER="/Applications/Google Chrome.app"

方案 B:设置自定义浏览器(Linux) ​

bash
export PLANNOTATOR_BROWSER="/usr/bin/firefox"

方案 C:远程模式手动打开(Devcontainer/SSH) ​

bash
# Plannotator 会输出 URL 和端口信息
# 复制 URL,在本地浏览器中打开
# 或使用端口转发:
ssh -L 19432:localhost:19432 user@remote

第 5 步:检查 Git 仓库状态(代码评审) ​

为什么

代码评审功能依赖 Git 命令。如果 Git 仓库状态异常(如没有提交、Detached HEAD),会导致 diff 显示为空或错误。

错误信息:

Git diff error for uncommitted: Error: Command failed: git diff HEAD

调试方法

检查 Git 仓库 ​

bash
# 检查是否在 Git 仓库中
git status

# 检查当前分支
git branch

# 检查是否有提交
git log --oneline -1

你应该看到:

  • 如果输出 fatal: not a git repository,说明当前目录不是 Git 仓库
  • 如果输出 HEAD detached at <commit>,说明处于 Detached HEAD 状态
  • 如果输出 fatal: your current branch 'main' has no commits yet,说明还没有任何提交

解决方案:

问题 A:不在 Git 仓库中 ​

bash
# 初始化 Git 仓库
git init
git add .
git commit -m "Initial commit"

问题 B:Detached HEAD 状态 ​

bash
# 切换到一个分支
git checkout main
# 或创建新分支
git checkout -b feature-branch

问题 C:没有提交 ​

bash
# 至少需要一个提交才能查看 diff
git add .
git commit -m "Initial commit"

问题 D:空 diff(没有更改) ​

bash
# 创建一些更改
echo "test" >> test.txt
git add test.txt

# 再次运行 /plannotator-review

检查点 ✅:

  • 再次运行 /plannotator-review,diff 应该正常显示
  • 如果仍然为空,检查是否有未暂存或未提交的更改

第 6 步:调试 Obsidian/Bear 集成失败 ​

为什么

Obsidian/Bear 集成失败不会阻止计划批准,但会导致保存失败。错误会输出到 stderr。

错误信息:

[Obsidian] Save failed: Vault not found
[Bear] Save failed: Failed to open Bear

调试方法

检查 Obsidian 配置 ​

macOS:

bash
cat ~/Library/Application\ Support/obsidian/obsidian.json

Windows:

powershell
cat $env:APPDATA\obsidian\obsidian.json

你应该看到:

json
{
  "vaults": {
    "/path/to/vault": {
      "path": "/path/to/vault",
      "ts": 1234567890
    }
  }
}

检查 Bear 可用性(macOS) ​

bash
# 测试 Bear URL scheme
open "bear://x-callback-url/create?title=Test&text=Hello"

你应该看到:

  • Bear 应用打开并创建新笔记
  • 如果没有任何反应,说明 Bear 未正确安装

解决方案:

Obsidian 保存失败 ​

  • 确保 Obsidian 正在运行
  • 检查 vault 路径是否正确
  • 尝试手动在 Obsidian 中创建笔记,验证权限

Bear 保存失败 ​

  • 确保 Bear 已正确安装
  • 测试 bear://x-callback-url 是否可用
  • 检查 Bear 设置中是否启用了 x-callback-url

第 7 步:查看详细错误日志(调试模式) ​

为什么

有时错误信息不够详细,需要查看完整的堆栈跟踪和上下文。

操作方法

启用 Bun 调试模式 ​

bash
export DEBUG="*"
plannotator review

# Windows PowerShell
$env:DEBUG = "*"
plannotator review

查看 Plannotator 服务器日志 ​

服务器内部的错误会通过 console.error 输出。关键日志位置:

  • packages/server/index.ts:260 - 集成错误日志
  • packages/server/git.ts:141 - Git diff 错误日志
  • apps/hook/server/index.ts:100-106 - Hook event 解析错误

你应该看到:

bash
# 成功保存到 Obsidian
[Obsidian] Saved plan to: /path/to/vault/Plan - 2026-01-24.md

# 保存失败
[Obsidian] Save failed: Cannot write to directory
[Bear] Save failed: Failed to open Bear

# Git diff 错误
Git diff error for uncommitted: Error: Command failed: git diff HEAD

检查点 ✅:

  • 错误日志包含足够的信息来定位问题
  • 根据错误类型采取对应的解决方案

踩坑提醒 ​

❌ 忽略 stderr 输出 ​

错误做法:

bash
# 只关注 stdout,忽略 stderr
plannotator review 2>/dev/null

正确做法:

bash
# 同时查看 stdout 和 stderr
plannotator review
# 或分离日志
plannotator review 2>error.log

❌ 盲目重启服务器 ​

错误做法:

  • 遇到问题就重启,不查看错误原因

正确做法:

  • 先查看错误日志,确定问题类型
  • 根据错误类型采取对应的解决方案
  • 重启只是最后的手段

❌ 在远程模式下期待浏览器自动打开 ​

错误做法:

bash
export PLANNOTATOR_REMOTE=1
plannotator review
# 期待浏览器自动打开(不会发生)

正确做法:

bash
export PLANNOTATOR_REMOTE=1
plannotator review
# 记录输出的 URL,手动在浏览器中打开
# 或使用端口转发

本课小结 ​

  • Plannotator 使用 console.error 输出错误到 stderr,console.log 输出正常信息到 stdout
  • 常见问题包括:端口占用、Hook event 解析失败、浏览器未打开、Git 仓库状态异常、集成失败
  • 调试的核心是:查看日志 → 定位问题类型 → 采取对应解决方案
  • 远程模式下不会自动打开浏览器,需要手动打开 URL 或配置端口转发

下一课预告 ​

下一课我们学习 常见问题。

你会学到:

  • 如何解决安装和配置问题
  • 常见的使用误区和注意事项
  • 性能优化建议

附录:源码参考 ​

点击展开查看源码位置

更新时间:2026-01-24

功能文件路径行号
端口重试机制packages/server/index.ts79-80
EADDRINUSE 错误处理packages/server/index.ts320-334
Hook event 解析apps/hook/server/index.ts91-107
浏览器打开packages/server/browser.ts45-74
Git diff 错误处理packages/server/git.ts139-144
Obsidian 保存日志packages/server/index.ts242-246
Bear 保存日志packages/server/index.ts252-256

关键常量:

  • MAX_RETRIES = 5:端口重试最大次数
  • RETRY_DELAY_MS = 500:端口重试延迟(毫秒)

关键函数:

  • startPlannotatorServer():启动计划评审服务器
  • startReviewServer():启动代码评审服务器
  • openBrowser():跨平台浏览器打开
  • runGitDiff():执行 Git diff 命令
  • saveToObsidian():保存计划到 Obsidian
  • saveToBear():保存计划到 Bear