命令行补全通常不会影响核心业务逻辑,但它会直接影响开发者每天的使用体验。尤其是 Zsh 用户,如果补全脚本语法错误,按 Tab 时不仅没有提示,还会抛出一串 _arguments 错误。
NousResearch/hermes-agent issue `#22686` 记录了一个具体问题:hermes completion zsh 生成的 Zsh completion script 中 _arguments 写法不符合 Zsh 语法,导致补全脚本被拒绝。
错误信息是:
_arguments:comparguments:327: invalid argument: (-h --help){-h,--help}[Show help and exit]
这类问题看起来小,但搜索价值很明确:zsh _arguments invalid argument、(-h --help){-h,--help}、hermes completion zsh,都是用户真实会复制搜索的错误片段。
复现:生成 zsh completion 后语法不合法
触发路径很直接:
hermes completion zsh
生成的脚本里有类似内容:
_arguments -C \
'(-h --help){-h,--help}[Show help and exit]' \
'(-V --version){-V,--version}[Show version and exit]' \
'(-p --profile){-p,--profile}[Profile name]:profile:_hermes_profiles' \
'1:command:->commands' \
'*::arg:->args'
问题集中在这几段:
'(-h --help){-h,--help}[Show help and exit]'
'(-V --version){-V,--version}[Show version and exit]'
'(-p --profile){-p,--profile}[Profile name]:profile:_hermes_profiles'
Zsh 的 _arguments 解析器看到 (-h --help) 后会报 invalid argument。
根因:() exclusion group 不能这样放长选项
在 Zsh completion 语法中,_arguments 的 option spec 可以包含 exclusion group,用来表示互斥关系。
但 issue 指出,像下面这种写法不合法:
(-h --help)
原因有两个:
1. group 中不应该混入 --help 这类长选项; 2. -h --help 中间有空格,整体被 _arguments 当成无效 spec。
换句话说,{-h,--help} 可以用来描述短/长选项形式,但前面的 exclusion group 不是同一回事。
这两个部分不能简单拼成:
'(-h --help){-h,--help}[...]'
修正:用 (-) 或只放合法短选项
issue 中给出的目标写法是:
'(-)'{-h,--help}'[Show help and exit]'
对应替换包括:
- '(-h --help){-h,--help}[Show help and exit]'
+ '(-)'{-h,--help}'[Show help and exit]'
- '(-V --version){-V,--version}[Show version and exit]'
+ '(-)'{-V,--version}'[Show version and exit]'
- '(-p --profile){-p,--profile}[Profile name]:profile:_hermes_profiles'
+ '(-)'{-p,--profile}'[Profile name]:profile:_hermes_profiles'
后续评论中的 draft PR `#22728` 又补充了更细一点的修正:
help/version 使用 (-)
profile 使用 (-p)
并且生成结果通过:
zsh -n
验证没有语法错误。
为什么 zsh -n 很适合做回归测试?
补全脚本的 bug 很容易被忽略,因为它不一定出现在普通单元测试里。
对 Zsh completion generator 来说,至少应该做两层检查:
hermes completion zsh > /tmp/_hermes
zsh -n /tmp/_hermes
这能捕获明显语法错误。
如果要进一步验证交互效果,还可以在测试 shell 中加载:
fpath=(/tmp $fpath)
autoload -Uz compinit
compinit
compdef _hermes hermes
但对 CI 来说,zsh -n 已经能防止 _arguments spec 写坏后直接发布。
为什么 CLI completion bug 也值得修?
补全脚本不像 gateway、model adapter、tool execution 那样“核心”,但它影响的是第一层开发体验。
Zsh 用户安装 Hermes 后,通常会期待:
hermes <TAB>
hermes gateway <TAB>
hermes config <TAB>
hermes completion <TAB>
如果每次按 Tab 都看到:
_arguments:comparguments:327: invalid argument
用户很容易误以为整个 CLI 安装坏了。
对开发者工具来说,completion 是“信任感入口”。小错误会放大成对项目成熟度的怀疑。
排查清单:遇到 _arguments: invalid argument 先看什么?
如果你遇到类似错误,可以按这个顺序查。
1. 直接生成补全脚本
hermes completion zsh > /tmp/_hermes
2. 用 zsh -n 验证语法
zsh -n /tmp/_hermes
如果这里报错,说明不是你的 .zshrc 问题,而是补全脚本本身语法有问题。
3. 搜索 _arguments 行
grep "_arguments" -n /tmp/_hermes
重点看是否存在:
(-h --help)
(-V --version)
(-p --profile)
4. 检查短/长选项写法
短/长形式可以写成:
{-h,--help}
但 exclusion group 不应写成:
(-h --help)
5. 更新 Hermes 或套用修复后的生成器
如果上游已修复,优先更新到包含修复的版本。不要长期手改生成出来的 _hermes 文件,因为下一次生成会覆盖。
外链与进一步阅读
- GitHub issue:`NousResearch/hermes-agent #22686`
- Draft PR:`NousResearch/hermes-agent #22728`
- Hermes Agent 项目:`NousResearch/hermes-agent`
- Zsh completion 相关背景可参考 Zsh 官方文档中的 completion system 与
_arguments说明。
站内相关分析:
- `/reload-mcp 一按就卡死:Hermes CLI 为什么会在确认框里等不到回车?`
- `delegate_task 为什么会偏向 Claude?从工具 schema priming 看 Hermes 子代理路由误导`
- `Hermes terminal 误拦截 setsid:安全过滤为什么不能只靠全文正则`
与 DeepAI API 中转站的关系:CLI 体验和模型路由是两条线
很多用户会把 Hermes、Cline、Cherry Studio、Dify、Open WebUI 这类工具接到 DeepAI API 中转站,统一管理 Base URL、API Key、模型路由和 OpenAI-compatible 调用。
但 CLI completion 属于本地命令行体验层:
shell → completion script → hermes command layout
而模型 API 层关注的是:
Base URL → API Key → model id → streaming/tool calling/usage/context length
两条线可以同时优化:模型入口统一,CLI 补全也要稳定。对开发者工具来说,API 能调通只是基础,命令行交互、补全、错误提示同样会影响日常效率。
FAQ
_arguments:comparguments:327: invalid argument 是什么意思?
表示 Zsh 的 _arguments 解析器遇到了不合法的 option spec。这里的问题是 (-h --help){-h,--help} 这类写法不符合 Zsh completion 语法。
为什么 {-h,--help} 可以,(-h --help) 不行?
{-h,--help} 是短/长选项形式展开;() 是 exclusion group。后者不应混入带空格的长选项组合。
我应该手动改 _hermes 文件吗?
临时可以,但不建议长期依赖。更好的方式是更新 Hermes,让 hermes completion zsh 生成正确脚本。
如何快速验证补全脚本有没有语法错误?
运行:
hermes completion zsh > /tmp/_hermes
zsh -n /tmp/_hermes
如果没有输出,说明至少语法层面通过。
这个问题会影响 Bash 或 Fish 补全吗?
issue 针对的是 Zsh _arguments 语法。Bash/Fish completion generator 是否受影响,需要分别检查生成结果。
总结
#22686 的核心很简单:
Hermes 的 zsh completion generator 把短选项和长选项错误地塞进 _arguments exclusion group,导致 Zsh 报 invalid argument。
正确方向是把:
'(-h --help){-h,--help}[Show help and exit]'
改为类似:
'(-)'{-h,--help}'[Show help and exit]'
并在 CI 或发布前用:
zsh -n
验证生成脚本。
CLI 补全不是边角料。它是用户每天触碰工具的入口,越是开发者工具,越应该把这类小而明确的体验问题修到位。