一份脚本、两个身份:Superpowers 跨平台钩子 3 步跑通与避坑指南
一份脚本、两个身份:Superpowers 跨平台钩子 3 步跑通与避坑指南
【免费下载链接】superpowersAn agentic skills framework & software development methodology that works.项目地址: https://gitcode.com/GitHub_Trending/su/superpowers
在新装 Windows 的机器上跑插件,SessionStart 钩子毫无反应:.sh 文件在 CMD 里被记事本打开,$CLAUDE_PLUGIN_ROOT也毫无展开。Superpowers 的解法藏在hooks/目录里——一份"一个脚本、两个身份"的 polyglot(多解释器脚本,即同一段文本被不同解释器按各自语法解析)调度器,让同一套钩子逻辑在 Windows、macOS、Linux 上跑通。
🔍 原理先行:同一份文件,两个解释器各读一半
这套方案能成立,靠的不是"兼容",而是双方各自只看到自己想看的部分。核心就一行开头的把戏:
: << 'CMDBLOCK' # CMD 里以 ":" 开头的行是标签,直接跳过;bash 里 ":" 是空操作,<< 启动 here-doc @echo off # Windows 侧从这里接管:按 3 个标准路径找 bash.exe,找到就执行目标脚本 exit /b 0 # Windows 侧在此退出,下面的内容永远不会被读 CMDBLOCK # bash 的 here-doc 终止符,之前的批量命令全部被"吞掉" exec bash "${SCRIPT_DIR}/${SCRIPT_NAME}" "$@" # Unix 侧:定位本脚本所在目录,执行真正的钩子说白了:
- CMD.exe 眼里,第一行是个被忽略的标签,随后执行批处理逻辑,
exit /b收场; - bash 眼里,第一行是"空命令 + 带引号的 here-doc",
CMDBLOCK之前的所有批处理语法都只是"要原样保留的文本",一行都不会执行; - 带引号的
'CMDBLOCK'保证 here-doc 内容不做变量展开,批处理里的%符号才不会干扰 bash。
两侧行为对照:
| 读到的内容 | Windows 侧(CMD.exe) | Unix 侧(bash/sh) |
|---|---|---|
第一行: << 'CMDBLOCK' | 冒号开头视为标签,跳过 | :空操作,启动 here-doc |
| 批处理段 | 真正执行:校验参数 → 找 bash → 跑目标脚本 | 被 here-doc 吞掉,不执行 |
CMDBLOCK行 | 已经exit /b,到不了这里 | here-doc 终止 |
| Unix 段 | 永远不可达 | exec bash执行实际钩子脚本 |
还有两个不起眼的决策,恰恰是踩坑踩出来的(详见 hooks/run-hook.cmd 内的注释):
- 钩子脚本不带
.sh扩展名:Windows 上 Claude Code 见到路径里有.sh会自动前缀bash,直接绕过调度器; - 找不到 bash 就静默
exit /b 0:没装 Git for Windows 的用户,插件照常工作,只是跳过钩子,而不是报错; - 不用
-l登录 shell、不用cygpath:钩子脚本应自包含,bash 直接接收 Windows 路径即可正确处理。
🔧 最小复现:hooks/ 目录里的三个文件
不用重写,直接照着仓库走三步:
克隆仓库:
git clone https://gitcode.com/GitHub_Trending/su/superpowers打开
hooks/目录,看懂三个文件的分工:- hooks/hooks.json——声明钩子命令
"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd" session-start,并指定"shell": "bash"强制走 Git Bash 通道; - hooks/run-hook.cmd——polyglot 调度器本体,也就是上面拆解的那个"两个身份"文件;
- hooks/session-start——真正的钩子逻辑,一个无扩展名的 bash 脚本(注意:不是
session-start.sh)。
- hooks/hooks.json——声明钩子命令
完整原理与取舍在 docs/windows/polyglot-hooks.md 里写得很清楚(文档还特别声明:文档与代码不一致时以代码为准)。改动调度器后,跑一下 tests/hooks/test-session-start.sh 回归验证。
⚠️ 踩坑速查表:四个真实事故
钩子静默不触发。现象是没有任何报错,钩子就是不跑,最容易误判为配置丢失。原因:调度器依次探测C:\Program Files\Git、C:\Program Files (x86)\Git和 PATH 三个位置的 bash,一个都没有时按设计静默退出 0。修法:把 Git for Windows 装到默认路径,或让bash进 PATH。
脚本带了 .sh 后缀。现象是 macOS 上正常、Windows 上没反应。原因:Claude Code 的 Windows 端看到命令里含.sh就自动前缀bash,绕开了 CMD 调度器这条路。修法:脚本一律无扩展名(如session-start),hooks.json里的命令同步改。
matcher 对不上事件名。现象是钩子在任何事件下都不触发。原因:不同宿主的事件名不同,Claude Code 用startup|clear|compact,Cursor 用sessionStart。修法:核对hooks.json的matcher;Cursor 场景看同目录的 hooks/hooks-cursor.json。
依赖 login-shell 的 PATH。现象是终端里手跑没问题,作为钩子就挂。原因:调度器不带-l,钩子脚本拿不到登录 shell 的 PATH,sed、awk这类外部命令可能根本找不到。修法:钩子逻辑尽量用纯 bash 内置命令实现,所有变量展开写成"$VAR"形式。
收益与延伸阅读
收益一句话:钩子逻辑只写一份 bash,调度层用"一份脚本、两个身份"消化掉 CMD 与 bash 的语法鸿沟,三个平台同一套行为,不再为 Windows 单独维护脚本。
深入建议直接读 hooks/run-hook.cmd 源码和 docs/windows/polyglot-hooks.md,改完用 tests/hooks/test-session-start.sh 兜底。
【免费下载链接】superpowersAn agentic skills framework & software development methodology that works.项目地址: https://gitcode.com/GitHub_Trending/su/superpowers
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
