opencode-skills-doctor 0.9.4 → 0.9.7

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.
package/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
  <h1 align="center">skills-doctor</h1>
6
6
 
7
7
  <p align="center">
8
- <b>Audit, fix and update the skills your coding agent loads.</b><br>
9
- Measure the per-step token tax, find shadowed duplicates and broken references — then fix them safely.
8
+ <b>Your skills are quietly taxing every single step.</b><br>
9
+ 29 skills = ~3,074 tokens burned before the model even sees your code.
10
10
  </p>
11
11
 
12
12
  <p align="center">
@@ -14,6 +14,7 @@
14
14
  <a href="https://www.npmjs.com/package/opencode-skills-doctor"><img src="https://img.shields.io/npm/dw/opencode-skills-doctor?style=for-the-badge&color=2ea043" alt="npm downloads"></a>
15
15
  <a href="https://github.com/wangyuchen5110/opencodeplugginprogram/stargazers"><img src="https://img.shields.io/github/stars/wangyuchen5110/opencodeplugginprogram?style=for-the-badge&color=58a6ff" alt="GitHub stars"></a>
16
16
  <a href="https://github.com/wangyuchen5110/opencodeplugginprogram/actions/workflows/test.yml"><img src="https://github.com/wangyuchen5110/opencodeplugginprogram/actions/workflows/test.yml/badge.svg" alt="tests"></a>
17
+ <a href="https://github.com/marketplace/actions/skills-doctor"><img src="https://img.shields.io/badge/GitHub%20Marketplace-skills--doctor-3fb950?style=for-the-badge&logo=github" alt="GitHub Marketplace"></a>
17
18
  </p>
18
19
 
19
20
  <p align="center">
@@ -31,25 +32,27 @@
31
32
  > **Runs 100% locally.** No telemetry, no account, no uploads — your skills,
32
33
  > prompts and files never leave your machine. See [Privacy](#privacy-local-only-no-data-collection).
33
34
 
34
- ## Contents
35
+ ## The hidden tax
35
36
 
36
- - [The 30-second version](#the-30-second-version) · [Privacy](#privacy-local-only-no-data-collection)
37
- - [See it](#see-it) · [How it works](#how-it-works) · [Quick start](#quick-start)
38
- - [Install](#install) · [Use it in CI](#use-it-in-ci-github-action) · [Commands](#commands) · [Works where you work](#works-where-you-work)
39
- - [Why it is safe](#why-it-is-safe) · [Development](#development)
37
+ Every agent skill with a `description` is injected into the system prompt on **every single step**. On a real machine with 29 skills that was **~3,074 tokens** — before the model read a single line of code. Duplicates silently shadow each other. Long descriptions never get trimmed. Broken references go unnoticed.
40
38
 
41
- ## The 30-second version
39
+ `skills-doctor` measures the exact cost, shows which definition actually wins, and gives you a concrete plan to cut it:
42
40
 
43
- Every agent skill with a `description` is advertised to the model on **every single step**. On a machine with 29 skills that is **~3,074 tokens per step** — before the model reads a line of your code. Duplicates silently shadow each other, descriptions drift, and references to files that no longer exist go unnoticed.
41
+ ```text
42
+ current: ~3,124 tokens/step (30 advertised) budget: 1,200
43
+
44
+ Recommended: trim 26 + hide 2 → 1,184 tokens/step (−1,940)
45
+ Over 100 steps that saves ~194,000 tokens.
46
+ ```
44
47
 
45
- `skills-doctor` measures that cost, shows which definition actually wins, and fixes it:
48
+ One command. Runs 100% locally. No account, no telemetry, nothing leaves your machine.
46
49
 
47
50
  | | |
48
51
  |---|---|
49
52
  | **Find** | token budget, shadowed duplicates, flat/dir collisions, long descriptions, oversized bodies, broken references, invalid frontmatter, stale skills |
50
- | **Fix** | archive shadowed definitions (reversible), hide low-frequency skills, trim descriptions with a measured plan |
53
+ | **Fix** | archive shadowed definitions (reversible), hide redundant skills before unique ones, keep the routing sentence in the plan |
51
54
  | **Update** | sync skills from HTTP catalogs with a lockfile, drift detection and `--prune` |
52
- | **Report** | terminal, JSON, or a self-contained HTML report |
55
+ | **Report** | a short note in the OpenCode chat, plus the terminal and JSON |
53
56
  | **Run it** | CLI · OpenCode plugin (1.x/2.x/Desktop) · MCP server · DeepSeek Harness skill |
54
57
 
55
58
  ## Privacy: local-only, no data collection
@@ -62,17 +65,13 @@ Every agent skill with a `description` is advertised to the model on **every sin
62
65
  | **Never reads** | conversation history, session transcripts, source code, documents, credentials, API keys or environment secrets |
63
66
  | **Uploads** | nothing: there is no server component and no remote endpoint besides the two optional calls below |
64
67
  | **Network** | only when you ask for it. `update` fetches the HTTP catalogs **you** configure; `upgrade` / the daily update check reads the npm registry for the latest version number (cached 24 h — disable with `"checkUpdates": "off"`, `SKILLS_DOCTOR_UPDATE_CHECK=0` or `--no-update-check`) |
65
- | **Writes** | only what you asked for: the HTML/JSON report, `.skills-doctor-archive/`, `.skills-doctor.json`, the lockfile, and the plugin/MCP/skill entries created by `install` |
68
+ | **Writes** | only what you asked for: `.skills-doctor-archive/`, `.skills-doctor.json`, the lockfile, and the plugin/MCP/skill entries created by `install` |
66
69
 
67
70
  `opencode.json(c)` and MCP configs can contain credentials; they are parsed locally only to find the relevant entries, and those values are never sent anywhere nor included in a report. Reports contain file paths and skill descriptions (which are part of your skill files), never file bodies. `check`, `plan`, `scan`, `fix --dry-run` and `mcp` all work with the network fully offline.
68
71
 
69
- ## See it
70
-
71
- <p align="center">
72
- <img src="https://raw.githubusercontent.com/wangyuchen5110/opencodeplugginprogram/main/docs/assets/report.png" alt="skills-doctor HTML report" width="82%">
73
- </p>
72
+ ## What you see
74
73
 
75
- A real `check --html` run: summary cards, the context-budget bar, filterable findings, and the exact potential savings.
74
+ In OpenCode 2, the first message of a session gets one notice in the chat when a skill is over budget, shadowed, or broken. It names at most three problems and does not change any file. `/skills-doctor` posts that notice again. The terminal `check` and `--json` output stay for CI.
76
75
 
77
76
  ## How it works
78
77
 
@@ -83,7 +82,7 @@ flowchart LR
83
82
  C --> D["lint<br/>16 rules + token budget"]
84
83
  D --> E{"findings?"}
85
84
  E -->|"yes"| F["plan / fix<br/>trim · hide · archive"]
86
- E -->|"always"| G["report<br/>terminal · JSON · HTML"]
85
+ E -->|"always"| G["tell you<br/>chat · terminal · JSON"]
87
86
  F --> G
88
87
  G --> H["you · CI · the agent"]
89
88
  ```
@@ -99,26 +98,12 @@ npx -y opencode-skills-doctor check
99
98
 
100
99
  # how many tokens can I actually cut?
101
100
  npx -y opencode-skills-doctor plan
102
-
103
- # shareable HTML report
104
- npx -y opencode-skills-doctor check --html report.html --open
105
- ```
106
-
107
- Example `plan` output on a real setup:
108
-
109
- ```text
110
- current: ~3,124 tokens/step (30 advertised) budget: 1,200
111
-
112
- Option A — trim descriptions 26 skills → 1,606 (−1,518)
113
- Option B — hide skills 11 skills → 1,200 (−1,924)
114
- Recommended trim 26 + hide 2 → 1,184 (−1,940)
115
- over 100 steps that saves ~194,000 tokens
116
101
  ```
117
102
 
118
103
  ## Install
119
104
 
120
105
  ```powershell
121
- # OpenCode — plugin + /skills-doctor, /skills-report, /skills-upgrade commands
106
+ # OpenCode — plugin + /skills-doctor and /skills-upgrade
122
107
  npx -y opencode-skills-doctor install # auto-detects 1.x / 2.x / Desktop
123
108
  npx -y opencode-skills-doctor install --client desktop
124
109
 
@@ -141,7 +126,8 @@ Nothing to configure for **skills discovery**: it reads `.opencode/skills`, `.cl
141
126
  ## Use it in CI (GitHub Action)
142
127
 
143
128
  A composite action ships in this repo: no install step, no runtime dependencies —
144
- it runs the checked-out code directly.
129
+ it runs the checked-out code directly. It is listed on the
130
+ [GitHub Marketplace](https://github.com/marketplace/actions/skills-doctor).
145
131
 
146
132
  ```yaml
147
133
  name: skills
@@ -156,16 +142,15 @@ jobs:
156
142
  runs-on: ubuntu-latest
157
143
  steps:
158
144
  - uses: actions/checkout@v4
159
- - uses: wangyuchen5110/opencodeplugginprogram@v0.9.4
145
+ - uses: wangyuchen5110/opencodeplugginprogram@v0.9.7
160
146
  with:
161
147
  budget: "1200"
162
148
  fail-on: warn # error | warn | never
163
- html: skills-report.html # written and uploaded as an artifact
164
149
  comment: "true" # post the summary on the PR
165
150
  ```
166
151
 
167
- It writes a summary to the job page, uploads the HTML report, optionally comments
168
- on the pull request, and fails the job according to `fail-on`.
152
+ It writes a summary to the job page, optionally comments on the pull request,
153
+ and fails the job according to `fail-on`.
169
154
 
170
155
  | Input | Default | Purpose |
171
156
  |---|---|---|
@@ -173,7 +158,6 @@ on the pull request, and fails the job according to `fail-on`.
173
158
  | `budget` | `1200` | Description tokens paid per model step |
174
159
  | `fail-on` | `error` | Fail on `error`, `warn`, or `never` |
175
160
  | `extra-args` | — | Extra `check` flags, e.g. `--no-global` |
176
- | `html` | — | HTML report path; uploaded as an artifact when set |
177
161
  | `comment` | `false` | Post/append the summary as a pull request comment |
178
162
 
179
163
  Outputs: `exit-code`, `error-count`, `warning-count`, `advertised-tokens`.
@@ -183,7 +167,7 @@ Outputs: `exit-code`, `error-count`, `warning-count`, `advertised-tokens`.
183
167
  | Command | What it does |
184
168
  |---|---|
185
169
  | `check` | audit sources, conflicts, budget and broken references (default) |
186
- | `plan` | exact token savings: what to trim, what to hide, projected over N steps |
170
+ | `plan` | savings from keeping the first sentence, then hiding redundant skills first, projected over N steps |
187
171
  | `scan` | every skill with its source, precedence and cost |
188
172
  | `fix` | archive shadowed definitions (reversible) or hide low-frequency skills |
189
173
  | `update` | sync skills from HTTP catalogs, verify hashes, detect drift |
@@ -204,7 +188,7 @@ All commands accept `--json`, `--lang en|zh`, `--budget`, `--root` and `--no-glo
204
188
  | **Claude Code / Codex** | MCP server (`npx -y opencode-skills-doctor mcp`) |
205
189
  | **Grok CLI / Cursor** | their skill roots are scanned natively |
206
190
  | **Hermes Agent** | MCP entry in `~/.hermes/config.yaml`; `~/.hermes/skills` is scanned |
207
- | **Kimi Code** | `install --client kimi` writes `~/.kimi-code/mcp.json` + the audit skill |
191
+ | **Kimi Code** | `install --client kimi` writes `~/.kimi-code/mcp.json` + the audit skill; or use the native plugin: [kimi-skills-doctor](https://github.com/wangyuchen5110/kimi-skills-doctor) |
208
192
  | **OpenClaw** | separate wrapper with its own native plugin: [openclaw-skills-doctor](https://github.com/wangyuchen5110/openclaw-skills-doctor) |
209
193
 
210
194
  ## Why it is safe
@@ -217,7 +201,7 @@ All commands accept `--json`, `--lang en|zh`, `--budget`, `--root` and `--no-glo
217
201
  ## Development
218
202
 
219
203
  ```powershell
220
- npm test # 58 tests (node test/doctor.test.mjs)
204
+ npm test # 73 tests (node test/doctor.test.mjs)
221
205
  npm run bench # lint timing for 100/500/1000 skills
222
206
  ```
223
207
 
package/SECURITY.md CHANGED
@@ -33,7 +33,7 @@ Include the version, a reproduction, the impact, and a suggested fix if you have
33
33
  - **No network by default.** Two opt-in/opt-out exceptions: `update` fetches the catalog URLs you configure, and the daily update check reads only the latest version number from the npm registry (24 h cache; disable with `"checkUpdates": "off"`, `SKILLS_DOCTOR_UPDATE_CHECK=0` or `--no-update-check`).
34
34
  - **No user data is read.** The tool reads skill files, their referenced resources, agent configuration and its own lockfile. It does not read chat history, session transcripts, source code, documents, model credentials or API keys — and it does not upload anything it reads.
35
35
  - **Config files may hold secrets** (`opencode.json(c)`, MCP configs). They are parsed locally only to locate the entries the tool needs; values are never transmitted, printed, or copied into reports.
36
- - **Reports are local files.** HTML/JSON reports contain file paths and skill descriptions, never file bodies. They can reveal your directory layout, so review them before sharing.
36
+ - **Reports stay on the machine.** Terminal output, JSON, the pull-request comment and the chat notice contain file paths and skill descriptions, never file bodies. They can reveal your directory layout, so review them before sharing.
37
37
  - `check`, `plan`, `scan`, `fix --dry-run` and `mcp` are fully offline; you can run them with networking disabled.
38
38
 
39
39
  ## Risk areas and mitigations
package/SECURITY.zh-CN.md CHANGED
@@ -33,7 +33,7 @@
33
33
  - **默认不联网。** 只有两个例外:`update` 抓取你配置的 catalog URL;每日更新检查只从 npm registry 读取最新版本号(缓存 24h,可用 `"checkUpdates": "off"`、`SKILLS_DOCTOR_UPDATE_CHECK=0` 或 `--no-update-check` 关闭)。
34
34
  - **不读取用户数据。** 只读 skill 文件及其引用资源、agent 配置和自身 lockfile;不读对话历史、会话记录、源代码、文档、模型凭据或 API key,也不上传任何读到的内容。
35
35
  - **配置文件可能含密钥**(`opencode.json(c)`、MCP 配置):只在本地解析以定位需要的条目,值不会被传输、打印或写进报告。
36
- - **报告是本地文件。** HTML/JSON 报告含文件路径和 skill 描述,不含文件正文;可能暴露目录结构,分享前请自行检查。
36
+ - **报告留在本机。** 终端输出、JSON、PR 评论和对话通知含文件路径和 skill 描述,不含文件正文;可能暴露目录结构,分享前请自行检查。
37
37
  - `check`、`plan`、`scan`、`fix --dry-run`、`mcp` 完全离线,可在断网环境运行。
38
38
 
39
39
  ## 风险点与缓解措施
@@ -5,8 +5,8 @@
5
5
  <h1 align="center">skills-doctor</h1>
6
6
 
7
7
  <p align="center">
8
- <b>审计、修复、更新你的 coding agent 加载的 skill。</b><br>
9
- 量出每步 token 税,找出遮蔽重复和断链,再安全地修掉。
8
+ <b>量出 coding agent 每一步为 skill 付出的 token。</b><br>
9
+ 按词估算,丢掉套话重叠,方案只留路由用的第一句,并先藏重复的 skill。
10
10
  </p>
11
11
 
12
12
  <p align="center">
@@ -14,6 +14,7 @@
14
14
  <a href="https://www.npmjs.com/package/opencode-skills-doctor"><img src="https://img.shields.io/npm/dw/opencode-skills-doctor?style=for-the-badge&color=2ea043" alt="downloads"></a>
15
15
  <a href="https://github.com/wangyuchen5110/opencodeplugginprogram/stargazers"><img src="https://img.shields.io/github/stars/wangyuchen5110/opencodeplugginprogram?style=for-the-badge&color=58a6ff" alt="stars"></a>
16
16
  <a href="https://github.com/wangyuchen5110/opencodeplugginprogram/actions/workflows/test.yml"><img src="https://github.com/wangyuchen5110/opencodeplugginprogram/actions/workflows/test.yml/badge.svg" alt="tests"></a>
17
+ <a href="https://github.com/marketplace/actions/skills-doctor"><img src="https://img.shields.io/badge/GitHub%20Marketplace-skills--doctor-3fb950?style=for-the-badge&logo=github" alt="GitHub Marketplace"></a>
17
18
  </p>
18
19
 
19
20
  <p align="center">
@@ -47,10 +48,10 @@ OpenCode skill 的**本地检测器 + 更新器 + 修复器**,并附带 **Open
47
48
  | **形态** | CLI · OpenCode 插件(1.x / 2.x)· MCP server(Claude Code、Codex、DSH…)· 兼容 Grok CLI |
48
49
  | **来源** | `.opencode/skills`、`.claude/skills`、`.agents/skills`、`.grok/skills`、`.cursor/skills`、`.hermes/skills`、`.kimi-code/skills`、`.dsh/skills`(含 `$DSH_HOME`)、`opencode.json(c)` 配置、HTTP catalog |
49
50
  | **能查** | 同 ID 遮蔽、重复、超长描述、超大正文、每步 token 预算、断链引用、非法 frontmatter、空正文、陈旧 skill |
50
- | **能修** | 归档遮蔽定义(可逆)、隐藏低频 skill、catalog 同步并检测 drift |
51
- | **报告** | 终端、JSON,或自包含 HTML(`--html [file] --open`) |
51
+ | **能修** | 归档遮蔽定义(可逆)、先藏重复的 skill、方案只留路由用的第一句 |
52
+ | **报告** | OpenCode 对话里的一条通知,加上终端和 JSON |
52
53
  | **规划** | 精确 token 节省:精简描述 / 隐藏 skill,按 N 步折算 |
53
- | **成本** | CLI 0 token;插件工具定义约 191/步,另有每会话一次预警 |
54
+ | **成本** | CLI 0 token;有问题时每个会话在对话里发一条通知 |
54
55
  | **要求** | Node ≥ 20,零运行时依赖 |
55
56
  | **质量** | 63 个测试,ubuntu/macos/windows × Node 20/22/24 CI |
56
57
 
@@ -64,7 +65,7 @@ OpenCode skill 的**本地检测器 + 更新器 + 修复器**,并附带 **Open
64
65
  | **不会读** | 对话历史、会话记录、源代码、文档、凭据、API key、环境变量里的密钥 |
65
66
  | **不会上传** | 任何东西:没有服务端组件,除下面两个可选联网外没有任何远端地址 |
66
67
  | **联网** | 只在你主动触发时发生:`update` 抓取**你自己配置**的 HTTP catalog;`upgrade` / 每日更新检查只读 npm registry 的最新版本号(缓存 24h,可用 `"checkUpdates": "off"`、`SKILLS_DOCTOR_UPDATE_CHECK=0` 或 `--no-update-check` 关闭) |
67
- | **会写** | 只写你要求的内容:HTML/JSON 报告、`.skills-doctor-archive/`、`.skills-doctor.json`、lockfile,以及 `install` 生成的插件/MCP/skill 条目 |
68
+ | **会写** | 只写你要求的内容:`.skills-doctor-archive/`、`.skills-doctor.json`、lockfile,以及 `install` 生成的插件/MCP/skill 条目 |
68
69
 
69
70
  `opencode.json(c)` 和 MCP 配置里可能有凭据;它们只在本地被解析用来定位相关条目,值不会被发送,也不会出现在报告里。报告只含文件路径和 skill 描述(本来就是你的 skill 文件内容),不包含正文。`check`、`plan`、`scan`、`fix --dry-run`、`mcp` 都可以在断网环境下运行。
70
71
 
@@ -131,20 +132,13 @@ skills-doctor check
131
132
  skills-doctor check --json
132
133
  skills-doctor check --budget 800 --strict # CI 用
133
134
  skills-doctor check --root .\some-project --no-global
134
- skills-doctor check --html report.html # 自包含 HTML 报告
135
- skills-doctor check --html report.html --open
136
135
  ```
137
136
 
138
- ### HTML 报告
137
+ ### 对话通知
139
138
 
140
- `--html [file]` 生成单个自包含 HTML 文件(无外部资源):
139
+ OpenCode 2 在你发出第一条消息时,如果有 error 或 warning,就在对话里发一条通知。它是带描述 `skills-doctor` 的 synthetic 消息,会单独占一行,不会再开一轮模型。`/skills-doctor` 会再发一次,没有问题也会说。工具和 MCP 返回同一段短文,不写文件。最多列三条。归档和隐藏仍然要你确认。
141
140
 
142
- - 摘要卡片 + 上下文预算条;
143
- - 可按严重级别和文本过滤的 findings;
144
- - skill 表格:来源、token 成本、描述预览、文件路径;
145
- - 只写 `--html` 不带路径时默认 `./skills-report.html`;`--open` 自动打开浏览器。
146
-
147
- 插件和 MCP 工具同样接受 `html` 参数,所以可以让 agent 先问你要存哪里——例如:*"把报告存到 D:\reports\skills.html"*。
141
+ OpenCode 1.x 没有这条通知接口,同一段话交给模型,让它在回复里说出来。
148
142
 
149
143
  ### `plan`(到底能省多少 token?)
150
144
 
@@ -161,7 +155,7 @@ skills-doctor plan --json
161
155
  - **方案 B**:用最少的隐藏数量把总量压进预算(仍可 `@id` 加载;按单项节省从大到小取,对「最少隐藏数」是最优的);
162
156
  - **推荐方案**:先精简再隐藏,不重复计算,并按 `--steps`(默认 100)折算总节省。
163
157
 
164
- 超预算时 `check` 会打印一行提示,HTML 报告里有同样的「potential savings」卡片。
158
+ 超预算时 `check` 会打印一行提示。具体方案看 `plan`。
165
159
 
166
160
  ### `scan`
167
161
 
@@ -272,9 +266,8 @@ skills-doctor upgrade --apply # npm install -g opencode-skills-doctor@latest
272
266
 
273
267
  它会注册:
274
268
 
275
- - `skills_doctor` 工具(命名空间 `skills`)—— agent 传 `{ directory?, budget?, html? }` 就能拿到 markdown 审计报告;
269
+ - `skills_doctor` 工具(命名空间 `skills`)—— `{ directory?, budget? }` 返回对话简报,不写文件;
276
270
  - `/skills-doctor` 命令 —— 让 agent 跑一次审计并总结修复建议;
277
- - `/skills-report` —— 先问你要把 HTML 报告存到哪里,再写文件;
278
271
  - `/skills-upgrade` —— 检查 skills-doctor 自身有没有新版本。
279
272
 
280
273
  `@opencode/plugin` 是可选 peer 依赖,运行时由 OpenCode 提供。
@@ -316,7 +309,7 @@ npx opencode-skills-doctor install --client desktop
316
309
  ```
317
310
 
318
311
  - 在标准安装位置探测桌面版,并从 `resources/app.asar` 读出内置 core 版本(例如 1.17.11),据此选择对应插件 API;
319
- - 写入与 CLI 相同的插件条目和 `/skills-doctor`、`/skills-report`、`/skills-upgrade` 命令 —— 装完重启桌面应用;
312
+ - 写入与 CLI 相同的插件条目和 `/skills-doctor`、`/skills-upgrade` 命令 —— 装完重启桌面应用;
320
313
  - `--client auto`(默认)在同时装了 CLI 时优先 CLI 版本;`--client opencode` 跳过桌面探测;
321
314
  - `uninstall --client desktop` 反向撤销。
322
315
 
@@ -331,16 +324,15 @@ npx opencode-skills-doctor install
331
324
  安装器会自动识别 OpenCode 版本并接好:
332
325
 
333
326
  - **2.x** —— 在 `opencode.json(c)` 里加 `"plugins": ["opencode-skills-doctor"]`;
334
- - **1.x** —— 把包装进 `~/.config/opencode`、写本地插件入口、生成 `/skills-doctor`、`/skills-report`、`/skills-upgrade` 三个 markdown 命令、补 `"type": "module"`;
327
+ - **1.x** —— 把包装进 `~/.config/opencode`、写本地插件入口、生成 `/skills-doctor`、`/skills-upgrade` 两个 markdown 命令、补 `"type": "module"`;
335
328
  - 改配置前会备份为 `<config>.bak-<timestamp>`。
336
329
 
337
330
  支持 `--dry-run` 预览、`--config-dir <dir>` 指定配置目录、`--no-npm` 跳过装包。
338
331
 
339
332
  装好后你会得到:
340
333
 
341
- - `skills_doctor` 工具(可选 `html` 参数,把报告写到指定路径);
334
+ - `skills_doctor` 工具,返回对话简报,不写文件;
342
335
  - `/skills-doctor` 命令(1.x 是生成的 markdown 命令,2.x 是插件命令);
343
- - `/skills-report` 命令(2.x)—— 会先问你要把 HTML 报告存到哪里;
344
336
  - `/skills-upgrade` 命令(2.x)—— 检查 skills-doctor 自身是否有新版本;
345
337
  - 当 skill 描述预算超标时,系统提示里会注入一次提醒(每个会话最多一次)。
346
338
 
@@ -395,7 +387,7 @@ npx -y opencode-skills-doctor install --client dsh
395
387
 
396
388
  它会找到 `~/.dsh/profiles/<profile>/cordis.patch.yml`(默认 `desktop`,否则用 `--profile <name>`),把 `mcp-skills-doctor` 这一行放在 `- insert:` 块里幂等写入,并把 `skills-doctor-audit` 技能复制到 `~/.dsh/skills/`。重启 DSH(启用 HMR 时会自动重载 patch)加载 MCP 工具;skill 目录有监听,无需重启。
397
389
 
398
- - 工具名 `mcp__skills_doctor__skills_doctor`,参数 `directory`、`budget`、`lang`、`global`、`html`;
390
+ - 工具名 `mcp__skills_doctor__skills_doctor`,参数 `directory`、`budget`、`lang`、`global`;
399
391
  - `uninstall --client dsh` 同时移除配置条目和 skill;
400
392
  - `--dsh-home <dir>` 用于非默认的 DSH 主目录。
401
393
 
@@ -487,7 +479,7 @@ npx -y opencode-skills-doctor install --client kimi
487
479
  | `shadowed` | warn | 同一 ID 多处定义,只有一份生效,其余白占体积且容易改错 |
488
480
  | `flat-dir-collision` | warn | 同一来源同时存在 `<id>.md` 和 `<id>/SKILL.md` |
489
481
  | `duplicate-content` | warn | 不同 skill 正文完全相同 |
490
- | `near-duplicate-description` | warn | 两个 skill 的 description 相似度 ≥ 75%,模型容易选错 |
482
+ | `near-duplicate-description` | warn | 去掉套话后,特征词重叠 ≥ 72%,或较短的触发词有 ≥ 85% 被另一条包含 |
491
483
  | `missing-description` | info | 没有 description,模型看不到它 |
492
484
  | `long-description` | warn | description > 240 字符(每个模型步骤都占上下文) |
493
485
  | `large-body` | warn | 正文 > 4000 tokens(调用时整段进上下文) |
@@ -560,7 +552,7 @@ npx -y opencode-skills-doctor install --client kimi
560
552
  **度量**
561
553
 
562
554
  - 默认 `budget`(1200 tokens)是建议值,不是硬限制;用 `.skills-doctor.json` 或 `--budget` 调整。
563
- - token 是启发式估算(CJK 约 1.7 字/token,其余约 4 字符/token),用于横向比较,不是精确计费。
555
+ - token 按词估算(短英文词 1 token,每个汉字 1 token,更长的词每多 4 个字符加 1)。用来比较,不是精确计费。
564
556
  - `check` 不联网;要看 catalog 新版本用 `update --check-only`。
565
557
  - 配置优先级假设:全局配置 < 项目配置 < `skills` 数组顺序。
566
558
 
package/docs/REFERENCE.md CHANGED
@@ -13,11 +13,11 @@ Local scanner, linter, fixer, updater and **OpenCode plugin** for agent skills
13
13
  | **Skill sources** | `.opencode/skills`, `.claude/skills`, `.agents/skills`, `.grok/skills`, `.cursor/skills`, `.hermes/skills`, `.kimi-code/skills`, `opencode.json(c)` entries, HTTP catalogs |
14
14
  | **What it finds** | shadowed IDs, duplicates, long descriptions, oversized bodies, per-step token budget, broken file references, invalid frontmatter, empty bodies, stale skills |
15
15
  | **What it fixes** | archives shadowed definitions (reversible), hides low-frequency skills, syncs catalogs with drift detection |
16
- | **Reports** | terminal, JSON, or a self-contained HTML report (`--html [file] --open`) |
16
+ | **Reports** | a chat notice in OpenCode, plus the terminal and JSON |
17
17
  | **Plan** | exact token savings: trim descriptions and/or hide skills, projected over N steps |
18
18
  | **Cost** | CLI: 0 tokens. Plugin: ~191 tokens/step for the tool definition, plus a one-time warning per session |
19
19
  | **Requirements** | Node ≥ 20, zero runtime dependencies |
20
- | **Quality** | 58 tests, CI on ubuntu/macos/windows × Node 20/22/24 |
20
+ | **Quality** | 73 tests, CI on ubuntu/macos/windows × Node 20/22/24 |
21
21
 
22
22
  ## Why
23
23
 
@@ -82,20 +82,13 @@ skills-doctor check
82
82
  skills-doctor check --json
83
83
  skills-doctor check --budget 800 --strict # for CI
84
84
  skills-doctor check --root .\some-project --no-global
85
- skills-doctor check --html report.html # self-contained HTML report
86
- skills-doctor check --html report.html --open
87
85
  ```
88
86
 
89
- ### HTML report
87
+ ### Chat notice
90
88
 
91
- `--html [file]` writes a single self-contained HTML file (no external assets):
89
+ OpenCode 2 posts one notice in the session the first time you send a message, when there is an error or a warning. The notice is a synthetic message with the description `skills-doctor`, so it shows as its own row. It does not start another model turn. `/skills-doctor` posts it again, including when nothing is wrong. The tool and the MCP server return the same short text and do not write a file. At most three findings are listed. Archive and hide still wait for you to confirm.
92
90
 
93
- - summary cards and a context-budget bar;
94
- - findings filterable by severity and text;
95
- - a skill table with scope, token cost, description preview and file path;
96
- - default path `./skills-report.html` when `--html` is given without a value; `--open` launches the browser.
97
-
98
- The plugin and MCP tool accept the same thing as an `html` argument, so the agent can ask you where to save it — for example: *"save the report to D:\reports\skills.html"*.
91
+ On OpenCode 1.x the same text is handed to the model with an instruction to say it in the chat.
99
92
 
100
93
  ### `plan` (how many tokens can I actually save?)
101
94
 
@@ -112,7 +105,7 @@ It answers "how much can I cut, exactly?":
112
105
  - **Option B** hides the fewest skills needed to reach the budget (still loadable with `@id`; picking the largest savings first is optimal for "minimal hides");
113
106
  - **Recommended** trims first, then hides, with no double counting, and projects the saving over `--steps` model steps (default 100).
114
107
 
115
- `check` prints a one-line pointer when you are over budget, and the HTML report shows the same potential-savings card.
108
+ `check` prints a one-line pointer when you are over budget. `plan` is the breakdown.
116
109
 
117
110
  ### `scan`
118
111
 
@@ -223,9 +216,8 @@ The package also exports an OpenCode 2.x plugin:
223
216
 
224
217
  It registers:
225
218
 
226
- - the `skills_doctor` tool (namespace `skills`) — the agent can audit with `{ directory?, budget?, html? }` and gets a markdown report;
227
- - the `/skills-doctor` command — asks the agent to run the audit and summarize fixes;
228
- - `/skills-report` — asks where to save an HTML report, then writes it;
219
+ - the `skills_doctor` tool (namespace `skills`) — `{ directory?, budget? }` returns the short chat briefing and writes nothing;
220
+ - `/skills-doctor` — posts that briefing in the chat;
229
221
  - `/skills-upgrade` — checks whether skills-doctor itself has a newer version.
230
222
 
231
223
  `@opencode/plugin` is an optional peer dependency; OpenCode provides it at runtime.
@@ -267,7 +259,7 @@ npx opencode-skills-doctor install --client desktop
267
259
  ```
268
260
 
269
261
  - detects the app in the standard install locations and reads its bundled core version from `resources/app.asar` (e.g. 1.17.11), then uses the matching plugin API;
270
- - writes the same plugin entry and `/skills-doctor`, `/skills-report`, `/skills-upgrade` commands as the CLI install — restart the desktop app afterwards;
262
+ - writes the same plugin entry and `/skills-doctor` and `/skills-upgrade` commands as the CLI install — restart the desktop app afterwards;
271
263
  - `--client auto` (default) prefers the CLI version when both are installed; `--client opencode` skips desktop detection;
272
264
  - `uninstall --client desktop` reverses it.
273
265
 
@@ -282,18 +274,17 @@ npx opencode-skills-doctor install
282
274
  The installer detects your OpenCode version and wires everything up:
283
275
 
284
276
  - **2.x** — adds `"plugins": ["opencode-skills-doctor"]` to `opencode.json(c)`;
285
- - **1.x** — installs the package into `~/.config/opencode`, writes the local plugin entry, generates `/skills-doctor`, `/skills-report` and `/skills-upgrade` markdown commands, sets `"type": "module"`;
277
+ - **1.x** — installs the package into `~/.config/opencode`, writes the local plugin entry, generates `/skills-doctor` and `/skills-upgrade` markdown commands, sets `"type": "module"`;
286
278
  - backs up the config file as `<config>.bak-<timestamp>` before editing.
287
279
 
288
280
  Use `--dry-run` to preview, `--config-dir <dir>` for a custom config location, and `--no-npm` to skip the package install.
289
281
 
290
282
  Once installed you get:
291
283
 
292
- - the `skills_doctor` tool (with an optional `html` argument to write a report to a path you choose);
293
- - the `/skills-doctor` command (1.x: generated markdown command; 2.x: plugin command);
294
- - the `/skills-report` command (2.x) that asks where to save the HTML report;
295
- - the `/skills-upgrade` command (2.x) that checks for a newer skills-doctor;
296
- - a one-time system-prompt warning when the skill description budget is exceeded.
284
+ - the `skills_doctor` tool, which returns the chat briefing and writes nothing;
285
+ - `/skills-doctor` (1.x: generated markdown command; 2.x: a notice posted in the chat);
286
+ - `/skills-upgrade` (2.x) that checks for a newer skills-doctor;
287
+ - one chat notice per session when a skill has an error or a warning. On 1.x the same text is given to the model to say out loud. `uninstall` deletes a leftover `/skills-report` command from older installs.
297
288
 
298
289
  ### Uninstall
299
290
 
@@ -346,7 +337,7 @@ npx -y opencode-skills-doctor install --client dsh
346
337
 
347
338
  It locates `~/.dsh/profiles/<profile>/cordis.patch.yml` (default `desktop`; otherwise `--profile <name>`), inserts the `mcp-skills-doctor` row under an `- insert:` block idempotently, and copies the `skills-doctor-audit` skill into `~/.dsh/skills/`. Restart DSH (or let HMR reload the patch) to load the MCP tool; the skill is watched and appears without a restart.
348
339
 
349
- - tool name `mcp__skills_doctor__skills_doctor`, arguments `directory`, `budget`, `lang`, `global`, `html`;
340
+ - tool name `mcp__skills_doctor__skills_doctor`, arguments `directory`, `budget`, `lang`, `global`;
350
341
  - `uninstall --client dsh` removes both the patch entry and the skill;
351
342
  - `--dsh-home <dir>` for a non-standard DSH home.
352
343
 
@@ -438,7 +429,7 @@ It merges `skills-doctor` into `~/.kimi-code/mcp.json` (or `$KIMI_CODE_HOME/mcp.
438
429
  | `shadowed` | warn | Same ID defined in multiple sources; only one wins, the rest is dead weight and easy to edit by mistake |
439
430
  | `flat-dir-collision` | warn | Both `<id>.md` and `<id>/SKILL.md` exist in the same source |
440
431
  | `duplicate-content` | warn | Two skills share identical body text |
441
- | `near-duplicate-description` | warn | Descriptions are ≥ 75% similar; the model may pick the wrong one |
432
+ | `near-duplicate-description` | warn | Distinctive words overlap by ≥ 72%, or a shorter trigger is ≥ 85% contained in a longer one. Shared boilerplate ("use this skill when…") is ignored |
442
433
  | `missing-description` | info | No description, so the model never discovers it |
443
434
  | `long-description` | warn | Description > 240 chars (paid on every model step) |
444
435
  | `large-body` | warn | Body > 4000 tokens (pasted into context when invoked) |
@@ -517,7 +508,7 @@ See [SECURITY.md](../SECURITY.md) for the full threat model, hardening checklist
517
508
  **Measurement**
518
509
 
519
510
  - The default `budget` (1200 tokens) is a recommendation, not a hard limit. Tune it with `.skills-doctor.json` or `--budget`.
520
- - Token counts are heuristic (CJK ≈ 1.7 chars/token, the rest ≈ 4 chars/token) — good for comparisons, not for billing.
511
+ - Token counts are a word-piece estimate (a short English word is 1 token, each CJK character is 1, longer words add 1 per 4 extra characters). Good for comparisons, not for billing.
521
512
  - `check` is offline; ask a catalog for new versions with `update --check-only`.
522
513
  - Config precedence is assumed: global config < project config < `skills` array order.
523
514
 
@@ -552,7 +543,7 @@ Executing code is free, but the tool definition is part of the model's context.
552
543
  ## Development and contributing
553
544
 
554
545
  ```powershell
555
- npm test # 58 tests (node test/doctor.test.mjs)
546
+ npm test # 73 tests (node test/doctor.test.mjs)
556
547
  npm run bench # lint timing for 100/500/1000 skills
557
548
  ```
558
549
 
@@ -41,7 +41,7 @@
41
41
  <text x="22" y="96" fill="#3fb950">✓ 29 skills · ~3,074 tokens/step</text>
42
42
  <text x="22" y="128" fill="#d29922">! over budget ×2</text>
43
43
  <text x="22" y="160" fill="#58a6ff">plan → save ~1,940 tokens/step</text>
44
- <text x="22" y="192" fill="#8b9bb4">HTML report ready →</text>
44
+ <text x="22" y="192" fill="#8b9bb4">told you in the chat →</text>
45
45
  </g>
46
46
  </g>
47
47
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "opencode-skills-doctor",
3
- "version": "0.9.4",
4
- "description": "Audit, fix and update agent skills: token cost, broken references, shadowed duplicates, HTML reports, catalog sync. CLI, OpenCode plugin, MCP server; works with OpenCode, Claude Code, Codex, Grok CLI, Cursor, Hermes Agent, Kimi Code and DeepSeek Harness.",
3
+ "version": "0.9.7",
4
+ "description": "Audit, fix and update agent skills: token cost, broken references, shadowed duplicates, catalog sync. Tells you in the chat. CLI, OpenCode plugin, MCP server; works with OpenCode, Claude Code, Codex, Grok CLI, Cursor, Hermes Agent, Kimi Code and DeepSeek Harness.",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./src/plugin.mjs",
@@ -21,9 +21,9 @@ npx -y opencode-skills-doctor check --json
21
21
  Read `summary.advertisedTokens` (cost per model step), `summary.advertised` and `findings[]`.
22
22
  If the command fails, fall back to `opencode-skills-doctor` when installed globally, or ask the user to run it from the repo.
23
23
 
24
- ## 2. Explain the top findings
24
+ ## 2. Tell the user in this chat
25
25
 
26
- Report at most three findings, in plain language, each with its token impact:
26
+ Say at most three findings, in plain language. Do not write a report file.
27
27
 
28
28
  - `token-budget` — descriptions cost roughly N tokens on **every** model step;
29
29
  - `shadowed` — the same skill ID loads from several places, only one wins;
@@ -47,8 +47,3 @@ Report `recommended.savings` (per step), `recommended.final` and `recommended.st
47
47
  - Trim descriptions manually, keeping them discoverable
48
48
  - Ask first, then re-run `check` to confirm the new cost
49
49
 
50
- ## 5. Optional shareable report
51
-
52
- ```powershell
53
- npx -y opencode-skills-doctor check --html skills-report.html --open
54
- ```
package/src/audit.mjs CHANGED
@@ -67,6 +67,35 @@ export function auditSkills({
67
67
  }
68
68
  }
69
69
 
70
+ /**
71
+ * 给对话用的短结论。agent 应原样告诉用户,不要再写成文件。
72
+ */
73
+ export function formatChat(audit, { limit = 3 } = {}) {
74
+ const zh = audit.lang === "zh"
75
+ const problems = audit.findings.filter((finding) => finding.severity === "error" || finding.severity === "warn")
76
+ if (!problems.length) {
77
+ return zh
78
+ ? `skills-doctor:技能没有需要处理的问题。${audit.summary.advertised} 个会在每一步注入,大约 ${audit.summary.advertisedTokens} token。`
79
+ : `skills-doctor: no skill problems to act on. ${audit.summary.advertised} skills are injected on every step, about ${audit.summary.advertisedTokens} tokens.`
80
+ }
81
+ const lines = [
82
+ zh ? "skills-doctor:" : "skills-doctor:",
83
+ zh
84
+ ? `技能有 ${problems.length} 个问题:`
85
+ : `${problems.length} skill problem${problems.length === 1 ? "" : "s"}:`,
86
+ ]
87
+ for (const finding of problems.slice(0, limit)) lines.push(`- ${finding.message}`)
88
+ if (problems.length > limit) {
89
+ lines.push(zh ? `- 还有 ${problems.length - limit} 条,需要的话我再展开。` : `- ${problems.length - limit} more. Ask if you want them.`)
90
+ }
91
+ lines.push(
92
+ zh
93
+ ? "我不会改文件。你确认之后,我可以归档被盖住的副本,或把不常用的藏起来。"
94
+ : "I will not change any files. After you confirm, I can archive shadowed copies or hide skills you rarely use.",
95
+ )
96
+ return lines.join("\n")
97
+ }
98
+
70
99
  /** 把审计结果渲染成适合给 agent / PR 评论用的 markdown。 */
71
100
  export function formatMarkdown(audit, { limit = 25 } = {}) {
72
101
  const lines = []
package/src/cli.mjs CHANGED
@@ -11,7 +11,7 @@ import { startMcpServer } from "./mcp.mjs"
11
11
  import { installOpenCode, uninstallOpenCode } from "./install.mjs"
12
12
  import { installDsh, uninstallDsh } from "./dsh.mjs"
13
13
  import { installKimi, uninstallKimi } from "./kimi.mjs"
14
- import { writeHtmlReport, openReport } from "./html.mjs"
14
+
15
15
  import { planBudget } from "./plan.mjs"
16
16
  import {
17
17
  checkForUpdate,
@@ -80,7 +80,7 @@ function parseArgs(argv) {
80
80
  extraDirs: [],
81
81
  configDir: null,
82
82
  noNpm: false,
83
- html: null,
83
+
84
84
  open: false,
85
85
  apply: false,
86
86
  updateCheck: true,
@@ -174,19 +174,6 @@ function parseArgs(argv) {
174
174
  case "--no-npm":
175
175
  options.noNpm = true
176
176
  break
177
- case "--html": {
178
- const next = args[i + 1]
179
- if (next && !next.startsWith("-")) {
180
- options.html = path.resolve(next)
181
- i++
182
- } else {
183
- options.html = path.resolve("skills-report.html")
184
- }
185
- break
186
- }
187
- case "--open":
188
- options.open = true
189
- break
190
177
  case "--apply":
191
178
  options.apply = true
192
179
  break
@@ -838,23 +825,16 @@ export async function main(argv) {
838
825
  })
839
826
  const result = buildCheckResult(audit, options)
840
827
 
841
- let htmlPath = null
842
- if (options.html) {
843
- htmlPath = writeHtmlReport(audit, options.html)
844
- if (options.open) openReport(htmlPath)
845
- }
846
-
847
828
  if (options.json) {
848
829
  console.log(
849
830
  JSON.stringify(
850
- { ...result, html: htmlPath, skills: serializeSkills(audit.skills, audit.managed) },
831
+ { ...result, skills: serializeSkills(audit.skills, audit.managed) },
851
832
  null,
852
833
  2,
853
834
  ),
854
835
  )
855
836
  } else {
856
837
  printCheck(audit, result, options, t)
857
- if (htmlPath) console.log(dim(t("check.htmlSaved", { path: htmlPath })))
858
838
  await maybeNotifyUpdate({ options, config: loaded.config, t })
859
839
  }
860
840
  process.exitCode = result.exitCode
package/src/discover.mjs CHANGED
@@ -341,6 +341,7 @@ function buildSkill({ id, file, source, form }) {
341
341
  const description = typeof data.description === "string" ? data.description.trim() : ""
342
342
  const displayName = typeof data.name === "string" && data.name.trim() ? data.name.trim() : id
343
343
  const hidden = autoinvoke === false || disabled === true
344
+ const stepTokens = estimateTokens(`${id} ${displayName} ${description}`)
344
345
  let mtime = 0
345
346
  try {
346
347
  mtime = fs.statSync(file).mtimeMs
@@ -366,6 +367,7 @@ function buildSkill({ id, file, source, form }) {
366
367
  bodyTokens: estimateTokens(body),
367
368
  bytes,
368
369
  descriptionTokens: estimateTokens(description),
370
+ stepTokens,
369
371
  hash: sha1(body.replace(/\s+/g, " ").trim()),
370
372
  mtime,
371
373
  }