--- name: workflow-update description: 更新或检查 Workflow(workflow.games)Agent 插件版本时使用;其他 workflow-* 技能的行为与线上 API 明显不符(多半是插件过期)时也用本技能先核对版本。 --- # workflow-update — 检查与更新插件 **先判安装形态,再查版本。** 插件有两条分发渠道,**版本真值不是同一个**:宿主托管安装(Claude Code marketplace)认公开仓的 `plugin.json`,手动安装(Codex / 官网脚本)认官网 `version.json`。两条渠道的发布节奏可以脱节,拿另一条渠道的版本号判自己,会得出「已是最新」甚至反向降级的错误结论。 ## 1. 判断安装形态 看**本技能所在路径**,按下面的顺序判,**先命中先算**: **0. 源码态** —— 向上两级既是插件根、又带 `.git` 或 `tests/`(你在开发这个插件本身,不是在用它)→ **提示无需更新,结束**。源码态归 git 管,不归本技能;这一条必须先判,否则插件仓库自己的工作副本会被下面的清单特征误判成宿主托管。 **A. 宿主托管安装** —— 技能路径在 `~/.claude/plugins/cache` 或其他客户端的插件缓存下 → 走**第 2 节**。 没有缓存路径特征、但向上两级是插件根(存在 `plugin.json` 或 `.claude-plugin/plugin.json`),且**不在 B 列出的手动安装目录里**,同样按 A 处理。 **B. 手动安装** —— 技能目录直接落在 `~/.codex/skills`、`.agents/skills` 或 `~/.claude/skills` 下 → 走**第 3 节**。**B 的路径特征优先于 A 的清单特征**:项目里恰好放着一份 `plugin.json`,不改变这是手动安装的事实。 ## 2. 宿主托管:交给宿主更新 **这条路不读 `version.json`。** 那份清单只服务手动安装渠道,可能**滞后**于 marketplace 发布;宿主托管的版本真值是 marketplace 公开仓里的 `plugin.json`,由宿主自己拉取比对。用官网清单判宿主托管安装,最常见的结果是误报「已是最新」,用户永远升不上去。 **本技能不自改插件目录**——宿主管理的目录由宿主维护,绕过它手改会造成状态不一致。改为提示用户走宿主自己的机制: - **Claude Code**:先刷新 marketplace,再更新插件。 ``` claude plugin marketplace update workflow-plugin claude plugin update workflow@workflow-plugin --scope user ``` 也可以用 `/plugin` 界面,或等 marketplace autoUpdate 自己生效。**更新后必须重启会话**才加载新版本——不提醒的话用户会以为没升成功。 - **其他 Agent Plugins 客户端**:用各自的安装器重装(例如 `npx plugins add` 那条路径)。 收尾读 `claude plugin list`(或宿主对应的列表命令)确认版本已变,向用户报告新旧版本号。 ## 3. 手动安装:比对官网版本 读**本技能目录下的 `VERSION` 文件**(安装包内由构建器生成,纯文本一行版本号)。 - 没有 `VERSION` 文件 = 你运行的是源码态(开发仓里直接用),**提示无需更新**,结束。 抓取: ``` https://workflow.games/plugin/version.json?cb=<当前 epoch 秒> ``` **必须带 `cb` 参数**(当前时间戳)绕 CDN 缓存,否则可能拿到旧版本误判「已最新」。返回含 `version`、`notes`(更新说明)与 `files`(文件清单地址)。 **按语义化版本逐段比大小,不做字符串相等判断**(`0.10.0` > `0.9.0`,字符串比较会判反): - 线上 **==** 本地 → 报告「已是最新(<版本>)」,结束。 - 线上 **<** 本地 → 本地更新(多半是源码态或线上发布滞后)。报告两个版本号并**结束,绝不"更新"**——照旧逻辑跑会把新版覆盖成旧版,是降级不是升级。 - 线上 **>** 本地 → 才进入第 4 节。 ## 4. 自更新流程(仅手动安装) 手动安装走插件自带的安装器,**不要在技能扫描目录里改名备份**。先判渠道(本节只服务手动安装;宿主托管见第 2 节),不要拿另一渠道的版本号决定升/降。 ``` node <插件根>/tools/workflow-install.mjs --from-dir <新版本解包根> # 官网(默认 --mode full): node <插件根>/tools/workflow-install.mjs # 兼容性诊断(只打印,不删 ADR / 历史计划): node <插件根>/tools/workflow-install.mjs --doctor ``` 1. 抓取 `version.json` 的 `files` 指向的文件清单(同样加 `cb` 参数)。**full** 要的是运行时清单;旧 `files.json` 只有技能 Markdown → 失败并说明缺运行时,不得标已完整安装。 2. 安装器下到**临时目录**(不直接写目标),逐一校验 **sha256**:任何一个不符 → **立即中止并报告,不落盘任何文件**。 3. **full**(默认):可执行文件必须命中 `runtime-manifest.json` 的 `executableGlobs`(清单内 `.mjs` / `.sh`),且 sha256 一致;不在白名单的可执行文件仍中止。 4. **skills**:仍只允许 `.md` 与 `VERSION`;清单里出现可执行文件 → **立即中止并告警**。结束时打印能力边界(无规则/工具/reviewer)。 5. 备份落到 `$XDG_DATA_HOME/workflow/backups/`(**不进** `~/.codex/skills`)。扫描根里已有的 `*.bak-*` 迁到 backups。 6. 完整树换根到 `$XDG_DATA_HOME/workflow/plugin`,技能目录改为指向运行时的受管 symlink。 7. 读新 `VERSION` 确认版本已变,向用户转述 `version.json` 的 `notes`。 `--doctor` 即兼容性诊断:缺资源、断链、同名技能、入口/reviewer 缺失、lint 扩展 `api≠1`。**默认只打印**,不删 ADR / 历史计划。 ## 安全边界 - **只从 `workflow.games` 域下载**(或本地 `--from-dir`)。清单里出现任何其他域的地址 → 中止并告警。 - **技能渠道**(`--mode skills` / 旧包)只应包含 **`.md` 与 `VERSION` 纯文本**。清单或下载内容里发现可执行文件(`.sh`、二进制等)→ **立即中止并告警**,不安装。 - **完整运行时**(`--mode full`)允许清单白名单内的 `.mjs`;不在 `executableGlobs` 里的可执行文件仍中止、不落盘。 - 宿主托管形态(第 2 节)**不下载任何文件**——它只调用宿主自己的命令,下载与落盘都由宿主负责。 - 更新**绝不触碰** `~/.config/workflow/config.toml`——凭证与插件更新无关;同样不得覆盖或删除 项目的 `.workflow-policy`、`.workflow-drafts/`(包括未完成的本地 bundle)。更新插件后若发现 草稿协议 schema 需要迁移,先备份并由 `workflow-upload` 按 checkpoint 迁移,不能静默丢弃草稿。