一条命令升级所有插件:hermes plugins update 现在会先给你看清单

放假一周回来,你打开终端敲下 hermes plugins list,发现自己装了十二个插件,其中七个后面挂着“有新版本”。你记得其中两个上周还修过 bug。于是你开始一个个敲名字:hermes plugins update foo、hermes plugins update bar……敲到第四个的时候你已经不记得剩下哪几个了,干脆放弃,等下次想起来再说。
这就是那种“不致命但一直恶心人”的小事。10 月 19 日合并的一个改动把它解决了:hermes plugins update 现在可以不带插件名,先体检、再一次性升级。
以前为什么必须带名字
update 子命令原本只做一件事:按名字找到这个插件,看它的安装来源,把新版本拉下来。它完全不知道“系统里还有哪些插件”,所以你不给名字,它只能打印用法错误:
$ hermes plugins update
usage: hermes plugins update [-h] name
hermes plugins update: error: the following arguments are required: name
要批量升级就得自己写循环,而循环写起来不难、写对很难:目录名到底是不是插件名?catalog 安装和 git 安装的升级方式不同,要不要分开处理?升级失败一个要不要继续?这些判断以前全在用户脑子里。
现在:不带名字等于“全部体检一遍”
hermes plugins update
在终端里,它会跑一次只读的 check-updates 探测,然后打印一张表:
| # | Plugin | Current | Latest | Update |
|---|---|---|---|---|
| 1 | hermes-dreaming | 2.9.3 | 2.9.5 | catalog re-pin |
| 2 | obsidian-sync | a1b2c3d4 | 9f8e7d6c | git pull |
表下面会把它跳过的每个插件和原因都点名列出,例如 skipped foo (pip): pip distribution; Hermes does not upgrade it。然后只问一次:
Update all 2? [Y/n]:
回车或输 y 就开始,逐个更新。每个插件仍然走完整流程——不是“一把梭”强推。也就是说,如果某个新版本申请了新的能力(比如新工具、新的文件系统权限),它仍然会单独弹出来问你要不要授权;如果 catalog 里这个插件的提交被重新指向(re-pin),也仍然会问。这一点很重要:批量更新的前提是“省掉重复劳动”,不是“省掉知情同意”。
部分失败不会连坐
批量操作最怕的是“第 3 个失败了,后面 4 个没跑”。这个实现里每个插件是独立的:
- 某个插件升级失败,会打印它自己的错误行,然后继续下一个;
- 最后给一份汇总,把结果分成三类:
✓ updated、= already current、✗ failed(带失败原因第一行); - 只要有任何一个失败,进程退出码为 1;全部成功为 0;
- 一个都不需要更新时,它会直接说
No plugin updates to apply.,退出码 0。
这意味着你可以直接把它塞进 CI 或定时任务:
hermes plugins update --yes || echo "some plugin failed to update"
脚本、cron 和管道里怎么用
没有终端(cron、CI、| tee 之类的管道)时,行为是默认不动手:它打印清单,然后以退出码 1 结束,并提示你加 --yes。这是有意的保守设计——批量升级不该在无人值守的环境里悄悄改东西。
加上 --yes 才会真的升级,但此时同意环节是“失败即拒绝”(fail closed):
- 新版本要求的新能力不会被授予,插件停在受限状态;
- catalog 里重新指向的提交不会被应用;
- 其它不需要额外同意的更新照常执行。
另外 --yes 只能和“不带名字”一起用。hermes plugins update foo --yes 会被拒绝,因为那会让人误以为“按名字升级 = 自动同意一切”。
如果你希望某些插件完全无人值守地自动更新,那要显式开另一个开关:
plugins:
auto_apply: true # 仅对"跟踪的 git 安装"生效,默认 false
auto_apply 只覆盖 tracked Git 插件,不碰 pinned、手工放置、漂移(provenance 对不上)和 pip 分发的那些行。两条路径都会走升级前的安全扫描。
哪些插件会被跳过,为什么
批量更新只处理 update 真正能动手的两类:catalog 安装(重新指向 catalog 审核过的提交)和跟踪的 git 安装(pull)。其余会被明确跳过,而不是假装升级了:
| 情况 | 跳过原因 |
|---|---|
| pip 分发 | Hermes 不接管 PyPI 包的升级,那是 pip 的事 |
| pinned(钉死了版本/提交) | 钉住就是你不想它动 |
| needs fixing(安装状态需要修复) | 先修好再谈升级 |
| 状态未知 | 探测不到远端信息,不冒险 |
如果你是从别人仓库 git clone 下来直接放进插件目录的,它不会被当成跟踪安装,需要先 hermes plugins adopt <name> 认领,之后升级才有据可查。这是有意的:Hermes 不想在你不知情的时候去 pull 一个它并不认识来源的目录。
还有一个安全细节:如果某个插件的新版本改了清单,或者引入/更换了 update_url,Hermes 会拒绝使用新地址,直到你手工确认:
hermes plugins trust-update-url my-plugin
这是“更新源可信性”检查,不是沙箱——它防的是“更新渠道被换成了别人的服务器”,不防已经信任的插件代码做坏事。
什么时候检查、怎么查
hermes plugins update 跑的是和 hermes plugins check-updates 同一套探测逻辑,后者是只读的,不改任何插件文件,适合放进监控:
hermes plugins check-updates # 只报告,不动文件
网关还有一个定时检查,间隔由 plugins.auto_update_check_hours 控制:默认 24 小时,设成 0 就关掉。检查结果(receipt)可以在 hermes pm status 和桌面端的同步状态里看到。注意这只是“多久查一次”,不是“查了就升”——默认情况下什么都没人升级,除非你亲手跑 update 或者打开了 auto_apply。
几个实际使用建议
- 先在只读模式看一眼。不确定有多少插件落后时,先
hermes plugins check-updates,它一个文件都不改。 - 批量更新后跑一次
hermes plugins list。批量升级会逐插件弹同意,如果你在终端里连按回车跳过了某个授权提示,那个插件会停在受限状态,不会报错——值得事后确认一遍。 - CI 里别用默认行为。没有终端时默认不升级并返回退出码 1,如果你的流水线把非零退出当失败,记得显式加
--yes或干脆别在 CI 里升级。 - catalog 安装和 git 安装的“新版本”含义不同。前者是 catalog 审核过的提交被重新指向,后者是上游仓库 HEAD 变了——后者的风险面更大,因为它意味着跟着一个随时会动的分支走。
本站之前写过 插件 catalog 怎么工作,以及 catalog 的 CI 供应链把关,如果你在意“为什么 catalog 里的版本值得信”,那两篇是背景。想让便携插件(plugin.json)的配置也能在桌面端表单里改,便携插件的 MCP 信任门禁 讲了另一层。命令行子命令的完整列表在 plugins 命令参考。
小结
批量升级本身不新鲜,难的是“批量”和“知情同意”如何共存。这个改动的取舍很明确:把重复的敲名字省掉,把需要判断的地方(新能力、catalog 重新指向、更新源变更)一个个留给你。对装了十几个插件的用户来说,这大概是从“懒得升级”到“每周跑一次”的差别。