skills-package-manager 0.6.3 → 0.8.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
@@ -11,6 +11,8 @@ npx skills-package-manager --help
11
11
  npx skills-package-manager --version
12
12
  npx skills-package-manager add <specifier> [--skill <name>]
13
13
  npx skills-package-manager install
14
+ npx skills-package-manager patch <skill>
15
+ npx skills-package-manager patch-commit <edit-dir>
14
16
  npx skills-package-manager update [skill...]
15
17
  npx skills-package-manager init [--yes]
16
18
  ```
@@ -104,6 +106,40 @@ npx skills-package-manager install
104
106
 
105
107
  This resolves each skill from its specifier, materializes it into `installDir` (default `.agents/skills/`), and creates symlinks for each `linkTarget`.
106
108
  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`.
109
+ If `patchedSkills` contains an entry for a skill, the corresponding patch file is applied after the skill is materialized.
110
+
111
+ ### `npx skills-package-manager patch`
112
+
113
+ Prepare a skill for patching without changing the manifest yet:
114
+
115
+ ```bash
116
+ npx skills-package-manager patch hello-skill
117
+ npx skills-package-manager patch hello-skill --edit-dir ./tmp/hello-skill
118
+ ```
119
+
120
+ Behavior:
121
+
122
+ - Resolves the currently locked content for the target skill
123
+ - Extracts an editable copy into a temporary directory by default
124
+ - Reapplies any committed patch for that skill unless `--ignore-existing` is passed
125
+ - Writes patch edit metadata so `patch-commit` can generate a new patch file later
126
+
127
+ ### `npx skills-package-manager patch-commit`
128
+
129
+ Commit an edited patch directory back into the project:
130
+
131
+ ```bash
132
+ npx skills-package-manager patch-commit /tmp/skills-pm-patch-hello-skill-12345
133
+ npx skills-package-manager patch-commit ./tmp/hello-skill --patches-dir ./custom-patches
134
+ ```
135
+
136
+ Behavior:
137
+
138
+ - Compares the edited directory with the original resolved skill content
139
+ - Writes a unified diff patch file to `patches/<skill>.patch` by default
140
+ - Updates `skills.json` through the `patchedSkills` field
141
+ - Updates `skills-lock.yaml` with patch path and digest metadata
142
+ - Reinstalls and relinks the patched skill so the working tree reflects the committed patch
107
143
 
108
144
  ### `npx skills-package-manager update`
109
145
 
@@ -172,10 +208,11 @@ link: link:<path-to-skill-dir>
172
208
  src/
173
209
  ├── bin/ # CLI entry points
174
210
  ├── cli/ # CLI runner and interactive prompts
175
- ├── commands/ # add, install command implementations
211
+ ├── commands/ # add, install, patch command implementations
176
212
  ├── config/ # skills.json / skills-lock.yaml read/write
177
213
  ├── github/ # Git clone + skill discovery (listSkills)
178
214
  ├── install/ # Skill materialization, linking, pruning
215
+ ├── patches/ # Patch edit state, diff generation, patch application
179
216
  ├── specifiers/ # Specifier parsing and normalization
180
217
  └── utils/ # Hashing, filesystem helpers
181
218
  ```
package/dist/291.js ADDED
@@ -0,0 +1,19 @@
1
+ import * as __rspack_external_zlib from "zlib";
2
+ import * as __rspack_external_node_readline_91c31510 from "node:readline";
3
+ export { stripVTControlCharacters, styleText } from "node:util";
4
+ export { default as node_process, stdin, stdout } from "node:process";
5
+ export { ReadStream } from "node:tty";
6
+ export { default as node_fs, existsSync, lstatSync, readdirSync } from "node:fs";
7
+ export { basename, default as node_path, dirname, join, posix, win32 } from "node:path";
8
+ export { EventEmitter, default as events } from "events";
9
+ export { default as fs } from "fs";
10
+ export { EventEmitter as external_node_events_EventEmitter } from "node:events";
11
+ export { default as node_stream } from "node:stream";
12
+ export { StringDecoder } from "node:string_decoder";
13
+ export { default as path, dirname as external_path_dirname, parse } from "path";
14
+ export { default as assert } from "assert";
15
+ export { Buffer } from "buffer";
16
+ export { default as node_assert } from "node:assert";
17
+ export { randomBytes } from "node:crypto";
18
+ export { default as promises } from "node:fs/promises";
19
+ export { __rspack_external_node_readline_91c31510, __rspack_external_zlib };
package/dist/612.js ADDED
@@ -0,0 +1,48 @@
1
+ var __webpack_modules__ = {};
2
+ var __webpack_module_cache__ = {};
3
+ function __webpack_require__(moduleId) {
4
+ var cachedModule = __webpack_module_cache__[moduleId];
5
+ if (void 0 !== cachedModule) return cachedModule.exports;
6
+ var module = __webpack_module_cache__[moduleId] = {
7
+ exports: {}
8
+ };
9
+ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
10
+ return module.exports;
11
+ }
12
+ __webpack_require__.m = __webpack_modules__;
13
+ (()=>{
14
+ __webpack_require__.n = (module)=>{
15
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
16
+ __webpack_require__.d(getter, {
17
+ a: getter
18
+ });
19
+ return getter;
20
+ };
21
+ })();
22
+ (()=>{
23
+ __webpack_require__.d = (exports, definition)=>{
24
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {
25
+ enumerable: true,
26
+ get: definition[key]
27
+ });
28
+ };
29
+ })();
30
+ (()=>{
31
+ __webpack_require__.add = function(modules) {
32
+ Object.assign(__webpack_require__.m, modules);
33
+ };
34
+ })();
35
+ (()=>{
36
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
37
+ })();
38
+ (()=>{
39
+ __webpack_require__.r = (exports)=>{
40
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {
41
+ value: 'Module'
42
+ });
43
+ Object.defineProperty(exports, '__esModule', {
44
+ value: true
45
+ });
46
+ };
47
+ })();
48
+ export { __webpack_require__ };
@@ -0,0 +1,466 @@
1
+ export declare function addCommand(options: AddCommandOptions): Promise<{
2
+ skillName: string;
3
+ specifier: string;
4
+ } | {
5
+ skillName: string;
6
+ specifier: string;
7
+ }[]>;
8
+
9
+ export declare type AddCommandOptions = {
10
+ cwd: string;
11
+ specifier: string;
12
+ skill?: string;
13
+ global?: boolean;
14
+ yes?: boolean;
15
+ agent?: string[];
16
+ };
17
+
18
+ /**
19
+ * Clone a git repo (shallow) into a temp dir, discover skills, then clean up.
20
+ */
21
+ export declare function cloneAndDiscover(gitUrl: string, ref?: string): Promise<{
22
+ skills: SkillInfo[];
23
+ cleanup: () => Promise<void>;
24
+ }>;
25
+
26
+ /**
27
+ * Converts a Node.js file system error to an appropriate SPM error type
28
+ */
29
+ export declare function convertNodeError(error: NodeJS.ErrnoException, context: {
30
+ operation: string;
31
+ path: string;
32
+ }): FileSystemError;
33
+
34
+ export declare function createInstallProgressReporter(options?: ProgressReporterOptions): InstallProgressReporter;
35
+
36
+ /**
37
+ * Discover skills in a local directory by scanning for SKILL.md files.
38
+ * Recursively scans the repo tree for directories containing SKILL.md.
39
+ */
40
+ export declare function discoverSkillsInDir(baseDir: string): Promise<SkillInfo[]>;
41
+
42
+ /**
43
+ * Error codes for SPM (Skills Package Manager)
44
+ * Inspired by pnpm's error code system
45
+ */
46
+ export declare enum ErrorCode {
47
+ FILE_NOT_FOUND = "ENOENT",
48
+ PERMISSION_DENIED = "EACCES",
49
+ FILE_EXISTS = "EEXIST",
50
+ FS_ERROR = "EFS",
51
+ GIT_CLONE_FAILED = "EGITCLONE",
52
+ GIT_FETCH_FAILED = "EGITFETCH",
53
+ GIT_CHECKOUT_FAILED = "EGITCHECKOUT",
54
+ GIT_REF_NOT_FOUND = "EGITREF",
55
+ GIT_NOT_INSTALLED = "EGITNOTFOUND",
56
+ PARSE_ERROR = "EPARSE",
57
+ JSON_PARSE_ERROR = "EJSONPARSE",
58
+ YAML_PARSE_ERROR = "EYAMLPARSE",
59
+ INVALID_SPECIFIER = "EINVALIDSPEC",
60
+ MANIFEST_NOT_FOUND = "EMANIFEST",
61
+ LOCKFILE_NOT_FOUND = "ELOCKFILE",
62
+ LOCKFILE_OUTDATED = "ELOCKOUTDATED",
63
+ MANIFEST_EXISTS = "EMANIFESTEXISTS",
64
+ MANIFEST_VALIDATION_ERROR = "EMANIFESTVAL",
65
+ NETWORK_ERROR = "ENETWORK",
66
+ REPO_NOT_FOUND = "EREPONOTFOUND",
67
+ UNKNOWN_ERROR = "EUNKNOWN",
68
+ NOT_IMPLEMENTED = "ENOTIMPL",
69
+ VALIDATION_ERROR = "EVALIDATION",
70
+ SKILL_NOT_FOUND = "ESKILLNOTFOUND",
71
+ SKILL_EXISTS = "ESKILLEXISTS"
72
+ }
73
+
74
+ export declare function expandSkillsManifest(_rootDir: string, manifest: SkillsManifest): Promise<NormalizedSkillsManifest>;
75
+
76
+ export declare function fetchSkillsFromLock(rootDir: string, manifest: SkillsManifest, lockfile: SkillsLock, options?: {
77
+ onProgress?: InstallProgressListener;
78
+ }): Promise<{
79
+ readonly status: "skipped";
80
+ readonly reason: "up-to-date";
81
+ readonly fetched?: undefined;
82
+ } | {
83
+ readonly status: "fetched";
84
+ readonly fetched: string[];
85
+ readonly reason?: undefined;
86
+ }>;
87
+
88
+ /**
89
+ * Error thrown when file system operations fail
90
+ */
91
+ export declare class FileSystemError extends SpmError {
92
+ readonly operation: string;
93
+ readonly path: string;
94
+ constructor(options: {
95
+ code: ErrorCode.FILE_NOT_FOUND | ErrorCode.PERMISSION_DENIED | ErrorCode.FILE_EXISTS | ErrorCode.FS_ERROR;
96
+ operation: 'read' | 'write' | 'access' | 'mkdir' | 'rm' | 'copy' | 'symlink' | string;
97
+ path: string;
98
+ message?: string;
99
+ cause?: Error;
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Formats an error for display to the user
105
+ * Provides helpful context for known error types
106
+ */
107
+ export declare function formatErrorForDisplay(error: unknown): string;
108
+
109
+ /**
110
+ * Gets the exit code for an error
111
+ * Returns 1 for general errors, specific codes for known error types
112
+ */
113
+ export declare function getExitCode(error: unknown): number;
114
+
115
+ /**
116
+ * Error thrown when git operations fail
117
+ */
118
+ export declare class GitError extends SpmError {
119
+ readonly operation: string;
120
+ readonly repoUrl?: string;
121
+ readonly ref?: string;
122
+ constructor(options: {
123
+ code: ErrorCode.GIT_CLONE_FAILED | ErrorCode.GIT_FETCH_FAILED | ErrorCode.GIT_CHECKOUT_FAILED | ErrorCode.GIT_REF_NOT_FOUND | ErrorCode.GIT_NOT_INSTALLED;
124
+ operation: 'clone' | 'fetch' | 'checkout' | 'ls-remote' | 'rev-parse' | string;
125
+ repoUrl?: string;
126
+ ref?: string;
127
+ message?: string;
128
+ cause?: Error;
129
+ });
130
+ }
131
+
132
+ export declare function initCommand(options: InitCommandOptions, promptInit?: InitPrompter): Promise<SkillsManifest>;
133
+
134
+ export declare type InitCommandOptions = {
135
+ cwd: string;
136
+ yes?: boolean;
137
+ };
138
+
139
+ declare type InitPrompter = () => Promise<InitPromptResult>;
140
+
141
+ declare type InitPromptResult = {
142
+ installDir: string;
143
+ linkTargets: string[];
144
+ };
145
+
146
+ export declare function installCommand(options: InstallCommandOptions): Promise<{
147
+ readonly status: "installed";
148
+ readonly installed: string[];
149
+ }>;
150
+
151
+ export declare type InstallCommandOptions = {
152
+ cwd: string;
153
+ frozenLockfile?: boolean;
154
+ };
155
+
156
+ declare type InstallPhase = 'resolving' | 'fetching' | 'linking' | 'finalizing' | 'done';
157
+
158
+ export declare type InstallProgressEvent = {
159
+ type: 'resolved';
160
+ skillName: string;
161
+ } | {
162
+ type: 'added';
163
+ skillName: string;
164
+ } | {
165
+ type: 'installed';
166
+ skillName: string;
167
+ };
168
+
169
+ export declare type InstallProgressListener = (event: InstallProgressEvent) => void;
170
+
171
+ declare type InstallProgressReporter = {
172
+ start(total: number): void;
173
+ setPhase(phase: Exclude<InstallPhase, 'done'>): void;
174
+ onProgress(event: InstallProgressEvent): void;
175
+ complete(): void;
176
+ fail(): void;
177
+ };
178
+
179
+ export declare function installSkills(rootDir: string, options?: {
180
+ frozenLockfile?: boolean;
181
+ onProgress?: InstallProgressListener;
182
+ }): Promise<{
183
+ readonly status: "skipped";
184
+ readonly reason: "manifest-missing";
185
+ readonly installed?: undefined;
186
+ } | {
187
+ readonly status: "installed";
188
+ readonly installed: string[];
189
+ readonly reason?: undefined;
190
+ }>;
191
+
192
+ export declare const installStageHooks: {
193
+ beforeFetch: (_rootDir: string, _manifest: SkillsManifest, _lockfile: SkillsLock) => Promise<void>;
194
+ };
195
+
196
+ export declare function isLockInSync(rootDir: string, manifest: NormalizedSkillsManifest, lock: SkillsLock | null): Promise<boolean>;
197
+
198
+ /**
199
+ * Checks if an error is a known SPM error
200
+ */
201
+ export declare function isSpmError(error: unknown): error is SpmError;
202
+
203
+ export declare function linkSkillsFromLock(rootDir: string, manifest: SkillsManifest, lockfile: SkillsLock, options?: {
204
+ onProgress?: InstallProgressListener;
205
+ }): Promise<{
206
+ readonly status: "linked";
207
+ readonly linked: string[];
208
+ }>;
209
+
210
+ /**
211
+ * List skills in a GitHub repo by cloning and scanning.
212
+ * This avoids GitHub API rate limits.
213
+ */
214
+ export declare function listRepoSkills(owner: string, repo: string, ref?: string): Promise<SkillInfo[]>;
215
+
216
+ /**
217
+ * Error thrown when manifest or lockfile operations fail
218
+ */
219
+ export declare class ManifestError extends SpmError {
220
+ readonly filePath: string;
221
+ constructor(options: {
222
+ code: ErrorCode.MANIFEST_NOT_FOUND | ErrorCode.LOCKFILE_NOT_FOUND | ErrorCode.LOCKFILE_OUTDATED | ErrorCode.MANIFEST_EXISTS | ErrorCode.MANIFEST_VALIDATION_ERROR;
223
+ filePath: string;
224
+ message?: string;
225
+ cause?: Error;
226
+ });
227
+ }
228
+
229
+ /**
230
+ * Error thrown when network operations fail
231
+ */
232
+ export declare class NetworkError extends SpmError {
233
+ readonly url?: string;
234
+ constructor(options: {
235
+ code: ErrorCode.NETWORK_ERROR | ErrorCode.REPO_NOT_FOUND;
236
+ url?: string;
237
+ message: string;
238
+ cause?: Error;
239
+ });
240
+ }
241
+
242
+ /**
243
+ * Skills manifest output type after validation/default application.
244
+ * Use this for normalized manifests returned from reads/parsing.
245
+ */
246
+ declare type NormalizedSkillsManifest = {
247
+ $schema?: string;
248
+ installDir: string;
249
+ linkTargets: string[];
250
+ selfSkill?: boolean;
251
+ skills: Record<string, string>;
252
+ patchedSkills?: Record<string, string>;
253
+ };
254
+
255
+ export declare type NormalizedSpecifier = {
256
+ type: 'git' | 'link' | 'file' | 'npm';
257
+ source: string;
258
+ ref: string | null;
259
+ path: string;
260
+ normalized: string;
261
+ skillName: string;
262
+ };
263
+
264
+ export declare function normalizeSkillsManifest(manifest: Partial<SkillsManifest>): NormalizedSkillsManifest;
265
+
266
+ export declare function normalizeSpecifier(specifier: string): NormalizedSpecifier;
267
+
268
+ /**
269
+ * Error thrown when parsing fails (JSON, YAML, specifiers)
270
+ */
271
+ export declare class ParseError extends SpmError {
272
+ readonly filePath?: string;
273
+ readonly content?: string;
274
+ constructor(options: {
275
+ code: ErrorCode.PARSE_ERROR | ErrorCode.JSON_PARSE_ERROR | ErrorCode.YAML_PARSE_ERROR | ErrorCode.INVALID_SPECIFIER;
276
+ filePath?: string;
277
+ content?: string;
278
+ message: string;
279
+ cause?: Error;
280
+ });
281
+ }
282
+
283
+ export declare function parseGitHubUrl(input: string): {
284
+ owner: string;
285
+ repo: string;
286
+ } | null;
287
+
288
+ export declare function parseOwnerRepo(input: string): {
289
+ owner: string;
290
+ repo: string;
291
+ } | null;
292
+
293
+ export declare function parseSpecifier(specifier: string): {
294
+ sourcePart: string;
295
+ ref: string | null;
296
+ path: string;
297
+ };
298
+
299
+ export declare function patchCommand(options: PatchCommandOptions): Promise<PatchCommandResult>;
300
+
301
+ export declare type PatchCommandOptions = {
302
+ cwd: string;
303
+ skillName: string;
304
+ editDir?: string;
305
+ ignoreExisting?: boolean;
306
+ };
307
+
308
+ export declare type PatchCommandResult = {
309
+ status: 'patched';
310
+ skillName: string;
311
+ editDir: string;
312
+ originalSpecifier: string;
313
+ };
314
+
315
+ export declare function patchCommitCommand(options: PatchCommitCommandOptions): Promise<PatchCommitCommandResult>;
316
+
317
+ export declare type PatchCommitCommandOptions = {
318
+ cwd: string;
319
+ editDir: string;
320
+ patchesDir?: string;
321
+ };
322
+
323
+ export declare type PatchCommitCommandResult = {
324
+ status: 'patched';
325
+ skillName: string;
326
+ patchFile: string;
327
+ };
328
+
329
+ declare type ProgressReporterOptions = {
330
+ isTTY?: boolean;
331
+ write?: (text: string) => void;
332
+ info?: (text: string) => void;
333
+ };
334
+
335
+ export declare function readSkillsLock(rootDir: string): Promise<SkillsLock | null>;
336
+
337
+ export declare function readSkillsManifest(rootDir: string): Promise<NormalizedSkillsManifest | null>;
338
+
339
+ export declare function resolveLockEntry(cwd: string, specifier: string, skillName?: string): Promise<{
340
+ skillName: string;
341
+ entry: SkillsLockEntry;
342
+ }>;
343
+
344
+ export declare function runCli(argv: string[], context?: {
345
+ cwd?: string;
346
+ }): Promise<unknown>;
347
+
348
+ /**
349
+ * Error thrown when a skill operation fails
350
+ */
351
+ export declare class SkillError extends SpmError {
352
+ readonly skillName: string;
353
+ constructor(options: {
354
+ code: ErrorCode.SKILL_NOT_FOUND | ErrorCode.SKILL_EXISTS | ErrorCode.VALIDATION_ERROR;
355
+ skillName: string;
356
+ message?: string;
357
+ cause?: Error;
358
+ });
359
+ }
360
+
361
+ export declare type SkillInfo = {
362
+ name: string;
363
+ description: string;
364
+ path: string;
365
+ };
366
+
367
+ export declare type SkillsLock = {
368
+ lockfileVersion: '0.1';
369
+ installDir: string;
370
+ linkTargets: string[];
371
+ skills: Record<string, SkillsLockEntry>;
372
+ };
373
+
374
+ export declare type SkillsLockEntry = {
375
+ specifier: string;
376
+ resolution: {
377
+ type: 'link';
378
+ path: string;
379
+ } | {
380
+ type: 'file';
381
+ tarball: string;
382
+ path: string;
383
+ } | {
384
+ type: 'git';
385
+ url: string;
386
+ commit: string;
387
+ path: string;
388
+ } | {
389
+ type: 'npm';
390
+ packageName: string;
391
+ version: string;
392
+ path: string;
393
+ tarball: string;
394
+ integrity?: string;
395
+ registry?: string;
396
+ };
397
+ digest: string;
398
+ patch?: {
399
+ path: string;
400
+ digest: string;
401
+ };
402
+ };
403
+
404
+ /**
405
+ * Skills manifest input type used for authoring/writing manifests.
406
+ * This preserves optionality for fields with defaults.
407
+ */
408
+ export declare type SkillsManifest = {
409
+ $schema?: string;
410
+ installDir?: string;
411
+ linkTargets?: string[];
412
+ selfSkill?: boolean;
413
+ skills?: Record<string, string>;
414
+ patchedSkills?: Record<string, string>;
415
+ };
416
+
417
+ /**
418
+ * Base error class for SPM (Skills Package Manager)
419
+ * All custom errors should extend this class
420
+ */
421
+ export declare class SpmError extends Error {
422
+ readonly code: ErrorCode;
423
+ readonly cause?: Error;
424
+ readonly context: Record<string, unknown>;
425
+ constructor(options: {
426
+ code: ErrorCode;
427
+ message: string;
428
+ cause?: Error;
429
+ context?: Record<string, unknown>;
430
+ });
431
+ /**
432
+ * Returns a formatted string representation of the error
433
+ */
434
+ toString(): string;
435
+ /**
436
+ * Returns a detailed object representation for logging/debugging
437
+ */
438
+ toJSON(): Record<string, unknown>;
439
+ }
440
+
441
+ export declare function updateCommand(options: UpdateCommandOptions): Promise<UpdateCommandResult>;
442
+
443
+ export declare type UpdateCommandOptions = {
444
+ cwd: string;
445
+ skills?: string[];
446
+ };
447
+
448
+ export declare type UpdateCommandResult = {
449
+ status: 'updated' | 'skipped' | 'failed';
450
+ updated: string[];
451
+ unchanged: string[];
452
+ skipped: Array<{
453
+ name: string;
454
+ reason: 'link-specifier';
455
+ }>;
456
+ failed: Array<{
457
+ name: string;
458
+ reason: string;
459
+ }>;
460
+ };
461
+
462
+ export declare function writeSkillsLock(rootDir: string, lockfile: SkillsLock): Promise<void>;
463
+
464
+ export declare function writeSkillsManifest(rootDir: string, manifest: SkillsManifest): Promise<void>;
465
+
466
+ export { }