选择安装 Manifest 管道
选择安装 Manifest 管道
学习目标
本章要解决什么问题:理解 ECC 如何在 246 个技能、61 个代理、76 个命令中只安装用户需要的部分。
读完本章后,你将了解:
- Manifest 驱动的模块化安装架构
- Profile 系统(full / minimal / custom)
- 依赖展开与目标过滤
- 安装状态持久化与 doctor / repair / uninstall
前置知识
本章涉及插件系统的基础知识,建议先阅读:
- 插件系统架构 — 约定优于配置的组件发现机制
项目实践
为什么需要选择性安装
ECC 包含大量文件:
skills/— 246 个技能目录agents/— 61 个代理定义commands/— 76 个命令rules/— 12 种语言的规则集scripts/— 40+ 个 Node.js 脚本hooks/— 完整钩子系统
全量安装(--profile full)会复制所有文件到 ~/.claude/ 下的插件目录。但很多用户只需要其中一部分(如只想要 TypeScript 相关的规则和几个核心技能)。
Manifest 架构
核心文件职责
| 文件 | 职责 |
|---|---|
manifests/install-modules.json | 模块目录 + 路径列表(如 skills: ["tdd-workflow", "continuous-learning-v2", ...]) |
manifests/install-profiles.json | Profile 定义 → 模块列表映射(如 full: ["skills", "agents", "commands", "rules", "hooks"]) |
scripts/lib/install/request.js | CLI 参数解析 + 请求规范化(--profile full → 模块列表) |
scripts/lib/install/runtime.js | 从规范化请求分派到安装计划创建 |
scripts/lib/install-executor.js | 参数转换、遗留兼容、操作具体化、文件系统变更、状态写入 |
scripts/lib/install-manifests.js | 模块/Profile 目录加载 + 依赖展开 |
scripts/lib/install-targets/ | 目标根目录和目的地路径脚手架 |
scripts/lib/install-state.js | Schema 支持的安装状态读写 |
scripts/lib/install-lifecycle.js | 基于已存储操作的 doctor/repair/uninstall |
scripts/lib/install-lifecycle.js | doctor/repair/uninstall 行为(从存储的操作派生) |
Profile 系统
ECC 提供三种安装配置文件:
| Profile | 包含内容 | 适用场景 |
|---|---|---|
| full | 所有模块 | 完整功能,适合专业用户 |
| minimal | 核心技能 + 基础规则 | 轻量安装,适合新用户 |
| custom | 用户自选模块 | 精确控制,按需安装 |
安装命令示例:
# 全量安装bash install.sh --profile full
# 最小安装bash install.sh --profile minimal
# 自定义模块安装bash install.sh --modules skills:tdd-workflow,rules:typescript,hooks依赖展开
模块之间可能存在依赖。例如安装 skills:django-tdd 可能依赖 rules:python。安装管道自动处理依赖展开:
用户请求: --modules skills:django-tdd ↓依赖展开: - skills:django-tdd (显式请求) - rules:python (django-tdd 的依赖) - hooks (django-tdd 的依赖) ↓目标过滤: 仅安装用户目标 Harness 支持的模块 ↓执行: 复制文件到 ~/.claude/plugins/...安装状态持久化
每次安装操作都写入 SQLite 状态存储:
-- 简化的状态 schemaCREATE TABLE install_operations ( id INTEGER PRIMARY KEY, module TEXT NOT NULL, -- 模块名 operation TEXT NOT NULL, -- "install" | "update" | "remove" target TEXT NOT NULL, -- 安装目标 timestamp TEXT NOT NULL, version TEXT -- 模块版本);这使得以下命令成为可能:
# 查看当前安装状态node scripts/list-installed.js
# 诊断安装问题node scripts/doctor.js
# 修复损坏的安装node scripts/repair.js
# 卸载特定模块node scripts/uninstall.js --modules skills:tdd-workflow遗留兼容
ECC 保留了旧的 ecc-install 兼容路径(指向 install.sh),同时支持新的 Manifest 安装模式:
# 旧方式(仍可用)bash install.sh --target claude --modules hooks-runtime
# 新方式(推荐)ecc install --profile full问题与规避
Manifest 路径指向不存在的文件
问题:install-modules.json 中声明的路径在仓库中不存在(文件被删除但未更新 Manifest)。
ECC 的规避:CI 验证脚本 scripts/ci/validate-install-manifests.js 检查所有 Manifest 路径是否存在。
依赖循环
问题:模块 A 依赖 B,B 依赖 A,导致无限展开。
规避方案:Manifest 系统在安装计划阶段检测循环依赖并报错。
卸载时残留文件
问题:卸载模块后,生成的文件(如 learned skills)可能残留。
规避方案:install-lifecycle.js 中的 uninstall 操作只移除 Manifest 跟踪的文件。本地生成的文件(learned/imported/evolved)不受影响,因为它们不在仓库 Manifest 中。
设计取舍
为什么用 JSON Manifest 而非 npm 依赖?
ECC 的选择安装系统超出了 npm 的依赖模型:
- npm 的依赖是”安装这个包及其所有依赖”
- ECC 需要的是”安装这个模块及其依赖,但只针对特定 Harness”
- npm 无法表达条件展开和目标感知
JSON Manifest 的优势:
- 明确声明每个模块的路径
- 支持 Profile → 模块的映射
- 支持运行时依赖展开
代价:需要自己实现安装管道,而非直接使用 npm install。
为什么保留遗留兼容?
install.sh 的旧路径仍然存在:
- 原因:已有用户和文档使用旧路径,突然移除会破坏
- 代价:需要维护两套安装模式
- ECC 的选择:旧路径指向新管道,而非旧实现。
install.sh现在是薄 shell,内部调用新的安装管道
SQLite vs JSON 状态文件
安装状态使用 SQLite 存储:
- 优势:查询能力、并发安全、Schema 约束
- 代价:比 JSON 文件重
- 为什么选 SQLite:安装/卸载/doctor 需要查询能力(“已安装了哪些模块”、“模块 X 安装了哪些文件”),JSON 文件不支持高效查询
参考来源
- 源码验证:
manifests/install-modules.json— 模块目录定义 - 源码验证:
manifests/install-profiles.json— Profile 定义 - 源码验证:
scripts/lib/install/目录 — 安装管道实现 - 源码验证:
scripts/ci/validate-install-manifests.js— CI 验证 - 源码验证:
scripts/install-apply.js,scripts/install-plan.js— CLI 入口