skill-guide 0.3.1 → 0.4.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ All notable changes to skill-guide will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.0] - 2026-06-01
9
+
10
+ ### Added
11
+ - Platform-scoped filtering: all modes (dashboard, doctor, find, review, recommend, share) default to the current agent's skills.
12
+ - Auto-detection via env vars (`CLAUDE_CODE`, `CODEX_AGENT`) or install path.
13
+ - `--platform <claude|codex>` flag to force a specific platform view.
14
+ - `--all` flag to see the full cross-platform inventory.
15
+ - `applyPlatformFilter()` helper for consistent platform filtering across all CLI modes.
16
+ - 8 new tests covering platform detection, filtering, and env var auto-detection.
17
+
18
+ ### Changed
19
+ - Review mode (`--review`) no longer flags cross-agent duplicates as issues — each agent needs its own skill copies.
20
+ - Cover slide title auto-adapts to show "Your Claude Code Skills" or "Your Codex Skills" based on filtered results.
21
+ - `--find` commands in Next Steps slide simplified (removed redundant `--find` flag).
22
+
23
+ ### Fixed
24
+ - `\n` literal rendering in Copy Review Prompt button (replaced inline string with window variable pattern).
25
+ - `--platform` value no longer misinterpreted as a positional `--find` argument.
26
+
8
27
  ## [0.3.1] - 2026-06-01
9
28
 
10
29
  ### Added
package/README.md CHANGED
@@ -1,322 +1,230 @@
1
- <p align="center">
2
- <img src="https://img.shields.io/badge/Zero%20Dependencies-Node.js-6ee7b7?style=flat-square" />
3
- <img src="https://img.shields.io/badge/Output-HTML%20Slides-f0abfc?style=flat-square" />
4
- <img src="https://img.shields.io/badge/Platform-Claude%20Code%20%7C%20Codex%20%7C%20cc--switch-818cf8?style=flat-square" />
5
- <img src="https://img.shields.io/github/actions/workflow/status/gtskevin/skill-guide/test.yml?branch=main&style=flat-square&label=tests" />
6
- <img src="https://img.shields.io/badge/License-MIT-green?style=flat-square" />
7
- <img src="https://img.shields.io/badge/Language-English%20%7C%20Chinese-7dd3fc?style=flat-square" />
8
- <img src="https://img.shields.io/badge/Feature-Health%20Dashboard-fbbf24?style=flat-square" />
9
- </p>
10
-
11
- <p align="center">
12
- <img src="demo.gif" alt="skill-guide demo — npx skill-guide --open generates HTML slides" width="760" />
13
- </p>
14
-
15
- > **Installed so many agent skills that you cannot remember what you have?**
16
- > One command scans everything Claude Code, Codex, cc-switch, plugins — and generates a beautiful dashboard so you actually know what you have.
1
+ <div align="center">
2
+
3
+ <picture>
4
+ <img src=".github/assets/banner.svg" alt="skill-guide — know what your AI agent can do before you trust it" width="800" />
5
+ </picture>
6
+
7
+ <br />
8
+
9
+ [![npm version](https://img.shields.io/npm/v/skill-guide?style=for-the-badge&logo=npm)](https://www.npmjs.com/package/skill-guide)
10
+ [![npm downloads](https://img.shields.io/npm/dm/skill-guide?style=for-the-badge&logo=npm)](https://www.npmjs.com/package/skill-guide)
11
+ [![tests](https://img.shields.io/github/actions/workflow/status/gtskevin/skill-guide/test.yml?branch=main&style=for-the-badge&label=tests)](https://github.com/gtskevin/skill-guide/actions/workflows/test.yml)
12
+ [![license](https://img.shields.io/badge/license-MIT-22c55e?style=for-the-badge)](LICENSE)
13
+
14
+ **Inspect, find, and review your installed Agent Skills across Codex and Claude Code.**
15
+
16
+ [Live Demo](https://gtskevin.github.io/skill-guide/) · [Quick Start](#quick-start) · [npm](https://www.npmjs.com/package/skill-guide) · [FAQ](#faq)
17
+
18
+ </div>
19
+
20
+ ---
21
+
22
+ > [!NOTE]
23
+ > You installed a useful Skill from someone else. But what will it actually do? When should it activate? Do you already have another Skill for the same job? Is its description heavy enough to deserve a closer look?
17
24
  >
18
- > Shows your local skill profile, radar chart, token budget estimate, and review candidates all in one click.
19
-
20
- <p align="center">
21
- <a href="https://gtskevin.github.io/skill-guide/"><strong>Live Demo</strong></a>
22
- ·
23
- <a href="#quick-start">Try it now</a>
24
- ·
25
- <a href="#install-methods">Install</a>
26
- ·
27
- <a href="#how-it-works">How it works</a>
28
- </p>
25
+ > `skill-guide` gives you a local map before you place uncertain trust in downloaded Agent Skills.
29
26
 
30
- ```bash
31
- npx skill-guide # ← that's it. Dashboard opens in your browser.
32
- ```
27
+ ## Highlights
33
28
 
34
- ## What it does
29
+ | | Capability | Why it matters |
30
+ |---|---|---|
31
+ | 🔍 | **Inventory your Skills** | See what is installed across Codex, Claude Code, cc-switch, and plugin directories. |
32
+ | 🎯 | **Find a Skill for a task** | Search names, descriptions, and declared triggers before installing another tool. |
33
+ | 📖 | **Inspect how a Skill is designed to work** | Review its source, declared tools, use cases, limitations, and document structure. |
34
+ | 🛡️ | **Review before you trust** | Surface local metadata signals such as sparse descriptions, duplicate sources, and estimated description tokens. |
35
+ | 🎯 | **Platform-scoped views** | Default to your current agent's Skills; use `--platform` or `--all` to switch scope. |
35
36
 
36
- skill-guide reads every skill from Claude Code, Codex, `~/.cc-switch/skills/`, and plugin marketplaces, then generates a polished dashboard you can view in any browser.
37
+ ## Quick Start
37
38
 
38
- **Platform-aware:** Automatically detects whether you're running inside Codex or Claude Code and shows only the relevant skills. Token budget is calculated per-platform, not across all platforms.
39
+ > ⏱️ **Get started in 30 seconds**
39
40
 
40
- **3 modes:**
41
+ No installation is required for the CLI:
41
42
 
42
- | Mode | Command | What it does |
43
- |------|---------|-------------|
44
- | **Dashboard** | `npx skill-guide` | Personality, radar, token budget, cleanup guide, highlights |
45
- | **Find** | `npx skill-guide --find <name\|query>` | Search by keyword or deep dive into a specific skill |
46
- | **Doctor** | `npx skill-guide --doctor` | Environment diagnostics (broken files, duplicates, paths) |
43
+ ```bash
44
+ npx skill-guide
45
+ ```
47
46
 
48
- **Flags:**
49
- - `--all` — Show skills from all platforms (default: current platform only)
50
- - `--full` — Expand dashboard to include all skill details
51
- - `--recommend` — Show recommendations from online directories
52
- - `--share` — Generate shareable portfolio page
53
- - `--no-open` — Do not open HTML in browser
47
+ The dashboard opens in your browser. The terminal also prints a local summary:
54
48
 
55
- ## Platform Support
49
+ ```text
50
+ skill-guide · 338 skills · Local profile: Collector
56
51
 
57
- | Platform | Status | Scanned paths |
58
- |----------|--------|---------------|
59
- | **Claude Code** | Supported | `~/.claude/skills`, `~/.claude/plugins/marketplaces` |
60
- | **Codex** | Supported | `~/.codex/skills`, `$CODEX_HOME/skills`, Codex plugin cache |
61
- | **OpenAI system skills** | Supported | `$CODEX_HOME/skills/.system` as a separate source |
62
- | **cc-switch** | Supported | `~/.cc-switch/skills` |
63
- | **Agent Skills** | Compatible | Standard `SKILL.md` skill folders |
52
+ Health: 68/100
53
+ 338 skills · 9/9 categories · ~20.0K description tokens
54
+ Sources: 59 user-directory · 280 plugin-directory
55
+ 16 skills have sparse metadata review descriptions and triggers
56
+ ```
57
+
58
+ > [!IMPORTANT]
59
+ > Token numbers are rough estimates for Skill descriptions, not measured runtime cost. Health output is a local review prompt, not a verdict on quality or safety.
64
60
 
65
- ## Screenshots
61
+ ## Demo
66
62
 
67
- ![skill-guide social preview](social-preview.png)
63
+ <div align="center">
64
+ <img src="demo.gif" alt="skill-guide scans installed Agent Skills and opens an HTML dashboard" width="760" />
65
+ </div>
68
66
 
69
67
  <table>
70
68
  <tr>
71
- <td><img src="demo-cover.png" alt="Cover slide" width="400" /></td>
72
- <td><img src="demo-categories.png" alt="Category map" width="400" /></td>
69
+ <td><img src="demo-cover.png" alt="skill-guide cover slide with local Skill sources" width="400" /></td>
70
+ <td><img src="demo-categories.png" alt="skill-guide category map grouped by Skill type" width="400" /></td>
73
71
  </tr>
74
72
  <tr>
75
- <td align="center"><em>Cover total count & sources</em></td>
76
- <td align="center"><em>Category map — grouped cards</em></td>
73
+ <td align="center"><em>Local inventory and sources</em></td>
74
+ <td align="center"><em>Category map</em></td>
77
75
  </tr>
78
76
  <tr>
79
- <td><img src="demo-highlights.png" alt="Top picks" width="400" /></td>
80
- <td><img src="demo-reference.png" alt="Quick reference" width="400" /></td>
77
+ <td><img src="demo-highlights.png" alt="skill-guide review highlights for installed Skills" width="400" /></td>
78
+ <td><img src="demo-reference.png" alt="skill-guide searchable reference table" width="400" /></td>
81
79
  </tr>
82
80
  <tr>
83
- <td align="center"><em>Top picks — best skills</em></td>
84
- <td align="center"><em>Quick reference table</em></td>
81
+ <td align="center"><em>Review highlights</em></td>
82
+ <td align="center"><em>Quick reference</em></td>
85
83
  </tr>
86
84
  </table>
87
85
 
88
- ### Health Dashboard Preview
86
+ ## What It Can Tell You
89
87
 
90
- ```bash
91
- npx skill-guide
92
- ```
88
+ `skill-guide` is a local inventory, discovery, and **pre-use review** tool. It deliberately separates evidence from inference.
93
89
 
94
- **Terminal output:**
95
- ```
96
- 🟡 Health Score: 68/100
97
- 🏛️ Local profile: Collector (The Collector)
98
- The local scan found a large skill inventory. Review descriptions, sources, and actual needs periodically.
99
-
100
- 📦 Total Skills: 338
101
- 🔤 Description Token Estimate: ~20.0K (9.98% of a 200K reference context)
102
- 📍 Local profile: based only on the current scan
103
-
104
- 🛡️ Security Review [medium]
105
- Review skills with security flags manually
106
- 📦 Budget Overage [high]
107
- Review longer descriptions when the local reference budget is exceeded
108
-
109
- Token Efficiency ████████░░ 80/100
110
- Organization ██████████ 100/100
111
- Security ████░░░░░░ 40/100
112
- Freshness ██████████ 100/100
113
- Budget Control ██░░░░░░░░ 21/100
114
- ```
90
+ | Question | What `skill-guide` does today | Boundary |
91
+ |---|---|---|
92
+ | What Skills do I have? | Scans local user, system, cc-switch, and plugin directories. Defaults to the current agent's Skills. | Reports what is visible on the current machine. Use `--all` for cross-platform inventory. |
93
+ | Do I already have a Skill for this task? | Searches names, descriptions, and declared triggers with `--find`. | Returns metadata matches, not a semantic guarantee. |
94
+ | How is this Skill designed to work? | Shows source, declared tools, use cases, limitations, and document sections. | Explains documented intent; it does not execute an audit of every command. |
95
+ | Could Skill descriptions be heavy? | Estimates description tokens and highlights longer descriptions. | Does not measure runtime tokens, API cost, or context injection behavior. |
96
+ | Was a Skill actually invoked? | Not yet. | Runtime invocation tracking requires logging integrations. |
97
+ | Is the output good or cost-effective? | Not yet. | Result quality and actual cost require runtime evidence and evaluation. |
115
98
 
116
- Health scores are local heuristics for review. They do not measure community rank, actual usage frequency, or whether deleting a skill is safe.
99
+ ## Commands
117
100
 
118
- ## Quick Start
101
+ | Goal | Command |
102
+ |---|---|
103
+ | Open your local dashboard | `npx skill-guide` |
104
+ | Find a Skill for a task | `npx skill-guide --find security` |
105
+ | Inspect one Skill | `npx skill-guide --find test-driven-development` |
106
+ | Diagnose local setup | `npx skill-guide --doctor` |
107
+ | Review directory mentions and same-category candidates | `npx skill-guide --recommend` |
108
+ | Generate a shareable local profile | `npx skill-guide --share` |
109
+ | Return structured scanner data | `npx skill-guide --format json` |
110
+ | Focus on one agent's Skills | `npx skill-guide --platform claude` |
111
+ | Include every detected platform | `npx skill-guide --all` |
119
112
 
120
- **1. Try instantly** — no install needed:
121
- ```bash
122
- npx skill-guide --open
123
- ```
113
+ ### Example Prompts
124
114
 
125
- **2. Install for Claude Code:**
126
- ```bash
127
- npx skills add gtskevin/skill-guide
128
- ```
115
+ When `skill-guide` is installed as an Agent Skill, try:
129
116
 
130
- **3. Use it** — type `/skill-guide` in Claude Code, or use the CLI:
131
- ```bash
132
- npx skill-guide # See your dashboard
133
- npx skill-guide --find security # Find skills for a task
134
- npx skill-guide --find tdd # Deep-dive one skill
135
- npx skill-guide --full --open # Generate a full manual
136
- npx skill-guide --doctor # Diagnose your setup
117
+ ```text
118
+ What Skills do I already have for code review?
119
+ Show me how the test-driven-development Skill is designed to work.
120
+ 帮我看看我有哪些 Codex Skills,并找出描述信息较少、值得人工复核的项目。
137
121
  ```
138
122
 
139
- ## Install Methods
123
+ ## Install as an Agent Skill
124
+
125
+ For Claude Code:
140
126
 
141
127
  ```bash
142
- # Claude Code: npx skills (recommended)
143
128
  npx skills add gtskevin/skill-guide
129
+ ```
144
130
 
145
- # Claude Code: manual symlink
146
- git clone https://github.com/gtskevin/skill-guide.git
147
- ln -s $(pwd)/skill-guide ~/.claude/skills/skill-guide
131
+ For Codex:
148
132
 
149
- # Claude Code: direct download
150
- mkdir -p ~/.claude/skills/skill-guide
151
- curl -sL https://github.com/gtskevin/skill-guide/archive/refs/heads/main.tar.gz | tar xz --strip-components=1 -C ~/.claude/skills/skill-guide
152
-
153
- # Codex: manual symlink
133
+ ```bash
154
134
  git clone https://github.com/gtskevin/skill-guide.git
155
135
  mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills"
156
136
  ln -s "$(pwd)/skill-guide" "${CODEX_HOME:-$HOME/.codex}/skills/skill-guide"
157
137
  ```
158
138
 
159
- ## Usage Examples
160
-
161
- ### Run as a CLI
162
- ```bash
163
- npx skill-guide --open
164
- npx skill-guide --search security --open
165
- npx skill-guide --skill test-driven-development --open
166
- npx skill-guide --share --open # Share your skill stack
167
- npx skill-guide --recommend --open # Review directory mentions and same-category candidates
168
- npx skill-guide # Health dashboard with personality & radar chart
169
- npx skill-guide --wrapped --open # Compatibility alias for the local profile
170
- npx skill-guide --format json
171
- npx skill-guide --doctor
172
- ```
173
-
174
- ### Discover all your skills
175
- ```
176
- /skill-guide
177
- ```
178
- Or say: "What skills do I have?" / "帮我看看我有哪些技能"
179
-
180
- In Codex, you can also say: "What Codex skills do I have?"
181
-
182
- ### Deep-dive one skill
183
- ```
184
- /skill-guide investigate
185
- ```
186
- Or say: "Tell me about the TDD skill" / "介绍一下 investigate 技能"
187
-
188
- ### Find the right skill
189
- ```
190
- Which skill should I use for code review?
191
- ```
192
- Or: "帮我推荐一个做测试的技能"
193
-
194
- ### Generate a full manual
195
- ```
196
- /skill-guide all
197
- ```
198
-
199
- ### Share your skill stack
200
- ```bash
201
- npx skill-guide --share --open # Generate portfolio page
202
- npx skill-guide --share --user @gtskevin --open # With personalized tag
203
- ```
139
+ <details>
140
+ <summary>More installation options</summary>
204
141
 
205
- ### Get recommendations
206
142
  ```bash
207
- npx skill-guide --recommend --open # HTML report
208
- npx skill-guide --recommend # Terminal output
209
- npx skill-guide --recommend --format json # JSON for agents
210
- ```
143
+ # Claude Code: manual symlink
144
+ git clone https://github.com/gtskevin/skill-guide.git
145
+ ln -s "$(pwd)/skill-guide" ~/.claude/skills/skill-guide
211
146
 
212
- ### Health check your skills
213
- ```bash
214
- npx skill-guide # Full HTML dashboard
215
- npx skill-guide --health # Terminal output
216
- npx skill-guide --health --lang zh --open # Chinese UI
147
+ # Claude Code: direct download
148
+ mkdir -p ~/.claude/skills/skill-guide
149
+ curl -sL https://github.com/gtskevin/skill-guide/archive/refs/heads/main.tar.gz \
150
+ | tar xz --strip-components=1 -C ~/.claude/skills/skill-guide
217
151
  ```
218
152
 
219
- **What you get:**
220
- - **Health Score** — 0-100 rating of your skill library's health
221
- - **Personality Analysis** — Are you a Collector, Minimalist, Security Expert, or Specialist?
222
- - **Five-Dimension Radar Chart** — Token Efficiency, Organization, Security, Freshness, Budget Control
223
- - **Review Prompts** — Local candidates based on scanned skill metadata
224
- - **Token Estimate** — Approximate description cost before a conversation starts
225
- - **One-Click Share** — Copy report to clipboard for sharing
153
+ </details>
226
154
 
227
- ### Personal Skill Report (--wrapped)
155
+ ## Platform Support
228
156
 
229
- Your local profile for AI skills:
230
- - Skill personality type (Collector, Minimalist, Security Expert, etc.)
231
- - Skill DNA breakdown (category distribution)
232
- - Readiness breakdown based on local metadata
233
- - Shareable HTML report with one-click copy
157
+ | Platform | Status | Scanned paths |
158
+ |---|---|---|
159
+ | Claude Code | Supported | `~/.claude/skills`, `~/.claude/plugins/marketplaces` |
160
+ | Codex | Supported | `~/.codex/skills`, `$CODEX_HOME/skills`, Codex plugin cache |
161
+ | OpenAI system Skills | Supported | `$CODEX_HOME/skills/.system` |
162
+ | cc-switch | Supported | `~/.cc-switch/skills` |
163
+ | Agent Skills | Compatible | Standard `SKILL.md` folders |
234
164
 
235
- ## How it works
165
+ ## How It Works
236
166
 
237
- ```
238
- skill-guide/
239
- ├── SKILL.md # Natural-language CLI entrypoint
240
- ├── agents/openai.yaml # Codex/OpenAI skill UI metadata
241
- ├── skill-guide.js # Deterministic CLI + HTML generator
242
- ├── scan-skills.js # Zero-dependency Node.js scanner
243
- ├── skill-registry.js # Online directory fetching + recommendation engine
244
- ├── demo.html # Demo presentation (this is what you see above)
245
- └── LICENSE # MIT
167
+ ```mermaid
168
+ flowchart LR
169
+ A["Local Skill directories"] --> B["scan-skills.js"]
170
+ B --> C["Parse metadata and document sections"]
171
+ C --> D["skill-guide.js"]
172
+ D --> E["Browser-ready HTML dashboard"]
173
+ C --> F["Search, doctor, and review prompts"]
246
174
  ```
247
175
 
248
- 1. `scan-skills.js` scans Claude Code, Codex, cc-switch, and plugin skill directories; parses YAML frontmatter; extracts sections and key paragraphs
249
- 2. `skill-guide.js` turns scanner JSON into deterministic HTML slides with scroll-snap navigation, keyboard controls, and animations
250
- 3. `SKILL.md` lets Claude Code and Codex invoke the same CLI from natural language
251
- 4. Output opens in your browser — zero config, zero dependencies
176
+ The scanner uses Node.js built-ins only:
252
177
 
253
- ### Scanner modes
178
+ 1. Scan local Skill directories and plugin caches.
179
+ 2. Parse frontmatter, descriptions, triggers, declared tools, and selected document sections.
180
+ 3. Estimate description tokens and surface deterministic local review prompts.
181
+ 4. Render a standalone HTML dashboard that opens in your browser.
254
182
 
255
- | Flag | Purpose | Data |
256
- |------|---------|------|
257
- | `--list` | Discovery | Name + description + category |
258
- | `--skill <name>` | Deep-dive | Full metadata + sections + key paragraphs |
259
- | `--search <query>` | Recommendations | Matching skills with full data |
260
- | `--full` | Complete manual | All skills with full data |
261
- | `--refresh` | Force re-scan | Ignores 5-min cache |
183
+ > [!WARNING]
184
+ > `skill-guide` does not silently delete, install, or modify your Skills. Review prompts require human judgment.
262
185
 
263
- ### CLI flags
186
+ ## FAQ
264
187
 
265
- | Flag | Purpose |
266
- |------|---------|
267
- | `--open` | Open the generated HTML in your browser |
268
- | `--output <file>` | Save HTML to a specific path |
269
- | `--format html,json` | Choose HTML slides or raw scanner JSON |
270
- | `--search <query>` | Generate recommendations for a task |
271
- | `--skill <name>` | Generate a deep-dive for one skill |
272
- | `--full` | Generate a complete manual |
273
- | `--share` | Generate a shareable portfolio HTML |
274
- | `--user <name>` | Add personalized tag to share page |
275
- | `--recommend` | Show directory mentions and same-category review candidates |
276
- | `--health` | Generate health dashboard with local profile, radar chart, and review prompts |
277
- | `--lang <code>` | UI language (`en` or built-in `zh`) |
278
- | `--doctor` | Check paths, sources, and scan counts |
188
+ <details>
189
+ <summary>Does skill-guide send my local Skills to a server?</summary>
279
190
 
280
- ### Doctor checks
191
+ No. Core scanning and dashboard generation run locally with Node.js built-ins. The optional `--recommend` command reads public online directories to show directory mentions.
192
+ </details>
281
193
 
282
- `npx skill-guide --doctor` reports Node.js version, Claude Code and Codex skill paths, source counts, duplicate skill names, malformed skill files, and suggested install paths.
194
+ <details>
195
+ <summary>Can it tell whether Claude Code or Codex actually invoked a Skill?</summary>
283
196
 
284
- ### Auto-categorization
197
+ Not yet. The current release scans local metadata. Reliable invocation tracking requires runtime logs or platform integrations.
198
+ </details>
285
199
 
286
- Skills are automatically sorted into 9 categories: `testing`, `design`, `security`, `documentation`, `automation`, `deployment`, `code-quality`, `development`, `other`.
200
+ <details>
201
+ <summary>Does the token estimate equal my real API cost?</summary>
287
202
 
288
- ## Language Support
203
+ No. It is a rough estimate based on description text. Runtime token usage depends on the platform, model, loaded context, and execution path.
204
+ </details>
289
205
 
290
- Dashboard labels are available in English and Chinese. Agents can summarize results in the user's language without modifying the generated HTML.
206
+ <details>
207
+ <summary>Does a health warning mean I should delete a Skill?</summary>
291
208
 
292
- - **English** default
293
- - **Chinese** — built-in (`--lang zh`)
294
- - **Other languages** — agent summary in the user's language; dashboard labels remain English
209
+ No. Warnings are review candidates. Read the Skill, check its source, and confirm your actual needs before changing anything.
210
+ </details>
295
211
 
296
- ## Why skill-guide?
212
+ <details>
213
+ <summary>Which languages are supported?</summary>
297
214
 
298
- - **Cross-platform inventory** scans Claude Code, Codex, cc-switch, and plugin sources in one visual overview
299
- - **Health dashboard** — local profile, radar chart, and review prompts for your skill library
300
- - **Zero dependencies** — pure Node.js with `fs`, `path`, `os`. No `npm install` needed
301
- - **Beautiful output** — scroll-snap slides with keyboard nav, animations, and responsive design
302
- - **Bilingual dashboard** — English by default, with built-in Chinese labels via `--lang zh`
303
- - **Smart caching** — 5-minute TTL so repeated queries are instant
304
- - **5 seconds to "wow"** — `npx skill-guide --open` is all you need
215
+ Dashboard labels are built in for English and Chinese. Agents can summarize the result in other languages without rewriting the generated HTML.
216
+ </details>
305
217
 
306
218
  ## Contributing
307
219
 
308
- See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
309
-
310
- ## Roadmap
220
+ Issues and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for the zero-dependency constraint and test commands.
311
221
 
312
- - [x] `--share` — generate a shareable standalone HTML or Markdown summary
313
- - [x] `--health` — health dashboard with local profile, radar chart, and review prompts
314
- - [ ] Gemini CLI skill scanning (`~/.gemini/skills`)
315
- - [ ] `--diff` — show recently added/removed skills since last scan
316
- - [ ] `--export markdown` — output a Markdown table for pasting into issues and docs
222
+ ## License
317
223
 
318
- Have an idea? [Open a feature request](https://github.com/gtskevin/skill-guide/issues/new?template=feature_request.yml).
224
+ [MIT](LICENSE)
319
225
 
320
- ## License
226
+ ---
321
227
 
322
- MIT
228
+ <div align="center">
229
+ <sub>Built with care by <a href="https://github.com/gtskevin">@gtskevin</a> for developers who want to understand Agent Skills before trusting them.</sub>
230
+ </div>
package/SKILL.md CHANGED
@@ -29,12 +29,15 @@ Use the bundled zero-dependency CLI to scan local skill metadata and generate a
29
29
  | Generate a full manual | `node <skill-dir>/skill-guide.js --full` |
30
30
  | Return structured data | `node <skill-dir>/skill-guide.js --format json` |
31
31
 
32
- Use `--refresh` when the user expects newly installed or removed skills to appear. Use `--all` only when the user wants a cross-platform inventory.
32
+ Use `--refresh` when the user expects newly installed or removed skills to appear. Use `--all` only when the user wants a cross-platform inventory. Add `--platform claude` or `--platform codex` to force a specific platform view regardless of auto-detection.
33
33
 
34
34
  ## Guardrails
35
35
 
36
36
  - The scanner reads local metadata; it does not measure actual usage frequency.
37
37
  - Same-category suggestions and directory mentions require human review before installing, editing, or deleting anything.
38
38
  - Never delete skills, install packages, or publish results based only on a generated score.
39
+ - The default dashboard includes a "Review Candidates" slide with evidence-based findings and a Copy Prompt button. The CLI only prepares evidence and questions — semantic judgment comes from the agent. Always wait for agent assessment before acting on any finding.
40
+ - The `--review --format json` flag outputs a structured brief for programmatic agent consumption (no HTML).
39
41
  - Built-in dashboard labels support English and Chinese. For other languages, summarize the result in the user's language without rewriting generated HTML unless explicitly requested.
40
42
  - If the CLI is unavailable, report the missing file instead of silently replacing its behavior.
43
+ - All modes default to the current platform (auto-detected from env vars or install path). Cross-agent duplicates are normal — each agent needs its own skill copies. Use `--all` to see the full inventory across all agents.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skill-guide",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Scan 6+ skill directories across Claude Code, Codex, and cc-switch, then generate beautiful HTML slide presentations.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
package/skill-guide.js CHANGED
@@ -27,6 +27,7 @@ function usage() {
27
27
  ' skill-guide # Dashboard: personality, radar, insights (opens HTML)',
28
28
  ' skill-guide --find <name|query> # Deep dive or search (opens HTML)',
29
29
  ' skill-guide --doctor # Quick environment diagnostic',
30
+ ' skill-guide --review --format json # Structured review brief for agents',
30
31
  '',
31
32
  'Options:',
32
33
  ' --output <file> Write to file instead of default',
@@ -34,6 +35,7 @@ function usage() {
34
35
  ' --lang en|zh UI language',
35
36
  ' --refresh Force re-scan (ignore cache)',
36
37
  ' --all Show skills from all platforms (default: current platform)',
38
+ ' --platform <name> Force platform: claude | codex',
37
39
  ' --no-open Do not open HTML in browser',
38
40
  '',
39
41
  'Examples:',
@@ -41,6 +43,7 @@ function usage() {
41
43
  ' npx skill-guide --find investigate # Deep dive into a skill',
42
44
  ' npx skill-guide --find security # Search for security skills',
43
45
  ' npx skill-guide --doctor # Check for issues',
46
+ ' npx skill-guide --review --format json # Review brief for agents',
44
47
  ].join('\n');
45
48
  }
46
49
 
@@ -103,6 +106,16 @@ const LABELS = {
103
106
  gapHint: '{action}',
104
107
  scatteredSkills: 'Scattered skills, no idea what you have?',
105
108
  manySkillsPain: '{count}+ skills but no idea what you have?',
109
+ reviewBrief: 'Skill Review Brief',
110
+ reviewItems: 'review items',
111
+ reviewCopyPrompt: 'Copy Review Prompt',
112
+ reviewPasteToAgent: 'Paste to your agent for semantic review',
113
+ reviewNoItems: 'No review items found. Your skill stack looks clean!',
114
+ reviewSecurity: 'Security Flags',
115
+ reviewDuplicates: 'Duplicate Candidates',
116
+ reviewOverlap: 'Category Overlap',
117
+ reviewMalformed: 'Malformed Skills',
118
+ reviewBudget: 'Budget Overflow',
106
119
  },
107
120
  zh: {
108
121
  yourAgentSkills: '你的 Agent Skills 技能库',
@@ -159,6 +172,16 @@ const LABELS = {
159
172
  gapHint: '{action}',
160
173
  scatteredSkills: '技能散落,不知道自己有什么?',
161
174
  manySkillsPain: '{count}+ 个技能但不知道自己有什么?',
175
+ reviewBrief: '技能审查简报',
176
+ reviewItems: '个审查项',
177
+ reviewCopyPrompt: '复制审查提示词',
178
+ reviewPasteToAgent: '粘贴给 Agent 进行语义审查',
179
+ reviewNoItems: '没有发现需要审查的项目,技能栈看起来很干净!',
180
+ reviewSecurity: '安全标记',
181
+ reviewDuplicates: '重复候选',
182
+ reviewOverlap: '类别重叠',
183
+ reviewMalformed: '配置不完整',
184
+ reviewBudget: '预算溢出',
162
185
  },
163
186
  };
164
187
 
@@ -386,6 +409,7 @@ function te(text) {
386
409
  function parseMode() {
387
410
  if (hasFlag('--help') || hasFlag('-h')) return { mode: 'help' };
388
411
  if (hasFlag('--doctor')) return { mode: 'doctor' };
412
+ if (hasFlag('--review')) return { mode: 'review' };
389
413
  if (hasFlag('--recommend')) return { mode: 'recommend' };
390
414
  if (hasFlag('--share')) return { mode: 'share' };
391
415
 
@@ -394,7 +418,7 @@ function parseMode() {
394
418
  if (find) return { mode: 'find', value: find };
395
419
 
396
420
  // Positional arg: treat as --find
397
- const valueFlags = new Set(['--output', '--find', '--search', '--skill', '--format', '--lang', '--user']);
421
+ const valueFlags = new Set(['--output', '--find', '--search', '--skill', '--format', '--lang', '--user', '--platform']);
398
422
  const positional = args.find((arg, index) => !arg.startsWith('-') && !valueFlags.has(args[index - 1]));
399
423
  if (positional) return { mode: 'find', value: positional };
400
424
 
@@ -407,6 +431,8 @@ function scannerArgsFor(mode) {
407
431
 
408
432
  if (mode.mode === 'list' || mode.mode === 'doctor') {
409
433
  scannerArgs.push('--list');
434
+ } else if (mode.mode === 'review') {
435
+ scannerArgs.push('--full');
410
436
  } else if (mode.mode === 'find') {
411
437
  // Try as skill first, fall back to search
412
438
  scannerArgs.push('--skill', mode.value);
@@ -701,35 +727,57 @@ function renderInsightDashboardSlide(skills) {
701
727
  function renderCleanupSlide(skills) {
702
728
  const isZh = lang() === 'zh';
703
729
 
730
+ // Build review brief for evidence-based candidates
731
+ const data = { skills };
732
+ const details = doctorDetails(data);
733
+ const brief = buildReviewBrief(data, details);
734
+ const copyPrompt = buildCopyPrompt(brief);
735
+ const promptId = `rp-${crypto.randomUUID().slice(0, 8)}`;
736
+
704
737
  // Source breakdown
705
738
  const userSkills = skills.filter(s => (s.sources || []).some(src => ['claude-user', 'codex-user', 'cc-switch'].includes(src)));
706
739
  const pluginSkills = skills.filter(s => (s.sources || []).some(src => ['claude-plugin', 'codex-plugin'].includes(src)));
707
740
  const systemSkills = skills.filter(s => (s.sources || []).includes('openai-system'));
708
741
 
709
- // Duplicates (same name in user + plugin)
710
- const nameMap = {};
711
- for (const s of skills) {
712
- if (!nameMap[s.name]) nameMap[s.name] = new Set();
713
- for (const src of (s.sources || [])) nameMap[s.name].add(src);
714
- }
715
- const duplicates = Object.entries(nameMap)
716
- .filter(([, srcs]) =>
717
- [...srcs].some(s => ['claude-user','codex-user','cc-switch'].includes(s)) &&
718
- [...srcs].some(s => ['claude-plugin','codex-plugin'].includes(s))
719
- )
720
- .map(([name]) => name);
721
-
722
- // Under-configured
723
- const wrapped = computeWrappedStats(skills, computeHealthStats(skills));
724
- const dormant = wrapped.untappedCount || 0;
725
- const dormantPct = skills.length > 0 ? Math.round((dormant / skills.length) * 100) : 0;
726
-
727
742
  const userPct = skills.length > 0 ? Math.round((userSkills.length / skills.length) * 100) : 0;
728
743
  const pluginPct = skills.length > 0 ? Math.round((pluginSkills.length / skills.length) * 100) : 0;
729
744
 
745
+ const hasReviewItems = brief.totalReviewItems > 0;
746
+ const severityColor = { high: '#ef4444', medium: '#f59e0b', low: '#6b7280', info: '#818cf8' };
747
+ const typeIcon = { security: '🔴', duplicate: '🟡', malformed: '⚪', overlap: '🟣', budget: '🔵' };
748
+ const typeLabel = {
749
+ security: isZh ? '安全标记' : 'Security flags',
750
+ duplicate: isZh ? '重复候选' : 'Duplicate candidates',
751
+ malformed: isZh ? '配置不完整' : 'Malformed',
752
+ overlap: isZh ? '类别重叠' : 'Category overlap',
753
+ budget: isZh ? '预算溢出' : 'Budget overflow',
754
+ };
755
+
756
+ // Build review cards by type
757
+ const typeOrder = ['security', 'duplicate', 'malformed', 'overlap', 'budget'];
758
+ let reviewCards = '';
759
+ for (const type of typeOrder) {
760
+ const typeItems = brief.items.filter(i => i.type === type);
761
+ if (typeItems.length === 0) continue;
762
+ const itemsHtml = typeItems.slice(0, 3).map(item => `
763
+ <div style="padding:8px 0;border-bottom:1px solid var(--border)">
764
+ <div style="display:flex;align-items:center;gap:8px;margin-bottom:4px">
765
+ <span style="font-size:11px;font-weight:700;color:${severityColor[item.severity]};background:${severityColor[item.severity]}22;padding:2px 6px;border-radius:4px">${item.severity.toUpperCase()}</span>
766
+ <span style="font-size:13px;font-weight:600">${item.skills.map(s => escapeHtml(s)).join(', ')}</span>
767
+ </div>
768
+ <p style="font-size:12px;color:var(--muted);margin:0">${escapeHtml(truncate(item.evidence, 80))}</p>
769
+ </div>`).join('');
770
+ const moreCount = typeItems.length - 3;
771
+ reviewCards += `<div style="background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:12px 16px;max-width:580px;margin:0 auto 10px;text-align:left">
772
+ <p style="margin:0 0 6px;font-weight:600;font-size:13px">${typeIcon[type]} ${typeLabel[type]} (${typeItems.length})</p>
773
+ ${itemsHtml}
774
+ ${moreCount > 0 ? `<p style="font-size:11px;color:var(--muted);margin:4px 0 0">+ ${moreCount} more</p>` : ''}
775
+ </div>`;
776
+ }
777
+
730
778
  return `<section class="slide">
731
779
  <div class="rv center">
732
- <div class="kicker" data-i18n="label">${isZh ? '清理指南' : 'CLEANUP GUIDE'}</div>
780
+ <div class="kicker" data-i18n="label">${isZh ? '复核候选' : 'REVIEW CANDIDATES'}</div>
733
781
  <h2>${isZh ? '你的技能从哪来的?' : 'Where did your skills come from?'}</h2>
734
782
  <div class="stats" style="margin:20px 0">
735
783
  <div class="stat" style="border-color:var(--accent)"><b>${userSkills.length}</b><span>${isZh ? '用户目录来源' : 'user-directory sources'}</span></div>
@@ -741,36 +789,21 @@ function renderCleanupSlide(skills) {
741
789
  <div style="background:var(--ab);height:100%;width:${pluginPct}%" title="${isZh ? '插件目录来源' : 'Plugin-directory sources'}"></div>
742
790
  </div>
743
791
 
744
- ${duplicates.length > 0 ? (() => {
745
- // Build precise delete commands with paths
746
- const dupeDetails = duplicates.map(name => {
747
- const skill = skills.find(s => s.name === name);
748
- const dir = skill ? skill.dir : '';
749
- // Expand ~ to actual path hint
750
- const displayDir = dir || `~/.claude/skills/${name}`;
751
- return { name, dir: displayDir };
752
- });
753
- return `<div style="background:var(--card);border:1px solid rgba(234,179,8,0.3);border-radius:var(--r);padding:16px;max-width:580px;margin:0 auto 16px;text-align:left">
754
- <p style="margin:0 0 8px;color:#f59e0b;font-weight:600;font-size:14px">⚠️ ${isZh ? `${duplicates.length} 个重复技能` : `${duplicates.length} duplicate skills`}</p>
755
- <p style="font-size:13px;color:var(--muted);margin:0 0 8px">${isZh
756
- ? '这些技能同时存在于你的目录和插件目录中。请先确认自定义改动和实际使用情况,再决定是否移除用户目录副本。'
757
- : 'These exist in both your directory and the plugin directory. Review custom changes and actual usage before removing a user copy.'}</p>
758
- ${dupeDetails.map(d => `<div style="margin:6px 0;display:flex;align-items:center;gap:8px">
759
- <code style="flex:1;padding:4px 8px;background:var(--bg);border-radius:4px;font-size:12px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${escapeHtml(d.dir)}</code>
760
- <code style="padding:4px 8px;background:var(--bg);border-radius:4px;font-size:12px;color:var(--accent2);cursor:pointer;white-space:nowrap" onclick="copyText('Please review whether the skill at ${d.dir} duplicates a plugin copy. Do not delete anything until I confirm.')">📋 copy</code>
761
- </div>`).join('')}
762
- <p style="font-size:12px;color:var(--muted);margin:8px 0 0;font-style:italic">${isZh
763
- ? '💡 复制后粘贴给 Agent,让它先复核来源;确认前不要删除'
764
- : '💡 Paste to your agent for source review; do not delete anything until you confirm'}</p>
765
- </div>`;
766
- })() : ''}
767
-
768
- ${dormant > 0 ? `<div style="background:var(--card);border:1px solid var(--border);border-radius:var(--r);padding:16px;max-width:580px;margin:0 auto;text-align:left">
769
- <p style="margin:0 0 8px;color:var(--muted);font-weight:600;font-size:14px">📋 ${isZh ? `${dormant} 个配置不完整(${dormantPct}%)` : `${dormant} under-configured (${dormantPct}%)`}</p>
770
- <p style="font-size:13px;color:var(--muted);margin:0">${isZh
771
- ? '这些技能缺少描述或触发词,Agent 可能更难发现它们。请先复核内容和使用情况。'
772
- : 'These lack descriptions or triggers, so agents may have more difficulty discovering them. Review content and usage first.'}</p>
773
- </div>` : ''}
792
+ ${hasReviewItems ? `
793
+ <div style="max-width:580px;margin:0 auto">
794
+ <p style="font-size:13px;color:var(--muted);margin:0 0 12px">${isZh
795
+ ? `${brief.totalReviewItems} 个候选需要复核 点击下方按钮生成审查提示词,粘贴给你的 Agent 进行语义判断`
796
+ : `${brief.totalReviewItems} candidates to review click below to generate a review prompt, paste it to your agent for semantic judgment`}</p>
797
+ ${reviewCards}
798
+ <div style="text-align:center;margin-top:12px">
799
+ <button onclick="copyText(window['${promptId}'])" style="background:var(--accent);color:#0F172A;border:none;border-radius:var(--r);padding:10px 20px;font-size:14px;font-weight:600;cursor:pointer">${isZh ? '📋 复制审查提示词' : '📋 Copy Review Prompt'}</button>
800
+ <p style="font-size:11px;color:var(--muted);margin:8px 0 0;font-style:italic">${isZh
801
+ ? 'Agent 会对每项回复 CONFIRM / DISMISS / SUGGEST,确认前不要删除任何东西'
802
+ : 'Agent responds CONFIRM / DISMISS / SUGGEST per item; do not delete anything until you confirm'}</p>
803
+ </div>
804
+ <script>window['${promptId}']=${JSON.stringify(copyPrompt)};</script>
805
+ </div>
806
+ ` : `<p style="font-size:14px;color:var(--accent)">${isZh ? '没有发现需要复核的候选,技能栈看起来很干净!' : 'No review candidates found. Your skill stack looks clean!'}</p>`}
774
807
  </div>
775
808
  </section>`;
776
809
  }
@@ -780,8 +813,8 @@ function renderNextStepsSlide(skills) {
780
813
  const sample = (skills || []).filter(s => (s.description || '').length > 100).slice(0, 3);
781
814
  const sampleName = sample.length > 0 ? sample[0].name : 'investigate';
782
815
  const sampleName2 = sample.length > 1 ? sample[1].name : 'security-audit';
783
- const searchCmd = `npx skill-guide --find security`;
784
- const skillCmd = `npx skill-guide --find ${sampleName}`;
816
+ const searchCmd = `npx skill-guide security`;
817
+ const skillCmd = `npx skill-guide ${sampleName}`;
785
818
  const fullCmd = `npx skill-guide --full`;
786
819
  const recommendCmd = `npx skill-guide --recommend`;
787
820
  const shareCmd = `npx skill-guide --share`;
@@ -915,11 +948,17 @@ function shouldAutoOpen() {
915
948
  return true;
916
949
  }
917
950
 
951
+ const PLATFORM_LABELS = { claude: 'Claude Code', codex: 'Codex', all: 'All Platforms' };
952
+
918
953
  function detectPlatform() {
919
- // Only filter when explicitly running inside an agent
954
+ if (hasFlag('--all')) return 'all';
955
+ const explicit = getArgValue('--platform');
956
+ if (explicit && PLATFORM_LABELS[explicit]) return explicit;
920
957
  if (process.env.CODEX_AGENT) return 'codex';
921
958
  if (process.env.CLAUDE_CODE) return 'claude';
922
- // Default: show all (CODEX_HOME alone is not enough — tests set it too)
959
+ const dir = __dirname;
960
+ if (dir.includes(path.join('.claude', 'skills')) || dir.includes(path.join('.claude', 'plugins'))) return 'claude';
961
+ if (dir.includes(path.join('.codex', 'skills')) || dir.includes(path.join('.codex', 'plugins'))) return 'codex';
923
962
  return 'all';
924
963
  }
925
964
 
@@ -936,6 +975,35 @@ function filterSkillsByPlatform(skills, platform) {
936
975
  return skills;
937
976
  }
938
977
 
978
+ function applyPlatformFilter(data) {
979
+ const platform = detectPlatform();
980
+ if (platform === 'all') {
981
+ data._platform = 'all';
982
+ return data;
983
+ }
984
+ data._platform = platform;
985
+ if (data.skills) {
986
+ data.skills = filterSkillsByPlatform(data.skills, platform);
987
+ data.totalCount = data.skills.length;
988
+ }
989
+ if (data.sources) {
990
+ const keep = platform === 'claude'
991
+ ? ['claude-user', 'claude-plugin', 'cc-switch']
992
+ : ['codex-user', 'codex-plugin', 'openai-system', 'cc-switch'];
993
+ const filtered = {};
994
+ for (const [k, v] of Object.entries(data.sources)) {
995
+ if (keep.includes(k)) filtered[k] = v;
996
+ }
997
+ data.sources = filtered;
998
+ }
999
+ return data;
1000
+ }
1001
+
1002
+ function platformLabel() {
1003
+ const p = detectPlatform();
1004
+ return PLATFORM_LABELS[p] || p;
1005
+ }
1006
+
939
1007
  function skillRoots() {
940
1008
  const home = os.homedir();
941
1009
  const codexHome = process.env.CODEX_HOME || path.join(home, '.codex');
@@ -1621,6 +1689,133 @@ function computeHealthStats(skills) {
1621
1689
  };
1622
1690
  }
1623
1691
 
1692
+ // ---------------------------------------------------------------------------
1693
+ // --review: LLM review brief
1694
+ // ---------------------------------------------------------------------------
1695
+ function buildReviewBrief(data, details) {
1696
+ const skills = data.skills || [];
1697
+ const health = computeHealthStats(skills);
1698
+ const items = [];
1699
+ let counter = 0;
1700
+ function nextId(prefix) { return `${prefix}-${++counter}`; }
1701
+
1702
+ // 1. Security flags
1703
+ for (const flag of health.securityFlags) {
1704
+ const skill = skills.find(s => s.name === flag.name);
1705
+ items.push({
1706
+ id: nextId('sec'),
1707
+ type: 'security',
1708
+ severity: 'high',
1709
+ skills: [flag.name],
1710
+ evidence: `Patterns: ${flag.flags.join(', ')}`,
1711
+ context: `Description: ${truncate(skill?.description || '', 200)}`,
1712
+ question: `Does "${flag.name}" actually pose a security risk, or are these patterns used safely in context?`,
1713
+ actionHint: 'Review the full skill content. If the patterns are in example code or are safe, dismiss. If genuinely risky, flag for revision.',
1714
+ });
1715
+ }
1716
+
1717
+ // 2. Duplicate candidates
1718
+ for (const group of health.duplicateGroups) {
1719
+ const descriptions = group.names.map(n => {
1720
+ const s = skills.find(sk => sk.name === n);
1721
+ return `${n}: ${truncate(s?.description || '(no description)', 100)}`;
1722
+ });
1723
+ items.push({
1724
+ id: nextId('dup'),
1725
+ type: 'duplicate',
1726
+ severity: 'medium',
1727
+ skills: group.names,
1728
+ evidence: `Normalized name: "${group.normalized}"`,
1729
+ context: descriptions.join('\n'),
1730
+ question: `Are "${group.names.join('" and "')}" truly duplicate skills, or do they serve different purposes despite similar names?`,
1731
+ actionHint: 'If they differ in scope or purpose, consider renaming to clarify. If truly redundant, keep the one with better documentation.',
1732
+ });
1733
+ }
1734
+
1735
+ // 3. Malformed skills
1736
+ for (const file of (details.malformed || []).slice(0, 10)) {
1737
+ const basename = path.basename(path.dirname(file));
1738
+ items.push({
1739
+ id: nextId('mal'),
1740
+ type: 'malformed',
1741
+ severity: 'low',
1742
+ skills: [basename],
1743
+ evidence: `Missing frontmatter in: ${file.replace(os.homedir(), '~')}`,
1744
+ context: '',
1745
+ question: `What name, description, and triggers should be added to the skill at "${basename}"?`,
1746
+ actionHint: 'Read the file, understand its purpose, and suggest appropriate frontmatter fields.',
1747
+ });
1748
+ }
1749
+
1750
+ // 4. Category overlap (3+ skills in same category)
1751
+ const groups = groupBy(skills, 'category');
1752
+ for (const [cat, catSkills] of Object.entries(groups)) {
1753
+ if (catSkills.length >= 3) {
1754
+ const names = catSkills.slice(0, 5).map(s => s.name);
1755
+ const descs = catSkills.slice(0, 5).map(s =>
1756
+ ` - ${s.name}: ${truncate(s.description || '(no description)', 80)}`
1757
+ );
1758
+ items.push({
1759
+ id: nextId('ovr'),
1760
+ type: 'overlap',
1761
+ severity: 'info',
1762
+ skills: names,
1763
+ evidence: `${catSkills.length} skills in "${cat}" category`,
1764
+ context: descs.join('\n'),
1765
+ question: `Are these ${catSkills.length} "${cat}" skills overlapping (doing the same thing) or complementary (covering different aspects)?`,
1766
+ actionHint: 'If overlapping, suggest which to consolidate. If complementary, clarify how they differ.',
1767
+ });
1768
+ }
1769
+ }
1770
+
1771
+ // 5. Budget overflow
1772
+ if (health.budgetUsedPercent > 100) {
1773
+ const topConsumers = [...skills]
1774
+ .sort((a, b) => (b.description?.length || 0) - (a.description?.length || 0))
1775
+ .slice(0, 5);
1776
+ items.push({
1777
+ id: nextId('bud'),
1778
+ type: 'budget',
1779
+ severity: 'medium',
1780
+ skills: topConsumers.map(s => s.name),
1781
+ evidence: `Description budget used: ${health.budgetUsedPercent}% (~${health.totalTokenEstimate} tokens)`,
1782
+ context: topConsumers.map(s => ` - ${s.name}: ${(s.description || '').length} chars`).join('\n'),
1783
+ question: 'Which skill descriptions should be shortened to fit within the token budget?',
1784
+ actionHint: 'Prioritize trimming the longest descriptions. Preserve key information about triggers and use cases.',
1785
+ });
1786
+ }
1787
+
1788
+ return {
1789
+ generatedAt: new Date().toISOString(),
1790
+ totalSkills: skills.length,
1791
+ totalReviewItems: items.length,
1792
+ summary: {
1793
+ security: items.filter(i => i.type === 'security').length,
1794
+ duplicate: items.filter(i => i.type === 'duplicate').length,
1795
+ malformed: items.filter(i => i.type === 'malformed').length,
1796
+ overlap: items.filter(i => i.type === 'overlap').length,
1797
+ budget: items.filter(i => i.type === 'budget').length,
1798
+ },
1799
+ items,
1800
+ };
1801
+ }
1802
+
1803
+ function buildCopyPrompt(brief) {
1804
+ const lines = [
1805
+ `Review the following ${brief.totalReviewItems} findings from skill-guide and provide your assessment.`,
1806
+ '',
1807
+ ];
1808
+ for (const item of brief.items) {
1809
+ lines.push(`## [${item.severity.toUpperCase()}] ${item.type}: ${item.skills.join(', ')}`);
1810
+ lines.push(`Evidence: ${item.evidence}`);
1811
+ if (item.context) lines.push(`Context:\n${item.context}`);
1812
+ lines.push(`Question: ${item.question}`);
1813
+ lines.push('');
1814
+ }
1815
+ lines.push('For each item, respond with: CONFIRM (agree with the finding), DISMISS (false positive with reason), or SUGGEST (alternative action).');
1816
+ return lines.join('\n');
1817
+ }
1818
+
1624
1819
  function renderHealthTerminal(data) {
1625
1820
  const skills = data.skills || [];
1626
1821
  const health = computeHealthStats(skills);
@@ -3082,6 +3277,7 @@ function main() {
3082
3277
  // --doctor: terminal-only diagnostic
3083
3278
  if (mode.mode === 'doctor') {
3084
3279
  const data = runScanner(mode);
3280
+ applyPlatformFilter(data);
3085
3281
  process.stdout.write(`${printDoctor(data)}\n`);
3086
3282
  return;
3087
3283
  }
@@ -3105,6 +3301,7 @@ function main() {
3105
3301
  process.exit(result.status || 1);
3106
3302
  }
3107
3303
  const data = JSON.parse(result.stdout);
3304
+ applyPlatformFilter(data);
3108
3305
  if (format === 'json') {
3109
3306
  process.stdout.write(JSON.stringify(data, null, 2) + '\n');
3110
3307
  return;
@@ -3118,6 +3315,7 @@ function main() {
3118
3315
  } else {
3119
3316
  // Skill found — deep dive
3120
3317
  mode.mode = 'skill';
3318
+ applyPlatformFilter(skillData);
3121
3319
  if (format === 'json') {
3122
3320
  process.stdout.write(JSON.stringify(skillData, null, 2) + '\n');
3123
3321
  return;
@@ -3131,9 +3329,21 @@ function main() {
3131
3329
  return;
3132
3330
  }
3133
3331
 
3332
+ // --review mode (JSON-only for agent programmatic consumption)
3333
+ if (mode.mode === 'review') {
3334
+ const data = runScanner(mode);
3335
+ applyPlatformFilter(data);
3336
+ const details = doctorDetails(data);
3337
+ const brief = buildReviewBrief(data, details);
3338
+ brief.copyPrompt = buildCopyPrompt(brief);
3339
+ process.stdout.write(JSON.stringify(brief, null, 2) + '\n');
3340
+ return;
3341
+ }
3342
+
3134
3343
  // --recommend mode (online registry data)
3135
3344
  if (mode.mode === 'recommend') {
3136
3345
  const data = runScanner(mode);
3346
+ applyPlatformFilter(data);
3137
3347
  const installed = data.skills;
3138
3348
  const refresh = hasFlag('--refresh');
3139
3349
  const onlineEntries = registryModule.fetchRegistry({ refresh });
@@ -3157,6 +3367,7 @@ function main() {
3157
3367
  // --share mode (portfolio with --user flag)
3158
3368
  if (mode.mode === 'share') {
3159
3369
  const data = runScanner(mode);
3370
+ applyPlatformFilter(data);
3160
3371
  const user = getArgValue('--user');
3161
3372
  if (format === 'json') {
3162
3373
  process.stdout.write(JSON.stringify({ skills: data.skills, totalCount: data.totalCount }, null, 2) + '\n');
@@ -3175,13 +3386,7 @@ function main() {
3175
3386
 
3176
3387
  // Default mode (list): overview dashboard
3177
3388
  const data = runScanner(mode);
3178
-
3179
- // Filter by platform unless --all
3180
- const platform = hasFlag('--all') ? 'all' : detectPlatform();
3181
- if (platform !== 'all' && data.skills) {
3182
- data.skills = filterSkillsByPlatform(data.skills, platform);
3183
- data.totalCount = data.skills.length;
3184
- }
3389
+ applyPlatformFilter(data);
3185
3390
 
3186
3391
  if (format === 'json') {
3187
3392
  const serialized = JSON.stringify(data, null, 2);
@@ -3202,10 +3407,8 @@ function main() {
3202
3407
  process.exit(1);
3203
3408
  }
3204
3409
 
3205
- // Terminal output
3206
- if (platform !== 'all') {
3207
- const platformLabel = platform === 'codex' ? 'Codex' : 'Claude Code';
3208
- process.stdout.write(` Showing skills for: ${platformLabel} (use --all to see all)\n\n`);
3410
+ if (data._platform && data._platform !== 'all') {
3411
+ process.stdout.write(` Showing: ${platformLabel()} (use --all to see all)\n\n`);
3209
3412
  }
3210
3413
  process.stdout.write(renderDefaultTerminal(data.skills || []));
3211
3414