ECC Auto Update 自动更新机制全解析:基于 install-state 的安全重装流程
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
ECC(Everything Claude Code / agent harness performance optimization system)的auto-update命令用于从上游仓库拉取最新改动,并依据记录的 install-state 请求重新生成当前上下文的全部托管安装。它不是一个简单的git pull,而是一套"拉取 + 依据安装状态重建参数 + 重新执行安装器"的完整闭环,专门用来处理普通增量修补无法覆盖的上游重命名与删除场景。读完本文,你将掌握auto-update的命令行参数、内部调用链、仓库根校验与安全机制,以及如何在 Claude Code、Cursor 等多种托管目标上安全地执行自动更新。
为什么需要 auto-update:与 repair.js 的定位差异
ECC 的安装体系将"安装了什么、从哪里复制、目标在何处"完整记录在install-state.json中(结构定义见 scripts/lib/install-state.js,包含schemaVersion、target、request、resolution、source、operations等字段)。日常维护中,repair.js可以基于旧的操作记录做增量修补,但一旦上游发生了重命名或删除,旧的 operations 就失去了对应的源文件,无法安全重建。
auto-update之所以选择"重新安装"而不是"修补",正是为了处理这类问题:它丢弃对旧操作记录的依赖,改用**原始安装请求(profile、modules、组件包含/排除、hook 同意状态等)**重新走一遍完整的安装规划与执行流程。命令文档在 docs/ja-JP/commands/auto-update.md 中明确说明:
重新安装是有意为之:
repair.js无法从过期的操作记录安全重建上游重命名或删除的内容。
快速上手:三种典型用法
在已安装 ECC 的环境中,auto-update通过 Node 直接调用 scripts/auto-update.js:
# 1. 预览更新,不修改任何内容 ECC_ROOT="${CLAUDE_PLUGIN_ROOT:-$(node -e "var r=(function(){var p=require('path'),f=require('fs'),o=require('os');var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var d=p.join(o.homedir(),'.claude');function L(x){try{return require(p.join(x,'scripts','lib','resolve-ecc-root')).resolveEccRoot({probe:p.join('scripts','auto-update.js')})}catch(_){return null}}var r=L(d);if(r)return r;var s=['ecc','ecc@ecc','marketplaces/ecc','everything-claude-code','everything-claude-code@everything-claude-code','marketplaces/everything-claude-code'];for(var i=0;i<s.length;i++){r=L(p.join(d,'plugins',s[i]));if(r)return r}try{var g=['ecc','everything-claude-code'];for(var j=0;j<g.length;j++){var c=p.join(d,'plugins','cache',g[j]);var O=f.readdirSync(c);for(var k=0;k<O.length;k++){var q=p.join(c,O[k]);var V=f.readdirSync(q);for(var m=0;m<V.length;m++){r=L(p.join(q,V[m]));if(r)return r}}}}catch(_){}return d})();console.log(r)")}" node "$ECC_ROOT/scripts/auto-update.js" --dry-run # 2. 仅更新当前项目中由 Cursor 托管管理的文件 node "$ECC_ROOT/scripts/auto-update.js" --target cursor # 3. 显式覆盖 ECC 仓库根目录 node "$ECC_ROOT/scripts/auto-update.js" --repo-root /path/to/everything-claude-code第一行命令中的ECC_ROOT解析逻辑来自 scripts/lib/resolve-ecc-root.js 的resolveEccRoot:依次尝试CLAUDE_PLUGIN_ROOT环境变量、标准安装位置~/.claude/、~/.claude/plugins/下的插件目录(含ecc、ecc@ecc、marketplaces/ecc、everything-claude-code等别名),以及插件缓存自动探测,最后回退到~/.claude/。其中probe参数指向scripts/auto-update.js自身,用于确认候选根目录里确实存在本命令需要的脚本。
命令行参数详解
auto-update的参数解析在 scripts/auto-update.js 的parseArgs中实现,完整参数如下:
| 参数 | 取值 | 作用 | 默认行为 |
|---|---|---|---|
--target <target> | 见下方支持列表 | 只更新指定托管目标的安装状态 | 不传则检查全部目标 |
--repo-root <path> | 任意路径 | 显式指定 ECC 仓库根目录,跳过从 install-state 推导 | 从 install-state 的 operations 推导 |
--dry-run | 布尔 | 只做 git fetch/pull 并生成重装计划,不执行任何写入 | 默认关闭,直接执行重装 |
--json | 布尔 | 输出机器可读的 JSON 结果 | 默认输出人类可读文本 |
--help/-h | 布尔 | 打印用法说明 | — |
--target支持的托管目标与安装清单一致,定义在 scripts/lib/install-manifests.js 的SUPPORTED_INSTALL_TARGETS中:
claude, claude-project, cursor, antigravity, codex, gemini, opencode, codebuddy, joycode, qwen, zed, hermes, openclaw, kimi, adal注意:--target可多次传入(parsed.targets是数组),意味着你可以一次更新多个目标;同时,未知参数会直接抛出Unknown argument: xxx错误并终止(对应测试见 tests/scripts/auto-update.test.js)。
内部工作流程:从发现状态到重装执行
runAutoUpdate是核心函数(scripts/auto-update.js),完整调用链如下:
发现 install-state 记录(discoverInstalledStates) │ ▼ 过滤出存在且非 legacy 的记录;对 legacy 记录生成迁移警告 │ ▼ 逐条推导仓库根(--repo-root 覆盖 或 deriveRepoRootFromState) │ ▼ 多仓库根冲突检测(不同记录指向不同仓库根时报错) │ ▼ 非 dry-run:git fetch --all --prune → git pull --ff-only │ ▼ 逐条重建 install-apply 参数并执行 install-apply.js --json [--dry-run] │ ▼ 汇总 checked / updated(planned) / error 并输出1. 发现安装状态
discoverInstalledStates来自 scripts/lib/install-lifecycle.js,按homeDir与projectRoot两个维度扫描。记录按适配器区分home(如~/.claude/)与project(如./.cursor/)两种类型。只有在--target限定范围内、且状态文件真实存在的记录才会进入更新队列。
2. 推导仓库根
如果未显式传--repo-root,deriveRepoRootFromState(scripts/auto-update.js)会从任一操作的sourcePath与其sourceRelativePath中向上回溯目录层级,还原出仓库根。测试 tests/scripts/auto-update.test.js 验证了该推导逻辑;若记录中缺少这两项元数据,则抛出Unable to infer ECC repo root from install-state operations。
当多个 install-state 记录推导出不同的仓库根时,命令会直接报错拒绝执行(Multiple ECC repo roots detected),避免把不同来源的文件混装到同一个环境中。
3. 拉取上游改动
非--dry-run模式下,命令在仓库根内依次执行:
git fetch --all --prune git pull --ff-only使用--ff-only强制快进合并,一旦本地有与上游分叉的提交,git pull会失败并中止更新,从机制上避免把本地未提交改动与上游变更混在一起。
4. 重建重装参数并执行 install-apply.js
每个有效记录都会通过buildInstallApplyArgs(scripts/auto-update.js)把记录的原始安装请求翻译回install-apply.js的命令行参数:
| install-state 记录字段 | 重建出的参数 |
|---|---|
target.target | --target <target> |
request.profile | --profile <name> |
request.modules | --modules <id,id,...> |
request.includeComponents | --with <component>(可多个) |
request.excludeComponents | --without <component>(可多个) |
hookConsent === 'enabled' | --enable-hooks |
hookConsent === 'declined' | --no-hooks |
request.legacyLanguages | 追加为裸语言参数(如typescript python) |
随后以当前 Node 解释器执行install-apply.js --json [--dry-run](scripts/install-apply.js 支持--target/--profile/--modules/--with/--without/--skills/--locale/--config/--enable-hooks/--no-hooks/--dry-run/--json全套参数),并解析其标准输出中的 JSON 作为结果负载。
关键细节:工作目录(cwd)的选择。determineInstallCwd(scripts/auto-update.js)规定:project类型的安装以项目根(target.root的父目录)为 cwd,home类型则以仓库根为 cwd。测试 tests/scripts/auto-update.test.js 对此有明确断言。
5. 结果汇总与退出码
无论人类可读还是 JSON 模式,都会输出checkedCount、updatedCount(dry-run 下为planned)、errorCount三个汇总指标;只要存在任一错误,进程退出码即为 1(见main中process.exitCode = result.summary.errorCount > 0 ? 1 : 0),便于在 CI 或脚本中做门禁判断。
安全机制:拒绝不可信仓库根
auto-update的核心风险点在于:它会执行任意"仓库根"下的install-apply.js。若一个克隆项目内嵌了伪造的scripts/install-apply.js并诱导用户指向它,就可能执行攻击者代码(源码注释中引用了安全公告编号GHSA-hfpv-w6mp-5g95)。
为此,validateRepoRoot(scripts/auto-update.js)做了三重校验:
- 仓库根下必须存在
package.json与scripts/install-apply.js; package.json可解析且其name必须命中官方包名白名单:ecc-universal或everything-claude-code;- 任何不满足条件的路径都会抛出
Refusing to run install from untrusted repo root ...。
此外,install-state 文件本身被视为不可信输入:所有写入/删除操作都被限制在适配器推导出的可信根目录内(assertWithinTrustedRoot,见 scripts/lib/install-lifecycle.js 与executeRepairOperation的注释),无论状态文件如何声称目标路径,都不得越界操作,同时拒绝..父级穿越与绝对路径来源。
遗留状态迁移:legacy 记录的降级处理
当环境中只存在旧版遗留的 install-state 时,auto-update不会盲目重装,而是输出迁移引导:
- 仅存在遗留 OpenCode 状态(
~/.opencode/):提示先运行一次 OpenCode 安装器,迁移到配置的 OpenCode 目录后再执行自动更新; - 仅存在遗留 Antigravity 状态(
.agent/):提示先运行 Antigravity 安装器迁移到.agents/。
这两类记录会被过滤出更新队列(records.filter(record => record.exists && !record.legacy)),并以Warning:前缀打印(对应测试见 tests/scripts/auto-update.test.js),确保升级路径可预期、不破坏未迁移环境。
实战建议
- 先
--dry-run再执行:文档明确建议在任何改动前先预览重建后的重装计划,确认参数与目标无误后再正式更新;dry-run 模式下 git fetch/pull 仍会执行(以便计划基于最新代码生成),但不会运行任何写入操作。 - 限定目标范围:多目标环境建议用
--target cursor之类的参数收敛更新范围,避免一次动到所有托管目标。 - 善用
--json做自动化:把结果接入巡检脚本,利用退出码与summary字段判断更新是否成功。 - 保持官方仓库身份:本地克隆的仓库名必须是
ecc-universal或everything-claude-code,否则会被安全校验拒绝;也不要混用多个仓库根(多根检测会直接报错)。
小结
auto-update把"拉取最新代码"与"按原始意图重装"两个阶段整合为一个幂等可预览的命令:--dry-run保证可审计,--repo-root支持显式指向,--target支持精确到单一托管平台,--json支持脚本化集成。其核心设计——以 install-state 请求重建参数、以白名单校验仓库根、以可信根约束所有写操作——保证了即使上游发生大规模重命名或删除,也能在受控前提下完成环境升级。进一步阅读可参考命令文档 docs/ja-JP/commands/auto-update.md、英文原版 commands/auto-update.md、命令注册表 docs/COMMAND-REGISTRY.json 以及安装器本体 scripts/install-apply.js。
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考