@teamix-evo/mcp 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,64 @@
1
+ # 0033. Entry skill 默认全局安装,bulk add 按 scope 过滤
2
+
3
+ - **Status**: Accepted
4
+ - **Date**: 2026-06-04
5
+ - **Region**: 0100–0999 协议与工具
6
+ - **Related ADR**: [0011](0011-mcp-single-package-multi-group.md)、[0013](0013-skills-source-mirror.md)、[0014](0014-ui-biz-ui-templates-tier.md)、[0030](0030-skill-uni-manager-uplift.md)
7
+
8
+ ## Context
9
+
10
+ `@teamix-evo/skills` 当前混了两类性质完全不同的 skill,放在同一个 `manifest.skills` 数组里:
11
+
12
+ | 类型 | 例子 | 安装语义 |
13
+ | ---- | ---- | ---- |
14
+ | **lifecycle skill / orchestrator** | `teamix-evo-manage` | 工具型。作为生命周期入口被调用(初始化、升级、卸载、placeholder→real 迁移)。**装一次即可**,不需要跟项目走。 |
15
+ | **content skill / variant 内容** | `teamix-evo-design-<variant>`、`teamix-evo-code-<variant>` | 跟 variant 绑定。装在哪个项目就影响哪个项目的页面 / 文件生成规则。**必须随项目走**。 |
16
+
17
+ 实际用户路径:
18
+
19
+ 1. 用户先全局装 `teamix-evo-manage` 到 `~/.claude/skills/` —— 因为只有装了它,IDE 才能识别"初始化一个工程"这类自然语言指令、并触发 CLI。
20
+ 2. 该 skill 的「场景 2 / 3」会驱动 `npm create teamix-evo` 或 `npx teamix-evo skills add`,bulk 模式把 manifest 里全部 5 个 skill 一律装到 project scope —— 包含 `teamix-evo-manage` 自己。
21
+ 3. 结果:`~/.claude/skills/teamix-evo-manage/` 与 `<project>/.claude/skills/teamix-evo-manage/` 同时存在,IDE 同时识别两份。版本漂移、`skills doctor` 误报、用户不知道改哪份才能生效。
22
+
23
+ 约束:
24
+
25
+ - 不希望强行禁止 manage 装到项目级(用户自有 override 需求,如离线分发场景)
26
+ - 不希望破坏 skills package 的"单包多 entry"协议([ADR 0011](0011-mcp-single-package-multi-group.md))
27
+ - 现存项目的 `skills-lock.json` 不能因此 schema 变更失效
28
+
29
+ ## Options Considered
30
+
31
+ | 选项 | 优点 | 缺点 |
32
+ | ---- | ---- | ---- |
33
+ | A. SkillEntry 加 `scope` 字段,bulk init 按 scope 过滤(本决策) | 声明式;符合 manifest 契约;新增 lifecycle skill 只需打一个标签;现存 manifest 不写该字段也兼容 | 引入一个语义字段,需要 schema bump;CLI 增加分支 |
34
+ | B. 运行时去重(`skills init` 检测 `~/.claude/skills/<id>` 已存在则跳过) | 不动 manifest | 依赖外部状态;同名不同版本时反而锁死;语义不显式 |
35
+ | C. 在 `teamix-evo-manage` 自身的 SKILL.md 决策树里手动让 AI 排除 manage | 不动 CLI / manifest | 每次新增 lifecycle skill 都要改 markdown;契约不机器可读;AI 偏离指令时无法兜底 |
36
+ | D. 把 `teamix-evo-manage` 拆成独立 npm 包 | 物理隔离 | 破坏单包多 group 原则;用户安装路径变复杂;需要 CI 改造 |
37
+
38
+ ## Decision
39
+
40
+ 1. `SkillEntrySchema`(`packages/registry/src/schema/manifest.ts`)新增可选字段 `scope: SkillScopeSchema.optional()`,复用已有的 `SkillScopeSchema = z.enum(['project', 'global'])`。`undefined` 视为隐式 `"project"`。
41
+ 2. `packages/skills/manifest.json` 中 `teamix-evo-manage` 标 `"scope": "global"`,其余 4 个 entry 不动。
42
+ 3. `runSkillsInit`(`packages/cli/src/core/skills-add.ts`,自举路径)candidate 过滤:若 `(s.scope ?? 'project') !== <current install scope>`,跳过(debug 日志说明)。**verb 命名见 [ADR 0034](0034-skills-cli-verb-alignment.md)**。
43
+ 4. `runSkillsAdd`(增量,显式指名)**不**过滤,但若指名的 skill 声明的 scope 与当前 scope 不一致,emit 一条 `logger.warn`,提示推荐 scope。**用户显式指令优先,自负责。**
44
+ 5. `create-teamix-evo` 的两个 preset(`opentrek` / `uni-manager`)从 `skills.entries` 移除 `teamix-evo-manage`。`skills.entries` 只剩 `design-${variant}` + `code-${variant}` 两条 variant 内容。orchestrator 末尾 next-steps 输出多一行,提示用户独立全局装 manage。
45
+ 6. `teamix-evo-manage` 自身的 SKILL.md 增加「安装方式」段落,声明 entry skill 语义、推荐 `--scope global`、说明 `skills init` 自动跳过的契约。
46
+
47
+ ## Consequences
48
+
49
+ - **Positive**:
50
+ - Lifecycle skill 与 content skill 在 manifest 里有显式语义区分,AI / 工具 / 用户都能机器可读地理解
51
+ - 用户在任何项目里跑 `npx teamix-evo skills init` 都不会再得到一份多余的 manage 副本
52
+ - 后续若新增其它 lifecycle skill(例如 `teamix-evo-incident` / `teamix-evo-release`),只需在 manifest 标 `"scope": "global"`,无须改 CLI 代码
53
+ - schema 字段可选,旧 manifest 无 `scope` 字段时仍按 project 处理 —— 完全向后兼容
54
+ - **Negative**:
55
+ - 用户首次使用 teamix-evo 时多了一步:在 `npm create teamix-evo` 之前,要独立运行 `skills add teamix-evo-manage --scope global`。文档与 create CLI 的 next-steps 已显式提示,但仍是一次"必须读说明"的额外门槛
56
+ - 已装项目的存量 `teamix-evo-manage` 副本不会自动清理。文档建议用户手动 `rm -rf .claude/skills/teamix-evo-manage`,我们不写迁移脚本(避免误删用户改过的 SKILL.md)
57
+ - **Trade-off**:
58
+ - 为了语义清晰与契约机器可读,接受了 manifest schema 多一个可选字段、CLI 多两条分支(`runSkillsInit` 过滤 + `runSkillsAdd` warning)。比方案 B(运行时去重)略复杂,但避免了 B 的隐式行为与状态依赖
59
+ - verb 命名分工见 [ADR 0034](0034-skills-cli-verb-alignment.md)
60
+
61
+ ## Source
62
+
63
+ - 用户反馈:「用户使用时会先全局安装 teamix-evo-manage 这个技能,然后使用该技能初始化工程,但是初始化过程中又会在项目级安装本技能,导致用户侧会有两个该技能」
64
+ - 实施 plan:`/Users/lyca/.claude/plans/refactored-roaming-grove.md`
@@ -0,0 +1,61 @@
1
+ # 0034. skills CLI verb 对齐:`init` 自举 + `add <ids>` 增量
2
+
3
+ - **Status**: Accepted
4
+ - **Date**: 2026-06-04
5
+ - **Region**: 0100–0999 协议与工具
6
+ - **Related ADR**: [0004 CLI 命令结构](0004-cli-command-structure.md)、[0013 skills source-mirror](0013-skills-source-mirror.md)、[0014 ui-biz-ui-templates 三层](0014-ui-biz-ui-templates-tier.md)、[0033 entry skill global-only scope](0033-entry-skill-global-only-scope.md)
7
+
8
+ ## Context
9
+
10
+ 仓库 CLI 各 group 的动词模型在 0.2.0 之前是统一的(`init` 自举 / `add` 增量),0.2.0 commit 38723ca 把 `skills init` 改名为 `skills add`,理由是"在一个动词下兼容无参与有参两种模式"。这次合并制造了不一致:
11
+
12
+ | Group | bootstrap | 增量装 | 是否一致 |
13
+ | -------- | ----------------- | ------------------ | --------------------- |
14
+ | `tokens` | `init <variant>` | (无,单 variant) | ✅ |
15
+ | `ui` | `init [-y]` | `add <id...>` | ✅ |
16
+ | `skills` | `add`(无参) | `add <ids...>` | ❌ verb 兼任两职 |
17
+ | `biz-ui` | (无,跟 ui config) | `add <id...>` | ✅ |
18
+ | `templates` | (无,跟 ui) | `add <id...>` | ✅ |
19
+
20
+ `add` 在 npm / git / cargo 等业界 CLI 里几乎都需要显式名称(`npm add lodash` / `git add file` / `cargo add serde`),"装一整个集合"通常用 `install` / `init` / `setup`。0.2.0 的合并违背了这个惯例,也让"无参 add 等价 add 全部"成为一个不易发现的隐式规则。
21
+
22
+ 仓库尚未对外发布,无需保留向后兼容。
23
+
24
+ ## Options Considered
25
+
26
+ | 选项 | 优点 | 缺点 |
27
+ | ---- | ---- | ---- |
28
+ | A. 保留 0.2.0 现状,文档说明清楚 | 不动代码 | verb 不一致问题留在用户视野;新人易踩坑 |
29
+ | **B. 拆 `skills init`(自举)+ `skills add <ids>`(增量必填)(本决策)** | 与 tokens / ui 横向对齐;符合 npm/git/cargo 惯例;不传 ids 报错 + help 兜底,意图明确 | 与 0.2.0 决策反转,需更新所有文档 / SKILL.md / 测试 |
30
+ | C. 让 `skills add` 不传 ids 时强制 `--all` flag | 比 B 改动小 | "add --all" 仍是一个 verb 兼两职的别扭表达;不解决根本问题 |
31
+
32
+ ## Decision
33
+
34
+ 1. 新增 CLI 子命令 **`teamix-evo skills init`**(无 ids):自举 — 按当前 tokens variant + install scope 装 manifest 里全部符合条件的 skill。已装的项目再跑返回 `'already-initialized'`。
35
+ 2. **`teamix-evo skills add <names...>`** 改为 `<names...>` 必填(commander `<>` 强制至少 1 个)。不传 ids → commander 在 [ADR 0033 的 `showHelpAfterError(true)` 兜底下自动报错 + 输出 help](0033-entry-skill-global-only-scope.md)。
36
+ 3. Programmatic API:
37
+ - 新增 `runSkillsInit(opts)` / `RunSkillsInitOptions` / `RunSkillsInitResult`(`'installed' | 'already-initialized'`)
38
+ - `runSkillsAdd(opts)` 改为 `names: readonly string[]` 必填,空 names 抛错;返回类型不再含 `'already-added'`
39
+ - 内部抽 `finalizeSkillsInstall()` 共享尾部(写 config / manifest / lock / mcp.json)
40
+ 4. 共享底层 `installSkills()` 不变 — 这是 ADR 0013 source-mirror 协议的实现层。
41
+ 5. 业务调用点(`runTokensInit` 自动装 variant skill、`create-teamix-evo` orchestrator 装 preset.skills)**已经是 incremental(传入 names)**,继续使用 `runSkillsAdd`,不需迁移。
42
+ 6. 文档与 SKILL.md 中"`skills add`"指代 bulk 路径处全部改为 `skills init`;带名引用(`skills add teamix-evo-manage --scope global`)保持不变。
43
+
44
+ ## Consequences
45
+
46
+ - **Positive**:
47
+ - skills 与 tokens / ui / biz-ui / templates 五个 group 的 verb 模型横向对齐
48
+ - 符合 npm / git / cargo 等业界 CLI 惯例,新人理解成本降低
49
+ - `skills add` 不传 ids 时 commander 自动报错 + 输出 help(ADR 0033 兜底配合),降低误用
50
+ - Programmatic API 类型更精确(`runSkillsAdd` 的 `names` 不再可选,types 即合约)
51
+ - **Negative**:
52
+ - 与 0.2.0 时 commit 38723ca 决策反转,需更新所有文档 / SKILL.md / ADR 引用 / 测试
53
+ - 任何已写下"`skills add`(无参)"的对外材料(如演讲稿、教程、issue 历史)都会过期 —— 但仓库尚未对外发布,影响面在内部
54
+ - **Trade-off**:
55
+ - 用"两个对外动词"换"verb 模型一致性 + 类型精确"。比 0.2.0 的"一个动词兼两职"略复杂,但用户实际多输入的字符仅是 `init` vs `add`,代价很小
56
+
57
+ ## Source
58
+
59
+ - 用户反馈(2026-06-04):「tokens 是 init,skills 是 add 是不是不统一?add 应该是需要指定某个技能的,这里是不是不允许 add 后边为空,要根据 variant 指明要安装的多个技能?」
60
+ - 实施 plan:`/Users/lyca/.claude/plans/refactored-roaming-grove.md`
61
+ - 历史决策:`packages/cli/CHANGELOG.md` 0.2.0 (commit 38723ca) — 本 ADR 反转该决策
@@ -0,0 +1,69 @@
1
+ # 0035. skills update 双闸:`keys(lock) ∩ scope-match` + version 短路
2
+
3
+ - **Status**: Accepted
4
+ - **Date**: 2026-06-04
5
+ - **Region**: 0100–0999 协议与工具
6
+ - **Related ADR**: [0013 skills source-mirror](0013-skills-source-mirror.md)、[0033 entry skill global-only scope](0033-entry-skill-global-only-scope.md)、[0034 skills CLI verb 对齐](0034-skills-cli-verb-alignment.md)
7
+
8
+ ## Context
9
+
10
+ `teamix-evo-manage` 是用户主操作点(全局装一份,后续所有研发流程的 AI 入口)。如果其它包(tokens / ui / biz-ui / templates / lint)的升级链尚未完善,只要 manage 自身能可靠升级,manage 就能引导 AI 把整个体系拉齐。
11
+
12
+ 但 0.5.x 之前的 `teamix-evo skills update`(实现在 [packages/cli/src/commands/skills/update.ts](../../packages/cli/src/commands/skills/update.ts) + [skills-installer.ts:333 updateSkills()](../../packages/cli/src/core/skills-installer.ts#L333))有 3 个真 bug + 3 个 UX 缺口:
13
+
14
+ **Bug**:
15
+
16
+ 1. **scope 闸丢失** — `updateSkills` 只过滤 `ides`,不看 `s.scope`。在全局根跑 update 会把 4 个 project-scope 的 design / code skill 也装到全局;在项目根跑 update 会把 manage(`scope: "global"`,见 ADR 0033)装到项目级 — 与 ADR 0033 决策完全反转。
17
+ 2. **lock 闸丢失** — update 不按现存 `lock.skills` 已装清单过滤。manifest 后续若新增第 6 个 skill(例如未来的 `teamix-evo-incident`),所有跑 update 的用户**自动装**它,违背"只刷新已装"的预期。
18
+ 3. **lock 写回也是 manifest 全集** — 把根本没装的 skill 也写进 lock,后续 `skills doctor` 报"源缺失/镜像缺失"误报洪水。
19
+
20
+ **UX 缺口**:
21
+
22
+ 4. version 完全相同时仍重写源 — managed 区域用户改动每次都要走「读 → 合并 → 备份 → 写」一遍,产生噪音
23
+ 5. 没有 `<names...>` 限定 — 想只升 manage 一个、不动其它 skill,办不到
24
+ 6. 没有 `--dry-run` — 看不到会改什么就要全量执行
25
+
26
+ **架构副问题**:无 `runSkillsUpdate` core API,逻辑全在 cli command 里 inline,与 ADR 0034 引入的 `runSkillsInit` / `runSkillsAdd` 不对称。
27
+
28
+ ## Options Considered
29
+
30
+ | 选项 | 优点 | 缺点 |
31
+ | ---- | ---- | ---- |
32
+ | A. 接受现状,文档建议用户清 lock 重装 | 不动代码 | 不可靠;manage 升级链脆弱;主操作点不能崩 |
33
+ | B. 在 update CLI command 内补过滤(单点修复) | 改动小 | 与 init / add 仍不对称;programmatic API 仍残缺 |
34
+ | **C. 抽 `runSkillsUpdate` core API,用三道闸 + version 短路 + dry-run + names(本决策)** | 与 ADR 0034 verb 三件套对齐;types 即合约;`updateSkills` 加 `onlyIds` 不破坏外部约定 | 改动量略大,需要测试覆盖三个闸 × 三个 UX |
35
+
36
+ ## Decision
37
+
38
+ 1. **`runSkillsUpdate` 的升级范围 = `keys(lock.skills) ∩ scope-match ∩ (names if given)`**:
39
+ - 起点 = 当前 lock 已记录的 skill ids(不再以 manifest 为起点)
40
+ - 减去 `(s.scope ?? 'project') !== currentInstallScope` 的(scope 闸,与 ADR 0033 在 init 中的过滤对齐)
41
+ - 与命令行传入的 `[names...]` 取交集(若有)
42
+ - = 真要更新的 `targetIds`
43
+ 2. **version 完全一致时短路**:`targetIds` 中所有 id 的 `lock.skills[id].version === manifest.skills[id].version` → 返回 `'no-changes'`,不写盘。
44
+ 3. **新 skill 不能被 update 自动引入**,只通过 `skills add <id>` 显式装。
45
+ 4. **`updateSkills` 接受可选 `onlyIds: string[]`**,与 `SkillSyncOptions.onlyIds` 类型对齐;不传保持旧行为(向后兼容,不破坏 `core` 子路径外部约定)。
46
+ 5. **lock 写回只触碰 `targetIds`**;未升级的条目原样保留。`installedManifest.installed[skills].resources` 同理 — 保留未触碰的 resource records。
47
+ 6. **CLI 表面**:`teamix-evo skills update [names...] [--dry-run]`。命令头打印 `teamix-evo CLI v0.x.y · skills package v0.a.b`,便于排查 CLI 与包版本是否同步。
48
+ 7. **新增 core API**:`runSkillsUpdate` / `RunSkillsUpdateOptions` / `RunSkillsUpdateResult` / `UpdatePlanItem`,与 `runSkillsInit` / `runSkillsAdd` 三件套对齐(ADR 0034)。
49
+
50
+ ## Consequences
51
+
52
+ - **Positive**:
53
+ - manage(主操作点)的全局升级路径可靠 — 不会装错 scope,不会引入未装 skill
54
+ - 版本未变时短路,managed 区域用户改动不再被来回备份
55
+ - `--dry-run` 让用户能预检,降低升级心智负担
56
+ - `[names...]` 让 manage 自身能精确升级而不动其它 skill
57
+ - CLI banner 让"哪个版本在跑"可见,排查 npx cache / 包不同步的问题更容易
58
+ - programmatic API 三件套对齐,types 即合约
59
+ - **Negative**:
60
+ - 用户原本期望"update 一并把新 skill 装上"会落空 — 但这本就是 `add` 的职责,文档已对齐
61
+ - `updateSkills` 的 `onlyIds` 参数让函数签名更长一点;不传时旧行为不变,影响面在内部
62
+ - **Trade-off**:
63
+ - 用三道闸 + 一个新 core API 的复杂度,换 manage 升级链路的可靠性。manage 是用户主操作点,这个权衡明显值得
64
+
65
+ ## Source
66
+
67
+ - 用户反馈(2026-06-04):「帮我关注下 teamix-evo-manage 安装后的升级吧。因为后续其他包的升级可能还没怎么完善,teamix-evo-manage 是用户主操作点,我如果可以更新 teamix-evo-manage,那就能保证后所有研发迭代都能处理」
68
+ - 实施 plan:`/Users/lyca/.claude/plans/refactored-roaming-grove.md`
69
+ - 测试覆盖:`packages/cli/src/__tests__/skills-update.test.ts`(Bug 1/2/3 + UX 4/5/6 + 3 个 edge case,共 10 个 it)
@@ -1,7 +1,7 @@
1
1
  # Architecture Decision Records
2
2
 
3
3
  > 本目录沉淀 Teamix Evo 的"为什么这么做"——决策的上下文、选项、取舍与后果。
4
- > 设计参照 [Michael Nygard. *Documenting Architecture Decisions*. 2011](https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions)。
4
+ > 设计参照 [Michael Nygard. _Documenting Architecture Decisions_. 2011](https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions)。
5
5
 
6
6
  ## 为什么需要 ADR
7
7
 
@@ -13,33 +13,38 @@ ADR 补这一层。每条 ADR 是一份**单决策档案**:在某一时刻、某
13
13
 
14
14
  ADR 按编号区段对应 [PLAN §12](../../PLAN.md#12-五层模型驱动的演进规划v05) 的抽象层:
15
15
 
16
- | 编号区段 | 抽象层 | 内容 |
17
- | --- | --- | --- |
18
- | 0001–0099 | 工程哲学(Philosophy) | 跨工种共享、几乎不变的工程理念 |
16
+ | 编号区段 | 抽象层 | 内容 |
17
+ | --------- | ------------------------------------ | -------------------------------------------------- |
18
+ | 0001–0099 | 工程哲学(Philosophy) | 跨工种共享、几乎不变的工程理念 |
19
19
  | 0100–0999 | 协议与工具(Foundations + Patterns) | CLI 命令、Schema、组件、Skills、MCP 等具体协议决策 |
20
- | 1000+ | 业务消费方决策(Scenarios) | 真实业务团队装机后的领域决策 |
20
+ | 1000+ | 业务消费方决策(Scenarios) | 真实业务团队装机后的领域决策 |
21
21
 
22
22
  > **种子 ADR 的特殊处理**:0001–0006 是 P0-1 任务从 PLAN.md §1 / §10 / §11 / 附录 B 反向沉淀的"已发生决策",作为种子条目使用顺序号,不严格按区段分配。从 0007 起按区段约定执行。
23
23
 
24
24
  ## 当前 ADR 索引
25
25
 
26
- | # | 标题 | 状态 | 日期 |
27
- | --- | --- | --- | --- |
28
- | 0001 | [三层对齐(能力/理念/工程)](0001-three-layer-alignment.md) | Accepted | 2026-05-15 |
29
- | 0002 | [包命名方案](0002-package-naming.md) | Accepted | 2026-05-13 |
30
- | 0003 | [资源升级三态语义](0003-update-strategy-tri-state.md) | Accepted | 2026-05-13 |
31
- | 0004 | [CLI 命令结构](0004-cli-command-structure.md) | Accepted | 2026-05-13 |
32
- | 0005 | [UI 包不分 variant](0005-ui-no-variant.md) | Accepted | 2026-05-14 |
33
- | 0006 | [UI 升级机制无 baseline](0006-ui-upgrade-no-baseline.md) | Accepted | 2026-05-14 |
34
- | 0007 | [治理文档放根目录,与 packages/docs/ 分离](0007-governance-docs-at-root.md) | Accepted | 2026-05-17 |
35
- | 0008 | [ESLint 视觉规则暂为 warn 级,等待 design 补 token](0008-eslint-visual-rules-warn-baseline.md) | Accepted | 2026-05-17 |
36
- | 0009 | [registry-mcp 作为 AI 协议层的第一个 MCP server](0009-registry-mcp-protocol-layer.md) | Superseded in part by 0011 | 2026-05-17 |
37
- | 0010 | [design 默认+变体模型(default + variants/ + extends,文件级覆盖)](0010-design-default-and-variants.md) | Proposed | 2026-05-18 |
38
- | 0011 | [MCP 单包单 bin 多 group + registry-mcp 改名 mcp](0011-mcp-single-package-multi-group.md) | Proposed | 2026-05-18 |
39
- | 0012 | [ESLint/Stylelint 双包共享 lint-core 内核](0012-lint-shared-core.md) | Proposed | 2026-05-18 |
40
- | 0013 | [Skills source-mirror 模型(.teamix-evo/skills/ 为源)](0013-skills-source-mirror.md) | Proposed | 2026-05-18 |
41
- | 0014 | [ui / biz-ui / templates 三层包分层(三包共享变体名空间)](0014-ui-biz-ui-templates-tier.md) | Proposed | 2026-05-18 |
42
- | 0019 | [已有工程升级 Teamix Evo 流程(语义合并 / 变体迁移 / cva codemod)](0019-project-upgrade-flow.md) | Proposed | 2026-05-21 |
26
+ | # | 标题 | 状态 | 日期 |
27
+ | ---- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ---------- |
28
+ | 0001 | [三层对齐(能力/理念/工程)](0001-three-layer-alignment.md) | Accepted | 2026-05-15 |
29
+ | 0002 | [包命名方案](0002-package-naming.md) | Accepted | 2026-05-13 |
30
+ | 0003 | [资源升级三态语义](0003-update-strategy-tri-state.md) | Accepted | 2026-05-13 |
31
+ | 0004 | [CLI 命令结构](0004-cli-command-structure.md) | Accepted | 2026-05-13 |
32
+ | 0005 | [UI 包不分 variant](0005-ui-no-variant.md) | Accepted | 2026-05-14 |
33
+ | 0006 | [UI 升级机制无 baseline](0006-ui-upgrade-no-baseline.md) | Accepted | 2026-05-14 |
34
+ | 0007 | [治理文档放根目录,与 packages/docs/ 分离](0007-governance-docs-at-root.md) | Accepted | 2026-05-17 |
35
+ | 0008 | [ESLint 视觉规则暂为 warn 级,等待 design 补 token](0008-eslint-visual-rules-warn-baseline.md) | Accepted | 2026-05-17 |
36
+ | 0009 | [registry-mcp 作为 AI 协议层的第一个 MCP server](0009-registry-mcp-protocol-layer.md) | Superseded in part by 0011 | 2026-05-17 |
37
+ | 0010 | [design 默认+变体模型(default + variants/ + extends,文件级覆盖)](0010-design-default-and-variants.md) | Proposed | 2026-05-18 |
38
+ | 0011 | [MCP 单包单 bin 多 group + registry-mcp 改名 mcp](0011-mcp-single-package-multi-group.md) | Proposed | 2026-05-18 |
39
+ | 0012 | [ESLint/Stylelint 双包共享 lint-core 内核](0012-lint-shared-core.md) | Proposed | 2026-05-18 |
40
+ | 0013 | [Skills source-mirror 模型(.teamix-evo/skills/ 为源)](0013-skills-source-mirror.md) | Proposed | 2026-05-18 |
41
+ | 0014 | [ui / biz-ui / templates 三层包分层(三包共享变体名空间)](0014-ui-biz-ui-templates-tier.md) | Proposed | 2026-05-18 |
42
+ | 0019 | [已有工程升级 Teamix Evo 流程(语义合并 / 变体迁移 / cva codemod)](0019-project-upgrade-flow.md) | Proposed | 2026-05-21 |
43
+ | 0021 | [语义色 API 统一治理(`tone`/`status`/`variant` 三分 + 字面值对齐 token)](0021-semantic-color-api-unification.md) | Accepted | 2026-05-29 |
44
+ | 0022 | [preferences.css 边界约束(仅装机偏好,禁止组件级 utility / token alias)](0022-preferences-css-boundary.md) | Accepted | 2026-05-31 |
45
+ | 0029 | [Input 拆分 + 移除 prefix/suffix/addon 快捷 prop + AutoComplete 内核同源化](0029-input-split-and-prefix-suffix-removal.md) | Accepted | 2026-06-02 |
46
+ | 0030 | [uni-manager 变体 design + code skill 落地 + 通用规则反哺 opentrek](0030-skill-uni-manager-uplift.md) | Accepted | 2026-06-02 |
47
+ | 0031 | [AI Skill 链路解耦 `@teamix-evo/templates` 包(patterns/ 单一默认来源)](0031-skill-templates-decoupling.md) | Accepted | 2026-06-02 |
43
48
 
44
49
  ## 写新 ADR 的流程
45
50
 
@@ -52,12 +57,12 @@ ADR 按编号区段对应 [PLAN §12](../../PLAN.md#12-五层模型驱动的演
52
57
 
53
58
  ## 状态值
54
59
 
55
- | 状态 | 含义 |
56
- | ---- | ---- |
57
- | Proposed | 草案,等待评审 |
58
- | Accepted | 已采纳并执行 |
59
- | Superseded by NNNN | 被另一条 ADR 替代 |
60
- | Deprecated | 决策不再适用,但无新替代 |
60
+ | 状态 | 含义 |
61
+ | ------------------ | ----------------------- |
62
+ | Proposed | 草案,等待评审 |
63
+ | Accepted | 已采纳并执行 |
64
+ | Superseded by NNNN | 被另一条 ADR 替代 |
65
+ | Deprecated | 决策不再适用,但无新替代 |
61
66
 
62
67
  ## 反向约束
63
68
 
package/dist/index.js CHANGED
@@ -88,33 +88,46 @@ function parseFrontmatter(text) {
88
88
 
89
89
  // src/groups/registry.ts
90
90
  var ListComponentsInput = z.object({
91
- status: z.enum(["stable", "experimental", "deprecated"]).optional()
91
+ status: z.enum(["stable", "experimental", "deprecated"]).optional(),
92
+ /**
93
+ * Include archived entries from `manifest.deprecatedEntries` (ADR 0028).
94
+ * Equivalent to `status: "deprecated"` when set alone, but composes with
95
+ * other filters: e.g. unset status + `includeDeprecated: true` returns
96
+ * active + deprecated together.
97
+ */
98
+ includeDeprecated: z.boolean().optional()
92
99
  });
93
100
  var GetComponentMetaInput = z.object({
94
101
  id: z.string().min(1)
95
102
  });
96
103
  var FindComponentsInput = z.object({
97
104
  query: z.string().min(1),
98
- limit: z.number().int().positive().max(100).optional()
105
+ limit: z.number().int().positive().max(100).optional(),
106
+ /** Include archived deprecated entries in matches (ADR 0028). */
107
+ includeDeprecated: z.boolean().optional()
99
108
  });
100
109
  var TOOLS = [
101
110
  {
102
111
  name: "list_components",
103
- description: "List all UI components in the @teamix-evo/ui registry. Optionally filter by status (stable / experimental / deprecated). Returns id, name, description, status, registryDependencies \u2014 small enough for the model to scan whole.",
112
+ description: 'List UI components in the @teamix-evo/ui registry. By default excludes archived `deprecatedEntries` (ADR 0028) \u2014 pass `includeDeprecated: true` (or `status: "deprecated"`) to inspect them, e.g. for upgrade audits. Returns id, name, description, status, registryDependencies \u2014 small enough for the model to scan whole.',
104
113
  inputSchema: {
105
114
  type: "object",
106
115
  properties: {
107
116
  status: {
108
117
  type: "string",
109
118
  enum: ["stable", "experimental", "deprecated"],
110
- description: "Filter by maturity status."
119
+ description: "Filter active entries by maturity status. `deprecated` returns the archived `deprecatedEntries` list."
120
+ },
121
+ includeDeprecated: {
122
+ type: "boolean",
123
+ description: "When true, merge archived `deprecatedEntries` into the result (ADR 0028)."
111
124
  }
112
125
  }
113
126
  }
114
127
  },
115
128
  {
116
129
  name: "get_component_meta",
117
- description: "Fetch the full registry entry + parsed meta.md for a single component by id. Returns props schema reference, registryDependencies, npm dependencies, AI generation rules, and the component description.",
130
+ description: "Fetch the full registry entry + parsed meta.md for a single component by id. Searches both active `entries` and archived `deprecatedEntries`; deprecated hits are flagged via `archived: true` in the payload. Returns props schema reference, registryDependencies, npm dependencies, AI generation rules, and the component description.",
118
131
  inputSchema: {
119
132
  type: "object",
120
133
  properties: {
@@ -128,7 +141,7 @@ var TOOLS = [
128
141
  },
129
142
  {
130
143
  name: "find_components",
131
- description: 'Substring match over component id / name / description. Use when you need a component but don\'t know its exact id (e.g. "find a component supporting async search and pagination"). Returns up to `limit` matches (default 10). Note: substring match is a v0.1 implementation; semantic search is planned for v0.7 (see ADR 0009).',
144
+ description: 'Substring match over component id / name / description. Use when you need a component but don\'t know its exact id (e.g. "find a component supporting async search and pagination"). Excludes archived `deprecatedEntries` by default \u2014 pass `includeDeprecated: true` to widen the search (ADR 0028). Returns up to `limit` matches (default 10). Note: substring match is a v0.1 implementation; semantic search is planned for v0.7 (see ADR 0009).',
132
145
  inputSchema: {
133
146
  type: "object",
134
147
  properties: {
@@ -141,6 +154,10 @@ var TOOLS = [
141
154
  minimum: 1,
142
155
  maximum: 100,
143
156
  description: "Max matches to return (default 10)."
157
+ },
158
+ includeDeprecated: {
159
+ type: "boolean",
160
+ description: "When true, also search archived `deprecatedEntries` (ADR 0028)."
144
161
  }
145
162
  },
146
163
  required: ["query"]
@@ -160,6 +177,9 @@ function pickListEntry(entry) {
160
177
  registryDependencies: entry.registryDependencies ?? []
161
178
  };
162
179
  }
180
+ function pickArchivedEntry(entry) {
181
+ return { ...pickListEntry(entry), archived: true };
182
+ }
163
183
  function createRegistryGroup(opts = {}) {
164
184
  let cache = opts.loaded ?? null;
165
185
  function getManifest() {
@@ -174,30 +194,44 @@ function createRegistryGroup(opts = {}) {
174
194
  if (name === "list_components") {
175
195
  const input = ListComponentsInput.parse(args ?? {});
176
196
  const { manifest } = getManifest();
177
- const entries = manifest.entries.filter((e) => e.type === "component").filter((e) => input.status ? e.status === input.status : true).map(pickListEntry);
197
+ const archived = manifest.deprecatedEntries ?? [];
198
+ if (input.status === "deprecated") {
199
+ const entries = archived.filter((e) => e.type === "component").map(pickArchivedEntry);
200
+ return {
201
+ content: [{ type: "text", text: JSON.stringify(entries, null, 2) }]
202
+ };
203
+ }
204
+ const active = manifest.entries.filter((e) => e.type === "component").filter((e) => input.status ? e.status === input.status : true).map(pickListEntry);
205
+ const merged = input.includeDeprecated ? [
206
+ ...active,
207
+ ...archived.filter((e) => e.type === "component").map(pickArchivedEntry)
208
+ ] : active;
178
209
  return {
179
- content: [{ type: "text", text: JSON.stringify(entries, null, 2) }]
210
+ content: [{ type: "text", text: JSON.stringify(merged, null, 2) }]
180
211
  };
181
212
  }
182
213
  if (name === "get_component_meta") {
183
214
  const input = GetComponentMetaInput.parse(args);
184
215
  const { manifest, rootDir } = getManifest();
185
216
  const entry = manifest.entries.find((e) => e.id === input.id);
186
- if (!entry) {
217
+ const archived = entry ? null : (manifest.deprecatedEntries ?? []).find((e) => e.id === input.id) ?? null;
218
+ const found = entry ?? archived;
219
+ if (!found) {
187
220
  return {
188
221
  content: [
189
222
  {
190
223
  type: "text",
191
- text: `Component not found: ${input.id}. Use list_components to discover ids.`
224
+ text: `Component not found: ${input.id}. Use list_components to discover ids (pass includeDeprecated: true to widen the search).`
192
225
  }
193
226
  ],
194
227
  isError: true
195
228
  };
196
229
  }
197
- const meta = loadMeta(entry, rootDir);
230
+ const meta = loadMeta(found, rootDir);
198
231
  const payload = {
199
- entry,
200
- meta: meta ?? null
232
+ entry: found,
233
+ meta: meta ?? null,
234
+ archived: archived !== null
201
235
  };
202
236
  return {
203
237
  content: [{ type: "text", text: JSON.stringify(payload, null, 2) }]
@@ -208,9 +242,23 @@ function createRegistryGroup(opts = {}) {
208
242
  const limit = input.limit ?? 10;
209
243
  const q = input.query.toLowerCase();
210
244
  const { manifest } = getManifest();
211
- const matches = manifest.entries.filter((e) => e.type === "component").filter((e) => {
212
- return e.id.toLowerCase().includes(q) || e.name.toLowerCase().includes(q) || e.description.toLowerCase().includes(q);
213
- }).slice(0, limit).map(pickListEntry);
245
+ const pool = input.includeDeprecated ? [
246
+ ...manifest.entries.map((e) => ({ entry: e, archived: false })),
247
+ ...(manifest.deprecatedEntries ?? []).map((e) => ({
248
+ entry: e,
249
+ archived: true
250
+ }))
251
+ ] : manifest.entries.map((e) => ({ entry: e, archived: false }));
252
+ const matches = pool.filter(({ entry }) => entry.type === "component").filter(({ entry, archived: a }) => {
253
+ if (!input.includeDeprecated && !a && entry.status === "deprecated") {
254
+ return false;
255
+ }
256
+ return true;
257
+ }).filter(({ entry }) => {
258
+ return entry.id.toLowerCase().includes(q) || entry.name.toLowerCase().includes(q) || entry.description.toLowerCase().includes(q);
259
+ }).slice(0, limit).map(
260
+ ({ entry, archived: a }) => a ? pickArchivedEntry(entry) : pickListEntry(entry)
261
+ );
214
262
  return {
215
263
  content: [
216
264
  {