# Skill Manage

> 管理本机 Agent Skills 的安装、卸载、上游更新与集中收编。当用户说「安装/启用某个 skill 到项目或全局」「卸载/移除某个 skill」「更新 skill」「看看有哪些 skill」「skill 散落各处」「扫描 skill」「skill 冲突了」时使用本工具，而不是手动创建目录或复制文件。

- Skill: `eastgold15/skill-manage` (Agent Skill)
- Install (CLI): `npx skillmds@latest add eastgold15/skill-manage`
- Raw SKILL.md: https://api.skillmd.com/api/skills/eastgold15/skill-manage/raw
- Safety review: pending (external: skill-scanner PASS, skillspector CAUTION)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: eastgold15 (https://skillmd.com/u/eastgold15)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/eastgold15/skill-manage

---


# Skill 管理

本机的 skill 由 `agent` CLI 统一管理。**不要手动在 `.claude/skills/` 下建目录或拷文件** —— 那样会绕过链接机制与三路合并，之后无法更新。

## 心智模型

```
~/.agents/skills/<id>     ← 本体（唯一实体，skills.sh 下载到这里）
       ↑ junction              ↑ junction
~/.claude/skills/<id>     ./.claude/skills/<id>
   （全局启用）                （项目启用）
```

- 启用 = 建一个 junction 链接，**不拷贝**。同一个 skill 在 10 个项目启用也只占一份磁盘。
- 因为两个作用域指向同一实体，**不存在"项目版本覆盖全局版本"**，改任何一处就是改本体。
- 卸载 = 删链接，本体库**永不受影响**。
- `~/.agents/.skill-lock.json` 是 skills.sh 的文件，本工具**只读不写**。

## 三个数据文件

| 文件 | 谁维护 | 作用 |
|---|---|---|
| `~/.agents/.skill-lock.json` | skills.sh | 上游来源总账，本工具只读 |
| `~/.agents/.merge-state.json` | 本工具 | base 快照与合并历史 |
| `~/.agents/.skill-scan.json` | **用户手工** | 扫描策略（include/exclude glob） |
| `~/.agents/.scan-cache.json` | 本工具 | 上次扫描结果，避免每次全盘扫 |

## 常用命令

工具在项目根目录，用 `bun run src/index.ts` 调用（或已装好的 `agent` 命令）。


### 查看有哪些 skill

```bash
agent list           # 表格，给人看（默认隐藏已失联的）
agent list --json    # JSON，给你（AI）解析用，优先用这个
agent list --all     # 连已失联的记录一起显示
```

JSON 每项形如：

```json
{ "id": "codegraph", "tracked": true, "status": "up-to-date", "checkedAt": "2026-08-05T11:12:25Z",
  "conflicts": 0, "enabledGlobal": false, "enabledProject": true, "orphaned": false }
```

表格里 `v` 表示已启用、`-` 表示未启用。**"项目"列只在当前目录确实有 `.claude/skills` 时才出现** —— 它指的是你执行命令所在的目录，不在项目里时那一列全是 `-`，纯占宽度。JSON 输出不受此影响，`enabledProject` 始终存在。

**`tracked` 与 `status` 是两件事，别混：**

- `tracked: true` = lock 里有上游记录，**能**执行 update。与"有没有新版本"无关。
- `status` = 上次检查的结论，回答**要不要** update：

| status | 含义 | update 会怎样 |
|---|---|---|
| `unknown` | 有上游但从未检查过 | 不知道，先跑 `agent check` |
| `up-to-date` | 上次检查时两边都没变 | 提示"已是最新"，什么都不做 |
| `local-only` | 只有你改过，上游没动 | 提示"上游无变化，保留本地修改" |
| `behind` | 上游有新内容 | 快进到最新 |
| `diverged` | 上游有新内容且你也改过 | 三路合并 |
| `conflicted` | 上次合并留了冲突未解 | 需先手工处理冲突标记 |
| `no-upstream` | 没有上游 | 无法 update |

`status` 来自**上次** check 或 update，可能过时——`checkedAt` 交代新鲜度。要知道上游此刻的真实状态，跑 `agent check`。

`list` 还会提示有多少 skill 散落在本体库外（读扫描缓存，不动文件）。

### 检查上游有无新版本

```bash
agent check              # 检查全部有上游的（联网，每个约 2 秒）
agent check codegraph    # 只检查指定的
agent check --json
```

**只看不动**：拉上游、比四象限、把结论写进 state，本体库一个字节都不碰。之后 `agent list` 的状态列就是实时的了。

为什么需要单独一个命令：判断"上游有没有新版本"**本地无从推导**。`lockFolderHash` 是 skills.sh 安装时算的，不随上游变化；`.base/` 快照只记录上次同步态。必须联网拉一次对比。做成独立命令是为了让 `list` 保持只读且毫秒级。

### 启用（安装到作用域）

用户说"把 X 装到这个项目"：

```bash
agent enable codegraph -p              # 装到当前项目
agent enable codegraph ast-grep -p     # 一次装多个
agent enable codegraph -g              # 装到全局
```

**给出 ID 时是非交互的，直接执行。** 不带 ID 会进入 TUI 多选界面 —— 你（AI）不要走这条路，会卡在交互上。

`-p` / `--project` 与 `-g` / `--global` 二选一；**都不传时默认项目作用域**（非交互路径）。若用户没说清装到哪，问一句再执行。

### 卸载（停用，保留本体）

用户说"把 X 从项目里移除"、"停用 X"：

```bash
agent disable codegraph -p
agent disable codegraph ast-grep -g
```

只删本工具建的链接，**本体库不动**，之后还能再启用。遇到外部工具建的链接或手写的真实目录会**拒绝删除并提示**，这是有意的保护。

### 彻底删除（从本体库抹掉）

用户说"删掉 X"、"不要 X 了"、"清理这些 skill"：

```bash
agent remove                          # TUI 多选
agent remove old-skill another-one    # 直接指定，仍会要确认
agent remove old-skill --force        # 跳过确认
agent remove old-skill --no-sync      # 不通知 skills.sh，只打印命令
```

**与 disable 的区别**：`disable` 只摘链接，`remove` 是把本体库里的目录删掉，不可再启用。用户说"移除/停用"时优先问清是哪个意思。

执行顺序（顺序有讲究，不能颠倒）：

1. **摘掉作用域链接** —— 必须先做。实测删掉本体后 junction 仍然存在但变成**悬空链接**（`lstat` 能读到、`readlink` 还指向原处，但内容 ENOENT），Claude Code 扫到会出错
2. 删除本体目录与 `.base/` 快照
3. 清掉 `.merge-state.json` 里的条目
4. **通知 skills.sh**（`npx skills remove <ids> -g -y`）—— 不同步的话它还以为装着，而且 `.skill-lock.json` 的残留记录会在下次 `syncFromLock` 时被重新投影，在 `ls` 里显示成"已失联"

**安全性**：删除前自动建 git 检查点（本体库已 git 化的话），可 `git revert` 找回。若本体库还没纳入 git，会警告"删除不可恢复"并建议先跑 `agent repo`。遇到非本工具建立的作用域链接会**中止该项删除**，避免留下悬空链接。

### 更新（三路合并）

```bash
agent update codegraph    # 更新单个
agent update              # TUI 多选，AI 不要用
```

更新按四象限判定：

| 本地改过 | 上游变了 | 行为 |
|---|---|---|
| 否 | 否 | 无需更新 |
| 否 | 是 | 快进到上游最新 |
| 是 | 否 | 保留本地，什么都不做 |
| 是 | 是 | 逐文件三路合并 |

第四象限里，**上游改 `SKILL.md`、你改 `references/usage.md` 会自动合并、零冲突**；只有同一文件同一处两边都改才需要人介入。

有冲突时：文件里留下 `<<<<<<<` 标记，命令会列出冲突文件路径，且**不推进基线**（下次仍能识别）。此时告知用户哪些文件冲突，可代为编辑解决冲突标记。

首次更新某个已装 skill 会提示"首次接管，已用当前内容建立基线" —— 这次判不出本地修改，第二次起完整可用。

### 诊断

```bash
agent doctor
```

区分作用域目录下三类东西：本工具纳管的链接、外部工具建的链接、真实目录副本。用户抱怨"skill 状态不对"时先跑这个。

### 扫描与收编（解决"skill 散落各处"）

```bash
agent scan                          # 按配置全盘扫，报告分布
agent scan L:/Documents/GitHub      # 只扫指定位置
agent scan --reuse                  # 用上次结果重新判定，不重扫磁盘（改完配置后用）
agent scan --json                   # JSON 输出
agent scan --normalize              # 预演收编，不动任何文件
agent scan --normalize --apply      # 真正执行
```

**判定 skill 的条件只有一条**：目录下直接含 `SKILL.md`。

**"是否算用户的 skill"由配置决定**，不是代码猜的。策略在 `~/.agents/.skill-scan.json`：

```json
{
  "roots": ["C:/Users/boer", "L:/Documents/GitHub"],
  "include": ["**/.claude/skills/*", "**/.agents/skills/*", "**/.cursor/skills/*"],
  "exclude": ["**/node_modules/**", "**/.trae-cn/builtin/**", "**/bundled-skills/**"]
}
```

用 `agent config` 查看位置与当前内容。**这个文件由用户手工编辑** —— 实测这台机器全盘有 2191 处 `SKILL.md`，其中 1985 处是 Trae/Hermes 内置资源与包缓存，只有 201 处是用户的。范围判断是用户偏好，代码判断不了。用户说"这些也要管"或"别扫那里"时，改这个文件再跑 `--reuse`。

**归一化做什么**：把本体库外的 skill 复制进 `~/.agents/skills/`，原位置替换为指向它的 junction。四种结果：

| 情况 | 结果 | 说明 |
|---|---|---|
| 本体库没有 | `adopted` | 复制进去，原位置换链接 |
| 本体库有、内容一致 | `linked` | 直接换链接 |
| 本体库有、**内容不同** | `diverged` | **一个文件都不动**，报出让人决定 |
| 指向别处的链接 | `external` | 别的工具的资产，不碰 |

`diverged` 是关键保护：同名不等于同内容，静默覆盖会真丢数据。遇到时用 `agent diff` 逐个处理（见下节）。

**默认是预演。** 不加 `--apply` 绝不动文件。执行前建议先让用户看预演结果。

### 比对与决定（处理 diverged）

```bash
agent diff --list          # 只列出差异清单与涉及的文件，不动任何东西
agent diff                 # 逐个处理
agent diff find-skills     # 只处理这个 id
```

每处会显示本体库与项目两侧路径、哪些文件内容不同、哪些是单边独有，然后给四个选项：

| 选项 | 行为 |
|---|---|
| 打开 VS Code 对照编辑 | `code --diff` 逐文件开左右对照；关窗后重新比对，两边一致则自动收编换链接 |
| 保留本体库这份 | 项目那份换成链接，其内容丢弃 |
| 用项目这份覆盖本体库 | 本体库被替换，项目换成链接 |
| 跳过 | 留着下次再说 |

**同一个 id 可能有多处待决**（实测 `find-skills` 在三个项目各一份，加本体库共四个版本互不相同）。工具会提示"另有 N 处待决"，并在每轮**实时重算**差异 —— 处理完一处后本体库内容已变，后面几处对照的是新内容。若某处恰好已与新的本体库一致，会直接收编不再询问。

编辑器不可用（找不到 `code` 命令）时会提示，其余三个选项仍然可用。

## 安装新 skill（本体库还没有的）

本工具**不负责从网上下载**。本体库为空或用户要装一个本地没有的 skill 时，用 skills.sh 的 CLI 下载到 `~/.agents/skills/`，再用 `agent enable` 启用。skill 目录也可以手动放到 `~/.agents/skills/<id>/`（含 `SKILL.md`），本工具会自动纳管，只是没有上游因而不可更新。

## 边界

- 目前只支持 Claude Code（`.claude/skills/`）作为启用目标
- 不写 `.skill-lock.json`
- 不删非本工具建立的东西
- `list` 只读不动文件；所有副作用都在 `enable`/`disable`/`update`/`scan --apply`


