问题:同一个 hook,CLI 里看得见,桌面端却「没反应」
不少人给 Claude Code 写了 hook:改完文件提示一句、跑完检查打印结果、会话结束时汇总。终端 CLI 里一切正常,换到桌面端或其他界面再用,同一个 hook 的部分输出却不显示——有时消息其实已写进会话记录,只是界面没展示出来。
这类「两端表现不一致」很容易让人误判:以为 hook 没执行,于是反复改配置;或者以为检查通过了,其实它早就报错。根本原因往往不是 hook 本身,而是你把「界面上看到了」当成了「hook 跑过了」的唯一证据。
更稳的思路是:hook 的执行结果写进机器上的日志文件,界面显示只当辅助;再把这套配置放到新加坡常开的 Mac mini 上,CLI 和桌面端读的是同一台机器、同一份配置、同一个日志。
步骤一:先确认两端读的是不是同一份配置
很多「不一致」其实是配置根本不同:
- 列出可能生效的配置位置:用户级
~/.claude/settings.json、项目级.claude/settings.json、本地覆盖.claude/settings.local.json(具体层级以你当前版本文档为准)。 - 确认桌面端打开的工作目录就是 CLI 所在的仓库根目录;工作目录不同,项目级 hook 就不会加载。
- 在两端分别执行一次相同的小任务,对比 hook 是否触发。
在 Mac mini 上可以快速对照:
cd "$HOME/work/your-app"
ls -la ~/.claude/settings.json .claude/settings.json .claude/settings.local.json 2>/dev/null
shasum ~/.claude/settings.json .claude/settings.json 2>/dev/null
如果你在笔记本上跑 CLI、在另一台机器上开桌面端,两边的 ~/.claude 本来就不是同一份。统一到一台机器,是排除这一类问题最省事的办法。
步骤二:让 hook 把结果写进日志,而不是只靠界面
把 hook 命令包成一个脚本,脚本做三件事:记录时间与触发事件、执行真正的检查、把输出和退出码追加到日志。
#!/bin/bash
# scripts/claude-hook.sh
LOG="$HOME/Library/Logs/claude-hooks.log"
EVENT="${1:-unknown}"
{
echo "=== $(date '+%F %T') event=$EVENT cwd=$PWD"
./scripts/check.sh 2>&1
echo "exit=$?"
} >> "$LOG"
tail -n 20 "$LOG"
然后在 .claude/settings.json 里引用它(示意结构,事件名与字段请按当前版本文档校正):
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "./scripts/claude-hook.sh post-edit" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "./scripts/claude-hook.sh stop" }
]
}
]
}
}
要点:
- 日志是唯一事实来源:界面显示与否,日志里都应有一条带时间和退出码的记录。
- 脚本非交互:不弹窗、不等输入,否则在某一端可能直接卡住。
- 输出精简:hook 往界面回传大段文本,某些界面可能折叠或不展示;把完整内容留在日志,界面只回传结论。
- 记得
chmod +x,并在终端手动跑一遍确认路径正确。
步骤三:两端各跑一次,对照日志
在新加坡 Mac mini 上开一个终端窗口持续看日志:
tail -f "$HOME/Library/Logs/claude-hooks.log"
然后:
- 在 CLI 里让 Claude Code 改一个小文件,观察日志是否出现
event=post-edit。 - 在桌面端打开同一个仓库,做同样的操作,再看日志。
- 对照三种情况:
- 两端日志都有记录 → hook 正常执行,差异只在显示层,不用再改 hook 逻辑。 - 只有一端有记录 → 回到步骤一,查工作目录和配置层级。 - 两端都没有 → hook 配置本身有误,先在终端单独运行脚本排错。
这样排查一次就能分清「没执行」和「没显示」,不用在两个界面之间来回猜。
步骤四:放到常开的 Mac mini 上,长期统一
本机笔记本既当编辑器、又当运行环境时,合盖、睡眠、切换网络都会打断会话,hook 日志也散落在不同机器上。把运行环境集中到一台常开的新加坡 Mac mini:
- 用 UU 远程连接打开桌面端,用 SSH 进终端跑 CLI,两者都落在同一台机器、同一个用户。
- CLI 会话放进
tmux,断线后tmux attach接回,不丢上下文。 - 日志统一在
~/Library/Logs/claude-hooks.log,定期用newsyslog或简单脚本轮转,避免越写越大。 - 把
scripts/claude-hook.sh和.claude/settings.json一起提交进仓库,团队成员看到的是同一套规则。
步骤五:常见坑
| 现象 | 常见原因 | 处理 | |------|----------|------| | 桌面端完全不触发 | 打开的不是仓库根目录 | 从仓库根打开项目 | | 触发了但界面没提示 | 显示层折叠或不展示该类输出 | 以日志为准,界面只回传一行结论 | | 脚本找不到 | 相对路径基于不同工作目录 | 脚本内用 $(git rev-parse --show-toplevel) 定位 | | 环境变量缺失 | 图形界面启动的进程不读你的 shell 配置 | 在脚本里显式设置 PATH |
最后一条在 macOS 上很常见:终端里能找到 node,图形界面启动的进程却找不到。在脚本开头写一句 export PATH="/opt/homebrew/bin:$PATH" 就能避免。
Zumac.Ai 怎么帮你
Zumac.Ai 在新加坡提供 Mac mini 整机独享,适合把 Claude Code CLI、桌面端和 hook 日志集中在同一台常开机器上。新客户整机租用 ¥999/月 起,季付、半年付、年付有折扣。交付后可用 UU 远程连接,SSH 按你的安全策略自行开启。Claude 账号由你自行准备,我们只提供稳定合规的使用环境。实际延迟取决于你本地的网络线路。咨询可 Telegram @singatao。
小结
CLI 和桌面端对 hook 输出的展示可能不一致,别把「界面看到了」当成唯一证据。先确认两端读同一份配置、同一个工作目录,再让 hook 把带退出码的记录写进日志,两端各跑一次对照。最后把运行环境集中到一台新加坡常开 Mac mini 上,配置、日志、会话都在一处,排查和长期维护都简单得多。
