refactor: fold ack kit into skill

This commit is contained in:
2026-07-30 11:54:02 +08:00
parent e308d6a04c
commit 076d87e303
32 changed files with 592 additions and 619 deletions
+219
View File
@@ -0,0 +1,219 @@
# Skill 来源模型
## 背景
skiff 当前使用 `owned` 表示本仓库 `skills/` 中维护的 Skill,同时还支持
`registry` 外部仓库和用户配置的 custom source。
这些名称混合了不同维度:
- `owned` 表示所有权。
- `registry` 表示来源配置存放在哪里。
- `external` 表示内容不在当前仓库。
- `collection` 表示一个来源中包含多个 Skill。
它们不能作为同一层级的互斥类型。例如 custom source 既可能来自外部 Git 仓库,
也可能是 collection;因此 `custom``external` 并不互斥。
本文建议将用户可见的来源注册方式统一为三类:
- `builtin`:随当前 skiff 仓库提供的 Skill。
- `catalog:<name>`:由 skiff 自带目录预先登记的来源。
- `custom:<name>`:用户在本机显式配置的命名来源。
来源注册方式与获取方式、仓库布局相互独立。builtin、catalog 和 custom 中的任意
来源都可以包含一个或多个 Skill;除 builtin 外,catalog 和 custom 都可以使用
Git 仓库或本地目录。
## 当前模型
```mermaid
flowchart TD
S[skiff 可发现的 Skills]
S --> O["owned<br/>~/.skills/skills/*"]
S --> C["custom source<br/>~/.config/skiff/config.yaml"]
S --> R["registry<br/>registry.yaml"]
O --> O1["本仓库维护<br/>随 skiff 一起分发"]
C --> C1["本地目录<br/>--local PATH"]
C --> C2["指定 Git 仓库<br/>repo + skills_path"]
R --> R1["外部单 Skill 仓库"]
R --> R2["外部 Skill Collection"]
R1 --> E["~/.local/share/skills/externals/"]
R2 --> E
```
当前实现中:
- `list``status` 支持 owned、registry 和 custom source。
- `resolve_skill_source` 可以解析三种来源并处理同名歧义。
- `select` 只组装 owned 和 registry 条目,尚未展示 custom source。
- `.skills.yaml` 默认将未声明来源的 Skill 解释为 `owned`
- custom source 的 `skills_path` 已经可以包含多个 Skill,本质上也是 collection。
## 推荐模型
```mermaid
flowchart TD
A[Skill Provider]
A --> B["builtin<br/>仓库内隐式注册"]
A --> C["catalog:waza<br/>skiff 预置目录"]
A --> D["custom:company<br/>用户本机配置"]
B --> B1["skills/ack"]
B --> B2["skills/skiff"]
B --> B3["skills/deb-publisher"]
C --> C1["Git 或本地目录"]
C1 --> C2["单 Skill"]
C1 --> C3["Collection"]
C3 --> C4["waza/think"]
C3 --> C5["waza/check"]
D --> D1["Git 或本地目录"]
D1 --> D2["单 Skill"]
D1 --> D3["Collection"]
D3 --> D4["company/security-review"]
D3 --> D5["company/release"]
```
### 来源注册方式
| 类型 | 含义 | 配置来源 | 用户界面展示 |
| --- | --- | --- | --- |
| `builtin` | 随当前 skiff 仓库提供 | `skills/` | `builtin` |
| `catalog` | skiff 预先登记、所有用户可发现的来源 | `catalog.yaml`,迁移前为 `registry.yaml` | `catalog:<name>` |
| `custom` | 用户在本机显式注册的命名来源 | `~/.config/skiff/config.yaml` | `custom:<name>` |
`builtin``owned` 更适合作为用户可见名称,因为它表达 Skill 的分发位置和可用
方式,而不是仓库的所有权关系。
`catalog``registry` 更准确:当前文件只是 skiff 随仓库维护的预置来源目录,
并不是远程注册中心,也不是一种 Skill 来源协议。
### 三个正交维度
每个 provider 应由三个维度描述:
```text
registration: builtin | catalog | custom
transport: bundled | local | git
layout: single | collection
```
custom source 示例:
```text
registration: custom
name: company
transport: local | git
layout: single | collection
```
catalog entry 示例:
```text
registration: catalog
name: waza
transport: local | git
layout: single | collection
```
`external` 只适合描述物理位置,可作为 catalog 和部分 custom provider 的统称,
不应成为与 builtin、custom 并列的持久化类型。
## `select` 展示
`skiff select` 应同时展示 builtin、catalog 和 custom Skill
```text
[ ] ack builtin
[ ] deb-publisher builtin
[-] company custom source
[ ] company/release custom:company
[ ] company/security-review custom:company
[-] waza catalog source
[ ] waza/check catalog:waza
[ ] waza/think catalog:waza
```
建议遵循以下规则:
- builtin Skill 直接显示 Skill 名称。
- catalog 和 custom collection 都使用来源名称作为父节点。
- catalog 和 custom Skill 都使用 `<source>/<skill>` 作为选择器键。
- 单 Skill 来源可以省略父节点,但仍显示注册方式和来源名称。
- 不同来源安装后名称相同时,继续拒绝同时选择,避免覆盖同一安装路径。
## 配置表示
新写入的 `.skills.yaml` 使用以下形式:
```yaml
skills:
- name: ack
source: builtin
- name: security-review
source: company
- name: think
source: catalog:waza
```
custom source 在 manifest 中继续保存其逻辑名称,例如 `company`。这样不同机器可以
独立配置仓库地址,而项目只依赖稳定的来源名称。
## 兼容迁移
这是一次用户可见术语调整,应提供兼容层,避免已有项目立即失效:
1. 对外文档、CLI 输出和 selector 统一使用 `builtin``catalog:<name>`
`custom:<name>`
2. 新生成的 `.skills.yaml` 对内置 Skill 写入 `source: builtin`
3. 读取旧 manifest 时继续接受 `source: owned`,并在解析时归一化为 `builtin`
4. CLI 参数在过渡期继续接受 `--source owned`,但帮助和输出只推荐 `builtin`
5. 读取旧 manifest 中的 `source: registry``registry: <name>`,归一化为
`catalog:<name>`
6. `registry.yaml` 可以先保留文件名,仅将用户界面术语改为 catalog;单独迁移为
`catalog.yaml` 时,应兼容读取旧文件。
7. custom source 的逻辑名称和现有 `config.yaml` 结构保持不变。
8.`builtin``catalog` 和兼容别名 `owned``registry` 设为 custom source
保留字。
9. `select` 同步接入 custom Skill,并让 custom collection 与 catalog collection
使用相同的父子展示逻辑。
## 影响范围
实施时预计涉及:
- `skiff/skills.py`:来源解析、归一化和 builtin 命名。
- `skiff/project.py`:manifest 默认值、序列化与旧值兼容。
- `skiff/sources.py`:来源保留字。
- `skiff/registry.py`:逐步重命名为 catalog 概念。
- `skiff/cli.py``list``status``add``select` 和输出文案。
- `skiff/selector.py`:统一 catalog/custom collection 的父子展示。
- CLI 与来源解析测试。
- 根 README、`skiff/README.md``skills/skiff/SKILL.md` 和相关示例。
## 验证要求
实施完成后至少覆盖:
- builtin Skill 可以通过新名称列出、选择、安装和写入 manifest。
- 旧的 `source: owned` manifest 仍可同步。
- custom local source 和 custom Git source 都出现在 selector 中。
- catalog 单 Skill 和 Collection 都保持可选择。
- custom 单 Skill 和 Collection 都保持可选择。
- 多来源同名 Skill 必须显式指定来源。
- 两个选择最终安装为同一个名称时,selector 拒绝冲突。
- `list``status``select` 对同一来源使用一致术语。
## 设计前提
本方案假设 `registry.yaml` 当前的真实职责是维护 skiff 预置的来源目录,而不是提供
远程发布、版本解析或可信签名等注册中心能力。因此推荐逐步将用户可见概念改为
`catalog`。如果未来实现真正的远程 registry,再单独定义其协议和与 catalog 的同步
关系,不复用当前含义模糊的名称。