skills-package-manager 0.10.0 → 0.11.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/README.md CHANGED
@@ -9,7 +9,7 @@ For one-off usage, `npx skills-package-manager add ...` is the low-friction migr
9
9
  ```bash
10
10
  npx skills-package-manager --help
11
11
  npx skills-package-manager --version
12
- npx skills-package-manager add <specifier> [--skill <name>]
12
+ npx skills-package-manager add <specifier> [--skill <name>...]
13
13
  npx skills-package-manager install
14
14
  npx skills-package-manager patch <skill>
15
15
  npx skills-package-manager patch-commit <edit-dir>
@@ -37,26 +37,37 @@ npx skills-package-manager add owner/repo
37
37
  # Interactive — clone repo, discover skills, select via multiselect prompt
38
38
  npx skills-package-manager add owner/repo
39
39
  npx skills-package-manager add https://github.com/owner/repo
40
+ npx skills-package-manager add https://gitlab.com/org/repo
41
+ npx skills-package-manager add git@github.com:owner/repo.git
42
+ npx skills-package-manager add ./my-local-skills
40
43
 
41
- # Non-interactive — add a specific skill by name
44
+ # Non-interactive — add one or more specific skills by name
42
45
  npx skills-package-manager add owner/repo --skill find-skills
46
+ npx skills-package-manager add owner/repo -s frontend-design -s skill-creator
43
47
  npx skills-package-manager add owner/repo@find-skills
44
48
  npx skills-package-manager add owner/repo#main@find-skills
45
49
 
46
50
  # Direct repo subpath
47
51
  npx skills-package-manager add owner/repo/skills/my-skill
48
- npx skills-package-manager add https://github.com/owner/repo/tree/main/skills/my-skill#main
52
+ npx skills-package-manager add https://github.com/owner/repo/tree/main/skills/my-skill
53
+
54
+ # Inspect or target agents with skills CLI-compatible flags
55
+ npx skills-package-manager add owner/repo --list
56
+ npx skills-package-manager add owner/repo --all
57
+ npx skills-package-manager add owner/repo -a claude-code -a opencode
49
58
 
50
59
  # Direct specifier — skip discovery
51
- npx skills-package-manager add https://github.com/owner/repo.git#path:/skills/my-skill
60
+ npx skills-package-manager add 'github:owner/repo#abc1234&path:/skills/my-skill'
52
61
  npx skills-package-manager add link:./local-source/skills/my-skill
53
- npx skills-package-manager add local:./.agents/skills/my-skill
62
+ npx skills-package-manager add 'local:*' --skill my-skill
54
63
  npx skills-package-manager add ./local-source
55
- npx skills-package-manager add file:./skills-package.tgz#path:/skills/my-skill
56
- npx skills-package-manager add npm:@scope/skills-package#path:/skills/my-skill
64
+ npx skills-package-manager add 'file:./skills-package.tgz&path:/skills/my-skill'
65
+ npx skills-package-manager add 'npm:@scope/skills-package@1.0.0&path:/skills/my-skill'
57
66
  ```
58
67
 
59
68
  After `npx skills-package-manager add`, the newly added skills are resolved, installed or registered according to their protocol, and linked to each configured `linkTarget` immediately.
69
+ GitHub sources are written back to `skills.json` as pinned `github:owner/repo#<commit>&path:<path>` specifiers.
70
+ The `--copy` flag is accepted for `npx skills add` command-line compatibility; SPM still keeps one canonical install directory and links configured agent targets from there.
60
71
 
61
72
  #### How it works
62
73
 
@@ -65,7 +76,7 @@ When given `owner/repo` or a GitHub URL:
65
76
  1. Shallow-clones the repository into a temp directory
66
77
  2. Scans for `SKILL.md` files (checks root, then `skills/`, `.agents/skills/`, etc.)
67
78
  3. Presents an interactive multiselect prompt (powered by [@clack/prompts](https://github.com/bombshell-dev/clack))
68
- 4. Writes selected skills to `skills.json` and resolves `skills-lock.yaml`
79
+ 4. Writes selected, pinned skill specifiers to `skills.json`
69
80
  5. Cleans up the temp directory
70
81
 
71
82
  ### `npx skills-package-manager init`
@@ -106,7 +117,7 @@ npx skills-package-manager install
106
117
  ```
107
118
 
108
119
  This resolves each skill from its specifier, installs managed skills into `installDir` (default `.agents/skills/`), registers `local:` skills in place, and creates symlinks for each `linkTarget`.
109
- When `selfSkill` is `true`, `npx skills-package-manager install` also installs the bundled `skills-package-manager-cli` skill so users get guidance for `skills.json`, `skills-lock.yaml`, and `npx skills-package-manager` commands. This helper skill is not written to `skills-lock.yaml`.
120
+ When `selfSkill` is `true`, `npx skills-package-manager install` also installs the bundled `skills-package-manager-cli` skill so users get guidance for `skills.json` and `npx skills-package-manager` commands. This helper skill is injected at install time and is not written to `skills.json`.
110
121
  If `patchedSkills` contains an entry for a managed skill, the corresponding patch file is applied after the skill is materialized. `local:` skills cannot be patched because their source directories are user-owned.
111
122
 
112
123
  ### `npx skills-package-manager patch`
@@ -120,7 +131,7 @@ npx skills-package-manager patch hello-skill --edit-dir ./tmp/hello-skill
120
131
 
121
132
  Behavior:
122
133
 
123
- - Resolves the currently locked content for the target skill
134
+ - Resolves the current manifest content for the target skill
124
135
  - Extracts an editable copy into a temporary directory by default
125
136
  - Reapplies any committed patch for that skill unless `--ignore-existing` is passed
126
137
  - Writes patch edit metadata so `patch-commit` can generate a new patch file later
@@ -139,12 +150,11 @@ Behavior:
139
150
  - Compares the edited directory with the original resolved skill content
140
151
  - Writes a unified diff patch file to `patches/<skill>.patch` by default
141
152
  - Updates `skills.json` through the `patchedSkills` field
142
- - Updates `skills-lock.yaml` with patch path and digest metadata
143
153
  - Reinstalls and relinks the patched skill so the working tree reflects the committed patch
144
154
 
145
155
  ### `npx skills-package-manager update`
146
156
 
147
- Refresh resolvable skills declared in `skills.json` without changing the manifest:
157
+ Refresh resolvable skills declared in `skills.json` and write the updated pins back to the manifest:
148
158
 
149
159
  ```bash
150
160
  npx skills-package-manager update
@@ -154,10 +164,10 @@ npx skills-package-manager update find-skills rspress-custom-theme
154
164
  Behavior:
155
165
 
156
166
  - Uses `skills.json` as the source of truth
157
- - Re-resolves git refs and npm package targets
158
- - Skips local `link:` and `local:` skills, including the bundled self skill
167
+ - Updates git skills to the latest `main` commit and npm skills to the registry `latest` version
168
+ - Skips local `link:`, `local:`, and `file:` skills
159
169
  - Fails immediately for unknown skill names
160
- - Writes `skills-lock.yaml` only after fetch and link succeed
170
+ - Writes `skills.json` only after the updated install succeeds
161
171
 
162
172
  ## Programmatic API
163
173
 
@@ -182,14 +192,15 @@ const skills = await listRepoSkills('vercel-labs', 'skills')
182
192
  ## Specifier Format
183
193
 
184
194
  ```text
185
- git/file/npm: <source>#[ref&]path:<skill-path>
195
+ git/file/npm: <source>[#ref][&path:<skill-path>]
186
196
  link: link:<path-to-skill-dir>
187
197
  local: local:<path-to-existing-skill-dir>
198
+ local shorthand: local:*
188
199
  ```
189
200
 
190
201
  | Part | Description | Example |
191
202
  |------|-------------|---------|
192
- | `source` | Git URL, direct `link:` or `local:` skill path, `file:` tarball, or `npm:` package name | `https://github.com/o/r.git`, `link:./local/skills/my-skill`, `local:./.agents/skills/my-skill`, `file:./skills.tgz`, `npm:@scope/pkg` |
203
+ | `source` | Git URL or `github:` shorthand, direct `link:` or `local:` skill path, `file:` tarball, or `npm:` package name | `github:o/r`, `https://github.com/o/r.git`, `link:./local/skills/my-skill`, `local:*`, `file:./skills.tgz`, `npm:@scope/pkg@1.0.0` |
193
204
  | `ref` | Optional git ref | `main`, `v1.0.0`, `HEAD`, `6cb0992`, `6cb0992a176f2ca142e19f64dca8ac12025b035e` |
194
205
  | `path` | Path to skill directory within source | `/skills/my-skill` |
195
206
 
@@ -201,7 +212,7 @@ local: local:<path-to-existing-skill-dir>
201
212
  - **`link`** — Symlinks a local skill directory into `installDir`
202
213
  - **`local`** — Uses an existing user-owned skill directory in place
203
214
  - **`file`** — Extracts a local `tgz` package and copies the selected skill
204
- - **`npm`** — Resolves a package from the configured npm registry, locks the tarball URL/version/integrity, and installs from the downloaded tarball
215
+ - **`npm`** — Resolves a package from the configured npm registry and installs from the downloaded tarball
205
216
 
206
217
  `npm:` reads `registry` and scoped `@scope:registry` values from `.npmrc`. Matching `:_authToken`, `:_auth`, or `username` + `:_password` entries are also used for private registry requests.
207
218
 
@@ -212,7 +223,7 @@ src/
212
223
  ├── bin/ # CLI entry points
213
224
  ├── cli/ # CLI runner and interactive prompts
214
225
  ├── commands/ # add, install, patch command implementations
215
- ├── config/ # skills.json / skills-lock.yaml read/write
226
+ ├── config/ # skills.json read/write and in-memory install plan resolution
216
227
  ├── github/ # Git clone + skill discovery (listSkills)
217
228
  ├── install/ # Skill materialization, linking, pruning
218
229
  ├── patches/ # Patch edit state, diff generation, patch application
@@ -231,4 +242,3 @@ pnpm build # Builds with Rslib (ESM output + DTS)
231
242
  ```bash
232
243
  pnpm test # Runs tests with Rstest
233
244
  ```
234
- ``
package/dist/index.d.ts CHANGED
@@ -4,15 +4,21 @@ export declare function addCommand(options: AddCommandOptions): Promise<{
4
4
  } | {
5
5
  skillName: string;
6
6
  specifier: string;
7
- }[]>;
7
+ }[] | {
8
+ status: "listed";
9
+ skills: SkillInfo[];
10
+ }>;
8
11
 
9
12
  export declare type AddCommandOptions = {
10
13
  cwd: string;
11
14
  specifier: string;
12
- skill?: string;
15
+ skill?: string | string[];
13
16
  global?: boolean;
14
17
  yes?: boolean;
15
18
  agent?: string[];
19
+ list?: boolean;
20
+ copy?: boolean;
21
+ all?: boolean;
16
22
  };
17
23
 
18
24
  /**
@@ -58,8 +64,6 @@ export declare enum ErrorCode {
58
64
  YAML_PARSE_ERROR = "EYAMLPARSE",
59
65
  INVALID_SPECIFIER = "EINVALIDSPEC",
60
66
  MANIFEST_NOT_FOUND = "EMANIFEST",
61
- LOCKFILE_NOT_FOUND = "ELOCKFILE",
62
- LOCKFILE_OUTDATED = "ELOCKOUTDATED",
63
67
  MANIFEST_EXISTS = "EMANIFESTEXISTS",
64
68
  MANIFEST_VALIDATION_ERROR = "EMANIFESTVAL",
65
69
  NETWORK_ERROR = "ENETWORK",
@@ -74,18 +78,6 @@ export declare enum ErrorCode {
74
78
 
75
79
  export declare function expandSkillsManifest(_rootDir: string, manifest: SkillsManifest): Promise<NormalizedSkillsManifest>;
76
80
 
77
- export declare function fetchSkillsFromLock(rootDir: string, manifest: SkillsManifest, lockfile: SkillsLock, options?: {
78
- onProgress?: InstallProgressListener;
79
- }): Promise<{
80
- readonly status: "skipped";
81
- readonly reason: "up-to-date";
82
- readonly fetched?: undefined;
83
- } | {
84
- readonly status: "fetched";
85
- readonly fetched: string[];
86
- reason?: undefined;
87
- }>;
88
-
89
81
  /**
90
82
  * Error thrown when file system operations fail
91
83
  */
@@ -156,7 +148,6 @@ export declare function installCommand(options: InstallCommandOptions): Promise<
156
148
 
157
149
  export declare type InstallCommandOptions = {
158
150
  cwd: string;
159
- frozenLockfile?: boolean;
160
151
  onProgress?: InstallProgressListener;
161
152
  };
162
153
 
@@ -190,38 +181,26 @@ declare type InstallProgressReporter = {
190
181
  };
191
182
 
192
183
  export declare function installSkills(rootDir: string, options?: {
193
- frozenLockfile?: boolean;
194
184
  onProgress?: InstallProgressListener;
195
185
  }): Promise<{
196
- readonly status: "skipped";
197
- readonly reason: "manifest-missing";
186
+ status: "skipped";
187
+ reason: string;
198
188
  installed?: undefined;
199
189
  } | {
200
- readonly status: "installed";
201
- readonly installed: string[];
190
+ status: "installed";
191
+ installed: string[];
202
192
  reason?: undefined;
203
193
  }>;
204
194
 
205
195
  export declare const installStageHooks: {
206
- beforeFetch: (_rootDir: string, _manifest: SkillsManifest, _lockfile: SkillsLock) => Promise<void>;
196
+ beforeFetch: (_rootDir: string, _manifest: SkillsManifest, _plan: ResolvedSkillsPlan) => Promise<void>;
207
197
  };
208
198
 
209
- export declare function isLockInSync(rootDir: string, manifest: NormalizedSkillsManifest, lock: SkillsLock | null, manifestStat?: ManifestStat | null, installState?: {
210
- manifestStat?: ManifestStat;
211
- } | null): Promise<boolean>;
212
-
213
199
  /**
214
200
  * Checks if an error is a known SPM error
215
201
  */
216
202
  export declare function isSpmError(error: unknown): error is SpmError;
217
203
 
218
- export declare function linkSkillsFromLock(rootDir: string, manifest: SkillsManifest, lockfile: SkillsLock, options?: {
219
- onProgress?: InstallProgressListener;
220
- }): Promise<{
221
- readonly status: "linked";
222
- readonly linked: string[];
223
- }>;
224
-
225
204
  /**
226
205
  * List skills in a GitHub repo by cloning and scanning.
227
206
  * This avoids GitHub API rate limits.
@@ -229,23 +208,18 @@ export declare function linkSkillsFromLock(rootDir: string, manifest: SkillsMani
229
208
  export declare function listRepoSkills(owner: string, repo: string, ref?: string): Promise<SkillInfo[]>;
230
209
 
231
210
  /**
232
- * Error thrown when manifest or lockfile operations fail
211
+ * Error thrown when manifest operations fail
233
212
  */
234
213
  export declare class ManifestError extends SpmError {
235
214
  readonly filePath: string;
236
215
  constructor(options: {
237
- code: ErrorCode.MANIFEST_NOT_FOUND | ErrorCode.LOCKFILE_NOT_FOUND | ErrorCode.LOCKFILE_OUTDATED | ErrorCode.MANIFEST_EXISTS | ErrorCode.MANIFEST_VALIDATION_ERROR;
216
+ code: ErrorCode.MANIFEST_NOT_FOUND | ErrorCode.MANIFEST_EXISTS | ErrorCode.MANIFEST_VALIDATION_ERROR;
238
217
  filePath: string;
239
218
  message?: string;
240
219
  cause?: Error;
241
220
  });
242
221
  }
243
222
 
244
- declare interface ManifestStat {
245
- mtimeMs: number;
246
- size: number;
247
- }
248
-
249
223
  /**
250
224
  * Error thrown when network operations fail
251
225
  */
@@ -283,7 +257,12 @@ export declare type NormalizedSpecifier = {
283
257
 
284
258
  export declare function normalizeSkillsManifest(manifest: Partial<SkillsManifest>): NormalizedSkillsManifest;
285
259
 
286
- export declare function normalizeSpecifier(specifier: string): NormalizedSpecifier;
260
+ export declare function normalizeSpecifier(specifier: string, options?: NormalizeSpecifierOptions): NormalizedSpecifier;
261
+
262
+ declare type NormalizeSpecifierOptions = {
263
+ installDir?: string;
264
+ skillName?: string;
265
+ };
287
266
 
288
267
  /**
289
268
  * Error thrown when parsing fails (JSON, YAML, specifiers)
@@ -352,46 +331,9 @@ declare type ProgressReporterOptions = {
352
331
  info?: (text: string) => void;
353
332
  };
354
333
 
355
- export declare function readSkillsLock(rootDir: string): Promise<SkillsLock | null>;
356
-
357
334
  export declare function readSkillsManifest(rootDir: string): Promise<NormalizedSkillsManifest | null>;
358
335
 
359
- export declare function resolveLockEntry(cwd: string, specifier: string, skillName?: string): Promise<{
360
- skillName: string;
361
- entry: SkillsLockEntry;
362
- }>;
363
-
364
- export declare function runCli(argv: string[], context?: {
365
- cwd?: string;
366
- }): Promise<unknown>;
367
-
368
- /**
369
- * Error thrown when a skill operation fails
370
- */
371
- export declare class SkillError extends SpmError {
372
- readonly skillName: string;
373
- constructor(options: {
374
- code: ErrorCode.SKILL_NOT_FOUND | ErrorCode.SKILL_EXISTS | ErrorCode.VALIDATION_ERROR;
375
- skillName: string;
376
- message?: string;
377
- cause?: Error;
378
- });
379
- }
380
-
381
- export declare type SkillInfo = {
382
- name: string;
383
- description: string;
384
- path: string;
385
- };
386
-
387
- export declare type SkillsLock = {
388
- lockfileVersion: '0.1';
389
- installDir: string;
390
- linkTargets: string[];
391
- skills: Record<string, SkillsLockEntry>;
392
- };
393
-
394
- export declare type SkillsLockEntry = {
336
+ export declare type ResolvedSkillEntry = {
395
337
  specifier: string;
396
338
  resolution: {
397
339
  type: 'link';
@@ -424,6 +366,46 @@ export declare type SkillsLockEntry = {
424
366
  };
425
367
  };
426
368
 
369
+ export declare type ResolvedSkillsPlan = {
370
+ installDir: string;
371
+ linkTargets: string[];
372
+ skills: Record<string, ResolvedSkillEntry>;
373
+ };
374
+
375
+ export declare function resolveSkillEntry(cwd: string, specifier: string, skillName?: string, options?: {
376
+ installDir?: string;
377
+ }): Promise<{
378
+ skillName: string;
379
+ entry: ResolvedSkillEntry;
380
+ }>;
381
+
382
+ export declare function resolveSkillsPlan(cwd: string, manifest: NormalizedSkillsManifest, options?: {
383
+ onProgress?: InstallProgressListener;
384
+ }): Promise<ResolvedSkillsPlan>;
385
+
386
+ export declare function runCli(argv: string[], context?: {
387
+ cwd?: string;
388
+ }): Promise<unknown>;
389
+
390
+ /**
391
+ * Error thrown when a skill operation fails
392
+ */
393
+ export declare class SkillError extends SpmError {
394
+ readonly skillName: string;
395
+ constructor(options: {
396
+ code: ErrorCode.SKILL_NOT_FOUND | ErrorCode.SKILL_EXISTS | ErrorCode.VALIDATION_ERROR;
397
+ skillName: string;
398
+ message?: string;
399
+ cause?: Error;
400
+ });
401
+ }
402
+
403
+ export declare type SkillInfo = {
404
+ name: string;
405
+ description: string;
406
+ path: string;
407
+ };
408
+
427
409
  /**
428
410
  * Skills manifest input type used for authoring/writing manifests.
429
411
  * This preserves optionality for fields with defaults.
@@ -474,7 +456,7 @@ export declare type UpdateCommandResult = {
474
456
  unchanged: string[];
475
457
  skipped: Array<{
476
458
  name: string;
477
- reason: 'link-specifier' | 'local-specifier';
459
+ reason: 'link-specifier' | 'local-specifier' | 'file-specifier';
478
460
  }>;
479
461
  failed: Array<{
480
462
  name: string;
@@ -482,10 +464,6 @@ export declare type UpdateCommandResult = {
482
464
  }>;
483
465
  };
484
466
 
485
- export declare function withBundledSelfSkillLock(rootDir: string, manifest: SkillsManifest, lockfile: SkillsLock): Promise<SkillsLock>;
486
-
487
- export declare function writeSkillsLock(rootDir: string, lockfile: SkillsLock): Promise<void>;
488
-
489
467
  export declare function writeSkillsManifest(rootDir: string, manifest: SkillsManifest): Promise<void>;
490
468
 
491
469
  export { }