更新与升级
升级方式取决于你当初是怎么装的。三种形态的升级路径互不相同,走错了不是升级失败,而是会在机器上留下两份互相打架的安装。
| 你装的是 | 谁负责升级 | 怎么升 |
|---|---|---|
| 独立 CLI(npm) | 你自己 | npm update -g @yoooclaw/cli |
| 独立 CLI(原生二进制) | 你自己 | 重跑 install.sh,必须带 --force |
| Hermes 插件 | 插件自己(可对话触发) | 对话里让它自更新,或重跑插件安装器 |
| OpenClaw 插件 | 宿主 | openclaw plugins update @yoooclaw/phone-notifications |
插件用户不要单独升 CLI
Hermes 插件自带对应平台的 yoooclaw 可执行文件,版本由插件包里的 manifest.json 锁定。单独跑 CLI 的 install.sh 会在 ~/.local/bin 装出第二份 CLI,和插件自管路径下的那份版本不一致 —— 插件仍然用它自己那份,你在终端敲的却是新装的那份,两者对同一份存储的预期可能不同。升级插件就是升级 CLI,不需要也不应该分开做。
独立 CLI
第一步:查当前版本与渠道
yoooclaw update self它只查不装 —— 读 npm registry 的 dist-tag 比对版本,然后告诉你该执行什么命令。返回字段:
| 字段 | 含义 |
|---|---|
dist | 当前这份二进制的安装来源,npm 或 native。按可执行文件路径是否落在 node_modules 下判定 |
current / latest | 本地版本 / 渠道最新版本 |
channel | latest;加 --beta 则查 beta dist-tag |
updateAvailable | 只比较 x.y.z 三段,忽略 prerelease 后缀 |
command | 有新版本时给出的升级命令,已按 dist 选好渠道;已是最新时为 null |
yoooclaw update self --beta --format jsonnpm 渠道
npm update -g @yoooclaw/cli # 稳定版
npm i -g @yoooclaw/cli@beta # 预发布版npm 包是极薄的 Node launcher,实际的 Go 二进制通过 optionalDependencies 按平台拉取,所以升级 npm 包会连同平台二进制一起换掉。
原生二进制渠道
# 升到最新稳定版
curl -fsSL https://artifact.yoooclaw.com/cli/install.sh | sh -s -- --force
# 升到指定版本
curl -fsSL https://artifact.yoooclaw.com/cli/install.sh \
| sh -s -- --version 0.9.0 --force
# 升到最新预发布版
curl -fsSL https://artifact.yoooclaw.com/cli/install.sh | sh -s -- --beta --force升级必须带 --force
安装器在目标路径已有 yoooclaw 时会直接报错退出(… 已存在;用 --force 覆盖,或先卸载旧版本),这是防止误覆盖的保护。首次安装不需要 --force,升级一定需要。
注意 yoooclaw update self 给出的 command 目前不带 --force,直接照抄执行会撞上这个保护 —— 手动补一个 --force 即可。
安装器还有两点和升级相关:
- 安装目录沿用旧的判定逻辑(优先
~/.local/bin,其次可写的/usr/local/bin),不会读取上一次装到哪。如果你当初用--dir装到了别处,升级时要再传一次同样的--dir,否则会在默认目录装出第二份。 - 默认不修改 shell PATH:安装器只在传入
--modify-path时才会把安装目录写进 shell 配置文件,且写入是幂等的(配置里已有那行时只报「PATH 已配置」,不会重复追加)。不传--modify-path就只装二进制,不碰你的 shell 配置——首次安装和升级都一样,--no-modify-path仍保留只为兼容旧调用,等价于默认行为。
update self 给的原生升级命令指向 GitHub raw 的安装脚本;国内直连不畅时换成上面的 artifact.yoooclaw.com(阿里云 OSS)即可,两个脚本参数完全一致,只是制品下载源不同。
不要混用两个渠道
npm 装过一次又用 install.sh 装一次,机器上就有了两份 yoooclaw,PATH 里谁在前面就用谁,而 update self 只会看到当前正在运行的那一份。真要换渠道,先把旧的卸干净:
yoooclaw uninstall # 停 daemon + 删二进制与配置,保留数据
npm uninstall -g @yoooclaw/cli # npm 形态由 node_modules 托管,需要这一步uninstall 默认保留通知 / 录音 / 图片数据,所以换渠道重装后数据还在。
升级时的所有权处理
同一台机器上如果 CLI 和 Hermes 插件都装了,install.sh 升级时默认保留升级前的所有权归属——原来谁持有写者锁 / Relay 连接,升级后还是谁持有,不会因为一次升级悄悄把所有权转手。安装器会先停掉正在跑的独立 CLI daemon(如果有)、换完二进制后按原 profile 重新拉起,失败会自动回滚重启。只有显式传 --activate(或设置 YOOOCLAW_ACTIVATE_OWNER=cli)才会在装完后主动把所有权转交给独立 CLI;也可以事后随时手动执行 yoooclaw owner activate cli 完成同样的转交,详见命令参考 · owner。
升级完记得重启 daemon
替换二进制不会影响已经在跑的 daemon —— 那是个旧版本的进程,还在照常收数据。要让新版本生效:
yoooclaw daemon restart
yoooclaw daemon status --format json # 确认 version 变了区分两个命令:换 api-key 用 daemon reload(增量刷隧道,不断已有连接);换二进制或轮换 gateway token 必须 daemon restart,reload 不够。
Hermes 插件
插件包里内置了 CLI 二进制,所以「升级插件」是一次性把插件和 CLI 一起换掉。当前插件 0.8.2 内置 CLI 0.8.2。
方式 A:对话里自更新(推荐)
插件暴露了两个工具,让你在和 Hermes 聊天时直接完成升级:
| 工具 | 作用 |
|---|---|
plugin_update_check | 读 OSS 的 latest 渠道标记比对版本。结果缓存 5 分钟,force=true 跳过缓存 |
plugin_update_apply | 真正执行升级。必须传 confirm=true,否则返回 YOOOCLAW_UPDATE_NOT_CONFIRMED |
confirm=true 这道门是故意设的:模型不能自己决定升级,需要你在对话里明确同意后它才会带上这个参数。可选 version 参数指定目标版本。
plugin_update_check 的返回:
{ "ok": true, "currentVersion": "0.7.0", "latestVersion": "0.7.1",
"channel": "latest", "updateAvailable": true,
"updating": false, "editableInstall": false }确认后执行的完整流程:
1. 写 pending.json(起止版本、发起对话、开始时间)
2. 从 OSS 下载渲染版 install.sh
3. setsid 脱离当前进程组启动安装器 —— 它必须活过自己触发的 gateway 重启
4. 工具立即返回「已开始」,让这句回复能在网关重启前送达
5. 旧进程里的 watcher 线程把 update.log 流式推送到对话
6. 安装器跑完 → hermes gateway restart
7. 新进程加载插件后调 resume_after_reload(),推送最终 ✅/❌第 3 步的 setsid 和第 5 步的 watcher 都不是多余的:安装器如果在 pip 阶段就失败,网关根本不会重启,也就没有「新进程」来汇报结果 —— 那种失败只能由旧进程里的 watcher 报出来。而 pending.json → result.json 的认领是原子改名,保证旧进程的 watcher 和新进程的 resume 不会各推一次通知。
推送通道不可用时,结果会留到你下一次发消息时由 pre_llm_call hook 告诉你,不会静默丢掉。
方式 B:重跑安装器
和首次安装是同一条命令,重复执行即升级:
curl -fsSL https://artifact.yoooclaw.com/hermes-plugin/install.sh | bash -s -- --api-key "ock_..."Windows(PowerShell):
& ([scriptblock]::Create((irm https://artifact.yoooclaw.com/hermes-plugin/install.ps1))) --api-key ock_...和 CLI 的安装器不同,插件安装器不需要 --force —— 它走的是 pip install --upgrade,覆盖是预期行为。--api-key 也可以省略,省略时复用 ~/.yoooclaw/credentials.json 里已有的 key。
升级相关的选项:
| 选项 | 说明 |
|---|---|
--version <VERSION> | 装指定版本(OSS 渠道下解析出对应的 wheel URL) |
--oss-channel <NAME> | 省略 --version 时读哪个版本标记,默认 latest |
--oss-base-url <URL> | 换一个 OSS 制品源 |
--no-oss | 不走 OSS,回退到 pip 包(pip install yoooclaw-hermes-plugin) |
--no-restart | 装完不执行 hermes gateway restart(你要自己重启才会生效) |
--python <PATH> | 显式指定 Hermes 使用的 venv Python |
--hermes-profile <name> | 目标 Hermes 是具名 profile(hermes --profile <name>)时指定,安装器会去改该 profile 下的 config.yaml 而不是未使用的全局配置;同名环境变量 HERMES_PROFILE 效果一致 |
安装完成后安装器会执行一次激活校验(依次确认包已装好 → 当前 Hermes profile 的 plugins.enabled 已勾上 → 运行时真正接管了写者锁和 Relay 连接)。校验不通过时脚本现在会明确失败并以非零退出码结束(此前无论校验是否通过都会打印"安装完成"),提示信息会区分「装好了但没激活」和「彻底失败」两种情况——遇到非零退出码不要当成安装成功,按下方排查确认原因。
会被拒绝的四种情况
| 错误码 | 触发条件 | 怎么办 |
|---|---|---|
YOOOCLAW_UPDATE_EDITABLE_INSTALL | 插件是 pip install -e 的可编辑安装或源码树 | 自更新会覆盖你正在改的工作树,故直接拒绝;在仓库里手动升级 |
YOOOCLAW_UPDATE_IN_PROGRESS | 已有一次更新在跑 | 等它跑完。若 pending.json 超过超时时间(默认 1800 秒,YOOOCLAW_HERMES_UPDATE_TIMEOUT_SECONDS 可调)仍未清除,会被判为陈旧并自动放行新的更新 |
YOOOCLAW_UPDATE_NOT_NEWER | 目标版本不比当前新 | 无需操作。自更新不做降级,要装旧版本用安装器的 --version |
YOOOCLAW_UPDATE_BAD_VERSION | 版本号格式不合法,或渠道标记返回了非法内容 | 检查 --version 拼写;渠道异常时看是不是 --oss-base-url 指错了 |
升级后确认
hermes yoooclaw lifecycle status看三处:components.pluginVersion 是不是新版本、daemon.storage.claimed 是不是 true(新进程重新接管了存储写者锁)、generation 是否已经跟着插件版本变了。插件版本是 generation 的输入之一,所以升级必然导致 generation 变化并触发一次隧道重建 —— 这是预期的。
插件模式下不要跑 yoooclaw update self
插件自管路径下那份 CLI 的可执行文件不在 node_modules 里,所以 update self 会把它判成 native,并建议你跑 CLI 的 install.sh —— 照做会装出第二份游离于插件之外的 CLI。插件内置 CLI 的版本以插件包的 manifest.json 为准,只能通过升级插件来更新。
排查
安装器报「已存在;用 --force 覆盖」
CLI 的原生安装器在升级时的正常表现,补一个 --force 即可。见上文原生二进制渠道。
升级完了但行为没变
依次确认:
- daemon 还是旧进程 —— 最常见。
yoooclaw daemon restart后看daemon status的version。 - PATH 里有两份 CLI ——
which -a yoooclaw看看是不是命中了另一个渠道装的那份。 - Hermes 网关没重启 —— 用了
--no-restart,或重启失败。hermes gateway restart。 - skills 目录没更新 ——
~/.hermes/skills/yoooclaw/若不带.yoooclaw-managed标记(被手动改过),插件会打警告并跳过覆盖,不会强制替换你自己放的内容。
自更新卡住不动
状态全部落在 ~/.yoooclaw/hermes-plugin/update/:
| 文件 | 内容 |
|---|---|
pending.json | 更新进行中(起止版本、发起对话、开始时间) |
update.log | 安装器的 stdout + stderr |
exit_code | 安装器退出码,由脱离的 shell 包装器写入 |
result.json | 已完成、等待推送给用户的终态记录 |
直接看 update.log 尾部和 exit_code 就能判断实际卡在哪一步。超时按退出码 124 处理。
下一步
- 独立 CLI:概述与安装 —— 两个分发渠道的完整安装说明。
- Hermes 插件:概述与安装 —— 安装器做了哪些事。
- 独立 CLI:调试与排错 —— 升级后连不上时的三步排查。