skillrepo 2.0.0 → 3.0.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.
Files changed (49) hide show
  1. package/README.md +215 -150
  2. package/bin/skillrepo.mjs +210 -36
  3. package/package.json +6 -3
  4. package/src/commands/add.mjs +176 -0
  5. package/src/commands/get.mjs +116 -0
  6. package/src/commands/init.mjs +471 -143
  7. package/src/commands/list.mjs +176 -0
  8. package/src/commands/remove.mjs +167 -0
  9. package/src/commands/search.mjs +188 -0
  10. package/src/commands/update.mjs +67 -0
  11. package/src/lib/cli-config.mjs +230 -0
  12. package/src/lib/config.mjs +238 -0
  13. package/src/lib/detect-ides.mjs +0 -19
  14. package/src/lib/errors.mjs +264 -0
  15. package/src/lib/file-write.mjs +705 -0
  16. package/src/lib/http.mjs +817 -37
  17. package/src/lib/identifier.mjs +153 -0
  18. package/src/lib/mcp-merge.mjs +275 -0
  19. package/src/lib/mergers/gitignore.mjs +73 -18
  20. package/src/lib/paths.mjs +46 -17
  21. package/src/lib/prompt.mjs +11 -44
  22. package/src/lib/sync.mjs +305 -0
  23. package/src/test/commands/add.test.mjs +285 -0
  24. package/src/test/commands/get.test.mjs +176 -0
  25. package/src/test/commands/init.test.mjs +486 -0
  26. package/src/test/commands/list.test.mjs +172 -0
  27. package/src/test/commands/remove.test.mjs +234 -0
  28. package/src/test/commands/search.test.mjs +204 -0
  29. package/src/test/commands/update.test.mjs +164 -0
  30. package/src/test/detect-ides.test.mjs +9 -14
  31. package/src/test/dispatcher.test.mjs +224 -0
  32. package/src/test/e2e/cli-commands.test.mjs +576 -0
  33. package/src/test/e2e/mock-server.mjs +364 -22
  34. package/src/test/helpers/capture-stream.mjs +48 -0
  35. package/src/test/integration/file-write.integration.test.mjs +279 -0
  36. package/src/test/lib/cli-config.test.mjs +407 -0
  37. package/src/test/lib/config.test.mjs +257 -0
  38. package/src/test/lib/errors.test.mjs +359 -0
  39. package/src/test/lib/file-write.test.mjs +784 -0
  40. package/src/test/lib/http.test.mjs +1198 -0
  41. package/src/test/lib/identifier.test.mjs +157 -0
  42. package/src/test/lib/mcp-merge.test.mjs +345 -0
  43. package/src/test/lib/paths.test.mjs +83 -0
  44. package/src/test/lib/sync.test.mjs +514 -0
  45. package/src/test/mergers/gitignore.test.mjs +145 -20
  46. package/src/lib/write-configs.mjs +0 -202
  47. package/src/test/e2e/HANDOFF.md +0 -223
  48. package/src/test/e2e/cli-init.test.mjs +0 -213
  49. package/src/test/e2e/payload-factory.mjs +0 -22
package/README.md CHANGED
@@ -1,214 +1,279 @@
1
1
  # skillrepo
2
2
 
3
- Set up SkillRepo in any IDE -- one command.
3
+ A pull-based CLI for managing your agent-skills library from the terminal.
4
4
 
5
5
  ```
6
6
  npx skillrepo init
7
7
  ```
8
8
 
9
- Auto-detects your IDEs, validates your access key, and writes the correct MCP
10
- configuration for each one. Safe to run multiple times.
9
+ Validates your access key, auto-detects your IDEs, wires up the MCP config,
10
+ and pulls your library. Safe to re-run at any time.
11
11
 
12
- ## Quick Start
13
-
14
- 1. **Create an access key** at [skillrepo.dev/app/settings](https://skillrepo.dev/app/settings) (Settings > Access Keys).
15
- 2. **Run the CLI** in your project directory:
16
- ```
17
- npx skillrepo init
18
- ```
19
- 3. **Done.** Your IDE can now discover and activate skills from your SkillRepo library.
20
-
21
- ## Usage
22
-
23
- ```
24
- npx skillrepo init [options]
25
- ```
26
-
27
- ### Options
28
-
29
- | Flag | Short | Description |
30
- |------|-------|-------------|
31
- | `--key <key>` | `-k` | Access key. If omitted, the CLI reads `SKILLREPO_ACCESS_KEY` from the environment, then prompts interactively. |
32
- | `--url <url>` | `-u` | SkillRepo server URL. Defaults to `https://skillrepo.dev`. Use this for self-hosted instances. |
33
- | `--yes` | `-y` | Non-interactive mode. Skips confirmation prompts. Useful for CI or scripted setups. |
34
-
35
- ### Examples
12
+ ## Install
36
13
 
37
14
  ```sh
38
- # Interactive setup (prompts for key and confirms detected IDEs)
39
- npx skillrepo init
40
-
41
- # Pass the key directly
42
- npx skillrepo init --key sk_live_abc123
15
+ # One-off via npx (recommended)
16
+ npx skillrepo <command>
43
17
 
44
- # Self-hosted instance, non-interactive
45
- npx skillrepo init --url https://skillrepo.internal.company.com --yes
46
-
47
- # Key from environment variable
48
- export SKILLREPO_ACCESS_KEY=sk_live_abc123
49
- npx skillrepo init --yes
18
+ # Or install globally
19
+ npm install -g skillrepo
20
+ skillrepo <command>
50
21
  ```
51
22
 
52
- ## What It Does
53
-
54
- The CLI performs four steps:
23
+ Requires Node.js 18 or later.
55
24
 
56
- 1. **Detects installed IDEs** by checking for IDE-specific directories in the
57
- current project (`.claude/`, `.cursor/`, `.vscode/`) and global paths
58
- (`~/.codeium/windsurf/`). If no IDE is detected, it defaults to Claude Code
59
- and Cursor.
25
+ ## Quick start
60
26
 
61
- 2. **Validates the access key** against the SkillRepo API and fetches the
62
- current skill mapping data for your library.
63
-
64
- 3. **Writes MCP configuration files** for each detected IDE, using the correct
65
- format and environment variable syntax for that IDE.
66
-
67
- 4. **Writes skill mapping files** that let agents match user requests to the
68
- right skill without a network round-trip. For Claude Code, it also installs a
69
- SessionStart hook that auto-refreshes the mapping on each session start.
70
-
71
- ### Files Created or Modified
27
+ 1. **Create an access key** at [skillrepo.dev/app/settings](https://skillrepo.dev/app/settings)
28
+ (Settings Access Keys).
29
+ 2. **Run `init`** inside your project directory:
30
+ ```sh
31
+ npx skillrepo init
32
+ ```
33
+ 3. **Your library is now on disk.** The CLI wrote skills into
34
+ `.claude/skills/` (project) and registered the MCP server with every IDE
35
+ it detected (`.claude/`, `.cursor/`, `.vscode/`, `~/.codeium/windsurf/`).
36
+ 4. **From now on**, use `skillrepo update` to pull new versions,
37
+ `skillrepo add` to add skills to your library, and `skillrepo list` to
38
+ see what you have.
72
39
 
73
- | File | IDE | Purpose |
74
- |------|-----|---------|
75
- | `.mcp.json` | Claude Code | MCP server connection config |
76
- | `.claude/skillrepo.md` | Claude Code | Skill-to-tool mapping |
77
- | `.cursor/mcp.json` | Cursor | MCP server connection config |
78
- | `.cursor/rules/skillrepo.mdc` | Cursor | Skill-to-tool mapping |
79
- | `~/.codeium/windsurf/mcp_config.json` | Windsurf | MCP server connection config (global) |
80
- | `.vscode/mcp.json` | VS Code + Copilot | MCP server connection config |
81
- | `.env.local` | All | Stores `SKILLREPO_ACCESS_KEY` (gitignored) |
40
+ ## Commands
82
41
 
83
- All writes are merge-safe. The CLI reads existing files, adds or updates only
84
- the `skillrepo` entry, and leaves all other entries untouched. Running `init`
85
- again with a new key updates the key in `.env.local` without affecting anything
86
- else.
42
+ ### `init` first-run setup
87
43
 
88
- ## IDE-Specific Details
44
+ Validates your access key, detects installed IDEs, writes the MCP config,
45
+ and runs the first library sync.
89
46
 
90
- ### Claude Code
47
+ ```sh
48
+ skillrepo init [--key <key>] [--url <url>] [--yes] [--force] [--ide <list>] [--global] [--json]
49
+ ```
91
50
 
92
- - Config file: `.mcp.json` with `mcpServers.skillrepo` entry
93
- - Uses `${SKILLREPO_ACCESS_KEY}` syntax for environment variable expansion
94
- - Includes `"type": "http"` in the server entry
95
- - Installs a SessionStart hook that refreshes the skill mapping file
96
- (`.claude/skillrepo.md`) automatically on every session start
97
- - Skill mappings are always current without manual intervention
51
+ | Flag | Description |
52
+ |------|-------------|
53
+ | `--key, -k <key>` | Access key. Falls back to `SKILLREPO_ACCESS_KEY` env var, then interactive prompt. |
54
+ | `--url, -u <url>` | Server URL. Defaults to `https://skillrepo.dev`. Use for self-hosted. |
55
+ | `--yes, -y` | Non-interactive. Skip all confirmation prompts. Required for CI. |
56
+ | `--force` | Re-prompt for a new key even if `~/.claude/skillrepo/config.json` is valid. |
57
+ | `--ide <list>` | Comma-separated vendor override. One or more of `claude`, `cursor`, `windsurf`, `vscode`, or `all`. |
58
+ | `--global` | Write skills to `~/.claude/skills/` (personal) instead of `.claude/skills/` (project). |
59
+ | `--json` | Emit a structured JSON summary on success. |
98
60
 
99
- ### Cursor
61
+ `init` is idempotent: re-running with a valid existing config re-runs
62
+ detection + MCP merge + first sync without re-prompting for a key. If the
63
+ stored key has been revoked (401 from `/auth/validate`), the CLI falls back
64
+ to the interactive prompt automatically.
100
65
 
101
- - Config file: `.cursor/mcp.json` with `mcpServers.skillrepo` entry
102
- - Uses `${env:SKILLREPO_ACCESS_KEY}` syntax for environment variable expansion
103
- - Skill mapping file (`.cursor/rules/skillrepo.mdc`) is static; re-run
104
- `npx skillrepo init` or ask your agent to run `update skills from skillrepo`
105
- to refresh it after adding or removing skills
66
+ **Headless / CI:** if you run from a directory with no IDE markers, init
67
+ will refuse and print a copy-pasteable MCP config for manual wiring. To
68
+ proceed anyway, pass `--ide claude` (or the target vendor).
106
69
 
107
- ### Windsurf
70
+ ### `update` — sync your library
108
71
 
109
- - Config file: `~/.codeium/windsurf/mcp_config.json` (global, not per-project)
110
- - Uses `serverUrl` instead of `url` in the server entry
111
- - Uses `${env:SKILLREPO_ACCESS_KEY}` syntax for environment variable expansion
72
+ ```sh
73
+ skillrepo update [--global] [--ide <list>] [--json]
74
+ ```
112
75
 
113
- ### VS Code + Copilot
76
+ Pulls the latest state of your library from the server using a delta
77
+ sync. Writes new and updated skills, removes skills that were removed
78
+ from the library, and skips skills that are unchanged. Uses ETag
79
+ caching so repeat runs return `304 Not Modified` when nothing has
80
+ changed.
114
81
 
115
- - Config file: `.vscode/mcp.json` with `servers.skillrepo` entry (note:
116
- `servers`, not `mcpServers`)
117
- - VS Code does not support environment variable interpolation in MCP config;
118
- instead, the CLI creates an `inputs` entry that prompts for the access key on
119
- first use
120
- - Uses `${input:skillrepo-api-key}` syntax to reference the input prompt
82
+ ### `get` fetch a single skill
121
83
 
122
- ## Team Setup
84
+ ```sh
85
+ skillrepo get <@owner/name> [--global] [--ide <list>] [--json]
86
+ ```
123
87
 
124
- For teams sharing a repository, an admin runs the setup once and commits the
125
- generated config files. Each developer then clones and adds their own key.
88
+ One-shot fetch. Does NOT mutate your library or the server just reads
89
+ `GET /api/v1/skills/{owner}/{name}` and writes the skill to disk. Use
90
+ this to preview or pin a specific skill without adding it to your library.
126
91
 
127
- ### Admin (one-time)
92
+ ### `list` — show what's in your library
128
93
 
129
94
  ```sh
130
- cd your-team-repo
131
- npx skillrepo init
132
- git add .mcp.json .claude/ .cursor/ .vscode/
133
- git commit -m "chore: add SkillRepo integration"
134
- git push
95
+ skillrepo list [--json]
135
96
  ```
136
97
 
137
- The `.env.local` file is not committed -- it contains the access key and should
138
- remain gitignored.
98
+ Renders your library as a table: owner, name, version, description. Uses
99
+ the same cached ETag as `update`.
139
100
 
140
- ### Each Developer
101
+ ### `search` — explore the registry
141
102
 
142
103
  ```sh
143
- git pull
144
- npx skillrepo init
104
+ skillrepo search <query> [--limit <n>] [--json] [--semantic]
145
105
  ```
146
106
 
147
- The CLI detects the existing config files, merges in any updates, and writes the
148
- developer's own access key to `.env.local`. Developers can also skip the CLI
149
- and set the environment variable manually:
107
+ Queries `/api/v1/skills/search` for public skills matching `query`.
108
+ `--limit` caps the result count (default 20). `--semantic` is accepted
109
+ but currently a no-op semantic search is a planned backend feature.
110
+
111
+ ### `add` — add a skill to your library
150
112
 
151
113
  ```sh
152
- echo 'SKILLREPO_ACCESS_KEY=sk_live_their_key' >> .env.local
114
+ skillrepo add <@owner/name> [--global] [--ide <list>] [--json]
153
115
  ```
154
116
 
155
- ## Self-Hosted Usage
117
+ POSTs to `/api/v1/library`, then fetches the single skill directly and
118
+ writes it to disk. Requires a write-scoped access key. On `409` (already
119
+ in library), re-fetches the current version so your local state is
120
+ consistent.
156
121
 
157
- If you run a self-hosted SkillRepo instance, pass the `--url` flag:
122
+ ### `remove` remove a skill from your library
158
123
 
159
124
  ```sh
160
- npx skillrepo init --url https://skillrepo.internal.company.com
125
+ skillrepo remove <@owner/name> [--global] [--ide <list>] [--json]
161
126
  ```
162
127
 
163
- The CLI writes the custom URL into all MCP config files. The access key is
164
- validated against your self-hosted instance instead of skillrepo.dev.
128
+ DELETEs from `/api/v1/library` and deletes the local directory. Requires
129
+ a write-scoped access key. The local delete is immediate and does not
130
+ wait for a follow-up sync.
165
131
 
166
- You can also set the URL via the `SKILLREPO_URL` environment variable to avoid
167
- passing `--url` every time.
132
+ ## Configuration
168
133
 
169
- ## Troubleshooting
170
-
171
- ### "Invalid key format. Keys start with sk_live_"
172
-
173
- Access keys always begin with `sk_live_`. Verify you copied the full key from
174
- Settings > Access Keys. If the key was created with a different prefix, it may
175
- be a test key that is not valid for production use.
134
+ ### Credentials
176
135
 
177
- ### "Cannot reach https://skillrepo.dev"
136
+ The CLI stores credentials at `~/.claude/skillrepo/config.json` (chmod
137
+ 0600 on POSIX):
178
138
 
179
- Check your network connection. If you are behind a corporate proxy or firewall,
180
- ensure HTTPS traffic to `skillrepo.dev` (or your self-hosted URL) is allowed.
181
- For self-hosted instances, verify the `--url` flag points to the correct address.
139
+ ```json
140
+ {
141
+ "schemaVersion": 1,
142
+ "apiKey": "sk_live_...",
143
+ "serverUrl": "https://skillrepo.dev",
144
+ "accountSlug": "alice",
145
+ "accountId": "acc_...",
146
+ "userId": "user_...",
147
+ "writtenAt": "2026-04-15T00:00:00Z"
148
+ }
149
+ ```
182
150
 
183
- ### "Cannot parse .mcp.json -- invalid JSON"
151
+ Every command except `init` resolves credentials in this order:
152
+ 1. `--key` / `--url` CLI flags
153
+ 2. `~/.claude/skillrepo/config.json`
154
+ 3. `SKILLREPO_ACCESS_KEY` / `SKILLREPO_URL` environment variables
155
+ 4. Hard-fail with a "run `skillrepo init`" hint
156
+
157
+ `init` is different by design. Because `init` owns the credential
158
+ lifecycle — it writes the config file in the first place, and
159
+ `--force` / stale-key re-prompts need to decide whether to reuse
160
+ cached credentials — `init` uses a more nuanced order. Resolved
161
+ in sequence (each step only runs if the prior ones produced no
162
+ key):
163
+
164
+ 1. `--key` / `--url` CLI flags
165
+ 2. `SKILLREPO_ACCESS_KEY` / `SKILLREPO_URL` environment variables
166
+ (process env, not files)
167
+ 3. Existing `~/.claude/skillrepo/config.json` — skipped when
168
+ `--force` is set
169
+ 4. `.env.local` and `.env` files in the project directory — skipped
170
+ when `--force` is set
171
+ 5. Interactive prompt for the key; server URL falls back to
172
+ `https://skillrepo.dev`
173
+
174
+ Two scenarios worth calling out:
175
+
176
+ - **`init --force` with `SKILLREPO_ACCESS_KEY` set**: uses the env
177
+ var (step 2). `--force` only clears the cached credentials, not
178
+ the runtime env.
179
+ - **`init` with valid existing config and no flags/env**: reuses
180
+ the cached credentials for a silent no-op refresh.
181
+ - **`init` with a config that the server now rejects (stale key)**:
182
+ falls through to the interactive prompt automatically, without
183
+ needing `--force`.
184
+
185
+ ### Environment variables
186
+
187
+ | Variable | Purpose |
188
+ |----------|---------|
189
+ | `SKILLREPO_ACCESS_KEY` | Access key for any command. Takes precedence over the config file but not CLI flags. |
190
+ | `SKILLREPO_URL` | Server URL. Same precedence as above. |
191
+ | `SKILLREPO_TIMEOUT_MS` | Per-request fetch timeout in milliseconds (default 30000). Set to `0` to disable. |
192
+ | `NO_COLOR` | Set any non-empty value to disable ANSI color in CLI output. |
193
+
194
+ ### Skill placement
195
+
196
+ By default, skills land at `.claude/skills/<name>/` (project-scoped). Pass
197
+ `--global` to target `~/.claude/skills/<name>/` instead. When the CLI
198
+ detects an IDE that has no documented skills convention (Cursor, Windsurf,
199
+ VS Code), it falls back to project `/skills/<name>/` and adds `/skills/`
200
+ to your `.gitignore` on first write.
201
+
202
+ ## Exit codes
203
+
204
+ | Code | Meaning |
205
+ |------|---------|
206
+ | 0 | Success |
207
+ | 1 | Network error (unreachable server, DNS, timeout, exhausted retries) |
208
+ | 2 | Auth error (invalid key, revoked, suspended account) |
209
+ | 3 | Disk error (cannot read or write a file/directory) |
210
+ | 4 | Scope error (key lacks the required `registry:write` scope) |
211
+ | 5 | Validation error (bad flag, malformed identifier, unknown vendor) |
212
+
213
+ Pass `--verbose` to any command to print stack traces and retry
214
+ attempts on failure.
215
+
216
+ ## Retries
217
+
218
+ The CLI automatically retries transient server failures on every
219
+ idempotent API call — specifically `POST /auth/validate`,
220
+ `GET /library`, `GET /skills/:owner/:name`, and `GET /skills/search`.
221
+ This means the read-only commands (`update`, `get`, `list`, `search`)
222
+ and the validate + sync calls inside `init` benefit automatically.
223
+
224
+ - **Triggered by:** 429, 502, 503, 504, and raw network errors (DNS,
225
+ TCP reset, timeout).
226
+ - **NOT triggered by:** 4xx auth/validation errors — those never
227
+ succeed on retry — nor 500, which is treated as a real-bug signal
228
+ that should surface loudly rather than be masked.
229
+ - **Backoff:** exponential with full jitter, 3 attempts total, base
230
+ 500ms, capped at 8 seconds per sleep.
231
+ - **Write endpoints** (`add`, `remove`) are single-shot to keep
232
+ behavior predictable — a 503 mid-POST could mean either "body
233
+ never reached the server" or "body processed, response lost",
234
+ and the client cannot distinguish the two.
235
+
236
+ ## Self-hosted SkillRepo
237
+
238
+ The CLI works against any SkillRepo instance that implements the v1 API.
239
+ Point it at your own host:
184
240
 
185
- The CLI cannot merge into a malformed JSON file. Open the file, fix the syntax
186
- error (or delete it to start fresh), then run `npx skillrepo init` again.
241
+ ```sh
242
+ skillrepo init --url https://skillrepo.internal.company.com
243
+ ```
187
244
 
188
- ### "No IDEs detected"
245
+ Or persist it via env var in your shell profile:
189
246
 
190
- The CLI looks for IDE-specific directories in the current working directory. If
191
- you are not in a project root, `cd` into your project first. If no IDE
192
- directories exist yet, the CLI defaults to configuring Claude Code and Cursor.
247
+ ```sh
248
+ export SKILLREPO_URL=https://skillrepo.internal.company.com
249
+ export SKILLREPO_ACCESS_KEY=sk_live_...
250
+ ```
193
251
 
194
- ### VS Code prompts for the access key every time
252
+ ## Troubleshooting
195
253
 
196
- This is expected. VS Code does not support environment variable expansion in
197
- MCP config files, so it uses an input prompt instead. The key is cached for the
198
- duration of your VS Code session. Enter the same key from your `.env.local`
199
- file.
254
+ **"No access key configured"** Run `skillrepo init`, or pass `--key`,
255
+ or set `SKILLREPO_ACCESS_KEY`.
200
256
 
201
- ### Skill mappings are stale
257
+ **"Invalid access key format"** — Keys must start with `sk_live_`.
258
+ The CLI trims leading and trailing whitespace from keys in every
259
+ path — both the interactive prompt in `init` and the Bearer header
260
+ used by every subsequent command — so pasting from email or a
261
+ browser with a trailing newline is safe.
202
262
 
203
- For Claude Code, the SessionStart hook refreshes mappings automatically. For
204
- Cursor and VS Code + Copilot, re-run `npx skillrepo init` or ask your agent to
205
- run `update skills from skillrepo` to regenerate the mapping file.
263
+ **"No IDEs detected in this directory"** The CLI detected no
264
+ `.claude/`, `.cursor/`, `.vscode/`, or `~/.codeium/windsurf/` markers.
265
+ Either run from inside a project with one of those folders, pass
266
+ `--ide <vendor>` to target a specific IDE, or copy the printed MCP
267
+ config manually.
206
268
 
207
- ## Requirements
269
+ **"Rate limit exceeded — retried automatically and still getting
270
+ 429"** — The CLI already retried with backoff. Wait a minute and
271
+ retry. Pass `--verbose` to see the per-attempt timings.
208
272
 
209
- - Node.js 18 or later
210
- - Zero runtime dependencies (uses built-in `fetch` and `fs`)
273
+ **Windows:** skill updates use a best-effort atomic rename pattern.
274
+ A crash mid-update may leave a partial state; the next `update` run
275
+ fully overwrites it.
211
276
 
212
277
  ## License
213
278
 
214
- AGPL-3.0
279
+ MIT — see [LICENSE](./LICENSE).