Skip to content

更新与升级

升级方式取决于你当初是怎么装的。三种形态的升级路径互不相同,走错了不是升级失败,而是会在机器上留下两份互相打架的安装。

你装的是谁负责升级怎么升
独立 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

第一步:查当前版本与渠道

bash
yoooclaw update self

只查不装 —— 读 npm registry 的 dist-tag 比对版本,然后告诉你该执行什么命令。返回字段:

字段含义
dist当前这份二进制的安装来源,npmnative。按可执行文件路径是否落在 node_modules 下判定
current / latest本地版本 / 渠道最新版本
channellatest;加 --beta 则查 beta dist-tag
updateAvailable只比较 x.y.z 三段,忽略 prerelease 后缀
command有新版本时给出的升级命令,已按 dist 选好渠道;已是最新时为 null
bash
yoooclaw update self --beta --format json

npm 渠道

bash
npm update -g @yoooclaw/cli      # 稳定版
npm i -g @yoooclaw/cli@beta      # 预发布版

npm 包是极薄的 Node launcher,实际的 Go 二进制通过 optionalDependencies 按平台拉取,所以升级 npm 包会连同平台二进制一起换掉。

原生二进制渠道

bash
# 升到最新稳定版
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 只会看到当前正在运行的那一份。真要换渠道,先把旧的卸干净:

bash
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 —— 那是个旧版本的进程,还在照常收数据。要让新版本生效:

bash
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 的返回:

json
{ "ok": true, "currentVersion": "0.7.0", "latestVersion": "0.7.1",
  "channel": "latest", "updateAvailable": true,
  "updating": false, "editableInstall": false }

确认后执行的完整流程:

text
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:重跑安装器

和首次安装是同一条命令,重复执行即升级:

bash
curl -fsSL https://artifact.yoooclaw.com/hermes-plugin/install.sh | bash -s -- --api-key "ock_..."

Windows(PowerShell):

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 指错了

升级后确认

bash
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 即可。见上文原生二进制渠道

升级完了但行为没变

依次确认:

  1. daemon 还是旧进程 —— 最常见。yoooclaw daemon restart 后看 daemon statusversion
  2. PATH 里有两份 CLI —— which -a yoooclaw 看看是不是命中了另一个渠道装的那份。
  3. Hermes 网关没重启 —— 用了 --no-restart,或重启失败。hermes gateway restart
  4. 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 处理。

下一步