skillpack 0.1.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 ADDED
@@ -0,0 +1,114 @@
1
+ # skillpack
2
+
3
+ A package manager for [skills.sh](https://skills.sh) that reads from a `skillpack.yaml` file and batch-installs skills to AI agents.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g skillpack
9
+ ```
10
+
11
+ Or run directly with npx:
12
+
13
+ ```bash
14
+ npx skillpack install
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ 1. Create a `skillpack.yaml` in your project:
20
+
21
+ ```bash
22
+ skillpack init
23
+ ```
24
+
25
+ 2. Edit the file to add your skills:
26
+
27
+ ```yaml
28
+ agents:
29
+ - claude-code
30
+ - cursor
31
+
32
+ skills:
33
+ vercel-labs/agent-skills:
34
+ - vercel-react-best-practices
35
+ - web-design-guidelines
36
+ ```
37
+
38
+ 3. Install all skills:
39
+
40
+ ```bash
41
+ skillpack install
42
+ ```
43
+
44
+ ## Configuration
45
+
46
+ ### skillpack.yaml
47
+
48
+ ```yaml
49
+ # Target agents to install skills to
50
+ agents:
51
+ - claude-code
52
+ - cursor
53
+
54
+ # Skills to install (owner/repo format)
55
+ skills:
56
+ # Install specific skills from a repo
57
+ vercel-labs/agent-skills:
58
+ - vercel-react-best-practices
59
+ - web-design-guidelines
60
+
61
+ # Install all skills from a repo
62
+ another-org/repo: all
63
+
64
+ # Pin to a specific git ref (tag, branch, or commit)
65
+ pinned-org/skill-repo:
66
+ ref: v1.0.0
67
+ skills:
68
+ - specific-skill
69
+ ```
70
+
71
+ ### Lockfile
72
+
73
+ Running `skillpack install` creates a `skillpack-lock.yaml` file that tracks installed versions. Commit this file to ensure reproducible installs across your team.
74
+
75
+ ## Commands
76
+
77
+ | Command | Description |
78
+ |---------|-------------|
79
+ | `skillpack install` | Install all skills from skillpack.yaml |
80
+ | `skillpack init` | Create a skillpack.yaml template |
81
+
82
+ ### Flags
83
+
84
+ ```bash
85
+ --dry-run # Show what would be installed without installing
86
+ --force # Reinstall even if already present
87
+ --verbose # Detailed output
88
+ --config <path> # Custom config file path
89
+ --no-lock # Ignore lockfile and install latest
90
+ ```
91
+
92
+ ## Examples
93
+
94
+ Preview what will be installed:
95
+
96
+ ```bash
97
+ skillpack install --dry-run
98
+ ```
99
+
100
+ Force reinstall all skills:
101
+
102
+ ```bash
103
+ skillpack install --force
104
+ ```
105
+
106
+ Use a custom config file:
107
+
108
+ ```bash
109
+ skillpack install --config ./configs/skills.yaml
110
+ ```
111
+
112
+ ## License
113
+
114
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { installCommand } from "./commands/install.js";
4
+ import { initCommand } from "./commands/init.js";
5
+ const program = new Command();
6
+ program
7
+ .name("skillpack")
8
+ .description("Package manager for skills.sh - batch install skills to AI agents")
9
+ .version("0.1.0");
10
+ program
11
+ .command("install")
12
+ .description("Install all skills from skillpack.yaml")
13
+ .option("--dry-run", "Show what would be installed without installing", false)
14
+ .option("--force", "Reinstall even if already present", false)
15
+ .option("--verbose", "Detailed output", false)
16
+ .option("--config <path>", "Custom config file path")
17
+ .option("--no-lock", "Ignore lockfile and install latest")
18
+ .action(async (opts) => {
19
+ const options = {
20
+ dryRun: opts.dryRun,
21
+ force: opts.force,
22
+ verbose: opts.verbose,
23
+ config: opts.config,
24
+ noLock: !opts.lock, // commander converts --no-lock to lock: false
25
+ };
26
+ await installCommand(options);
27
+ });
28
+ program
29
+ .command("init")
30
+ .description("Create a skillpack.yaml template")
31
+ .option("--force", "Overwrite existing skillpack.yaml", false)
32
+ .action(async (opts) => {
33
+ const options = {
34
+ force: opts.force,
35
+ };
36
+ await initCommand(options);
37
+ });
38
+ // Default to install if no command specified
39
+ program.action(async () => {
40
+ // Show help if no arguments
41
+ program.help();
42
+ });
43
+ program.parse();
44
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,mEAAmE,CAAC;KAChF,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,WAAW,EAAE,iDAAiD,EAAE,KAAK,CAAC;KAC7E,MAAM,CAAC,SAAS,EAAE,mCAAmC,EAAE,KAAK,CAAC;KAC7D,MAAM,CAAC,WAAW,EAAE,iBAAiB,EAAE,KAAK,CAAC;KAC7C,MAAM,CAAC,iBAAiB,EAAE,yBAAyB,CAAC;KACpD,MAAM,CAAC,WAAW,EAAE,oCAAoC,CAAC;KACzD,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,OAAO,GAAmB;QAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,8CAA8C;KACnE,CAAC;IACF,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,SAAS,EAAE,mCAAmC,EAAE,KAAK,CAAC;KAC7D,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,MAAM,OAAO,GAAgB;QAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC;IACF,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEL,6CAA6C;AAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;IACxB,4BAA4B;IAC5B,OAAO,CAAC,IAAI,EAAE,CAAC;AACjB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { InitOptions } from "../lib/types.js";
2
+ export declare function initCommand(options: InitOptions): Promise<void>;
3
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AASnD,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBrE"}
@@ -0,0 +1,57 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { dirname } from "node:path";
6
+ import { logger } from "../utils/logger.js";
7
+ const CONFIG_FILENAME = "skillpack.yaml";
8
+ // Get template path relative to this file
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const TEMPLATE_PATH = join(__dirname, "../../templates/skillpack.yaml");
11
+ export async function initCommand(options) {
12
+ const targetPath = join(process.cwd(), CONFIG_FILENAME);
13
+ // Check if file already exists
14
+ if (existsSync(targetPath) && !options.force) {
15
+ logger.warn(`${CONFIG_FILENAME} already exists. Use --force to overwrite.`);
16
+ process.exit(1);
17
+ }
18
+ // Read template and write to cwd
19
+ let template;
20
+ try {
21
+ template = await readFile(TEMPLATE_PATH, "utf-8");
22
+ }
23
+ catch {
24
+ // Fallback to inline template if file not found (e.g., during development)
25
+ template = getDefaultTemplate();
26
+ }
27
+ await writeFile(targetPath, template, "utf-8");
28
+ logger.success(`Created ${CONFIG_FILENAME}`);
29
+ logger.info("Edit the file to add your skills, then run: skillpack install");
30
+ }
31
+ function getDefaultTemplate() {
32
+ return `# skillpack.yaml - Package manager for skills.sh
33
+ # Run \`skillpack install\` to install all skills below
34
+
35
+ # Target agents to install skills to
36
+ agents:
37
+ - claude-code
38
+ # - cursor
39
+
40
+ # Skills to install (owner/repo format)
41
+ skills:
42
+ # Install specific skills from a repo
43
+ vercel-labs/agent-skills:
44
+ - vercel-react-best-practices
45
+ - web-design-guidelines
46
+
47
+ # Install all skills from a repo
48
+ # another-org/repo: all
49
+
50
+ # Pin to a specific git ref (tag, branch, or commit)
51
+ # pinned-org/skill-repo:
52
+ # ref: v1.0.0
53
+ # skills:
54
+ # - specific-skill
55
+ `;
56
+ }
57
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAEzC,0CAA0C;AAC1C,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1D,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,gCAAgC,CAAC,CAAC;AAExE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAoB;IACpD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;IAExD,+BAA+B;IAC/B,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,4CAA4C,CAAC,CAAC;QAC5E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,iCAAiC;IACjC,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,2EAA2E;QAC3E,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IAClC,CAAC;IAED,MAAM,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/C,MAAM,CAAC,OAAO,CAAC,WAAW,eAAe,EAAE,CAAC,CAAC;IAC7C,MAAM,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,kBAAkB;IACzB,OAAO;;;;;;;;;;;;;;;;;;;;;;;CAuBR,CAAC;AACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { InstallOptions } from "../lib/types.js";
2
+ export declare function installCommand(options: InstallOptions): Promise<void>;
3
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,iBAAiB,CAAC;AAG/E,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA2H3E"}
@@ -0,0 +1,108 @@
1
+ import { findConfigPath, loadConfig, parseSkillsToInstall } from "../lib/config.js";
2
+ import { getLockfilePath, readLockfile, createLockfile, updateLockfile, writeLockfile, isAlreadyInstalled, } from "../lib/lockfile.js";
3
+ import { installSkillEntry, getRepoCommit } from "../lib/skills-cli.js";
4
+ import { logger, createSpinner } from "../utils/logger.js";
5
+ export async function installCommand(options) {
6
+ // 1. Find config file
7
+ const configPath = options.config || findConfigPath();
8
+ if (!configPath) {
9
+ logger.error("No skillpack.yaml found.");
10
+ logger.info("Run 'skillpack init' to create one.");
11
+ process.exit(1);
12
+ }
13
+ logger.debug(`Using config: ${configPath}`, options.verbose);
14
+ // 2. Parse and validate config
15
+ let config;
16
+ try {
17
+ config = await loadConfig(configPath);
18
+ }
19
+ catch (err) {
20
+ logger.error(err instanceof Error ? err.message : String(err));
21
+ process.exit(1);
22
+ }
23
+ const skillsToInstall = parseSkillsToInstall(config);
24
+ if (skillsToInstall.length === 0) {
25
+ logger.warn("No skills defined in skillpack.yaml");
26
+ return;
27
+ }
28
+ logger.info(`Found ${skillsToInstall.length} skill source(s) for agents: ${config.agents.join(", ")}`);
29
+ // 3. Load lockfile (unless --no-lock)
30
+ const lockfilePath = getLockfilePath(configPath);
31
+ let lockfile = null;
32
+ if (!options.noLock) {
33
+ lockfile = await readLockfile(lockfilePath);
34
+ if (lockfile) {
35
+ logger.debug("Using existing lockfile", options.verbose);
36
+ }
37
+ }
38
+ // 4. Install each skill
39
+ const allResults = [];
40
+ let newLockfile = lockfile || createLockfile();
41
+ for (const skill of skillsToInstall) {
42
+ // Check if already installed (unless --force)
43
+ if (!options.force &&
44
+ isAlreadyInstalled(lockfile, skill.repo, skill.skills, skill.agents)) {
45
+ const skillNames = skill.skills === "all" ? "all skills" : skill.skills.join(", ");
46
+ logger.info(`Skipping ${skill.repo} (${skillNames}) - already installed`);
47
+ allResults.push({
48
+ repo: skill.repo,
49
+ skill: skillNames,
50
+ status: "skipped",
51
+ message: "already in lockfile",
52
+ });
53
+ continue;
54
+ }
55
+ const skillNames = skill.skills === "all" ? "all skills" : skill.skills.join(", ");
56
+ const spinner = createSpinner(`Installing ${skill.repo} (${skillNames})`);
57
+ if (!options.dryRun) {
58
+ spinner.start();
59
+ }
60
+ const results = await installSkillEntry(skill, {
61
+ dryRun: options.dryRun,
62
+ verbose: options.verbose,
63
+ });
64
+ allResults.push(...results);
65
+ // Update spinner based on results
66
+ const failed = results.filter((r) => r.status === "failed");
67
+ const installed = results.filter((r) => r.status === "installed");
68
+ if (!options.dryRun) {
69
+ if (failed.length > 0) {
70
+ spinner.fail(`Failed: ${skill.repo}`);
71
+ for (const f of failed) {
72
+ logger.error(` ${f.skill}: ${f.message}`);
73
+ }
74
+ }
75
+ else if (installed.length > 0) {
76
+ spinner.succeed(`Installed ${skill.repo}`);
77
+ }
78
+ else {
79
+ spinner.info(`Skipped ${skill.repo}`);
80
+ }
81
+ }
82
+ // Update lockfile with successful installations
83
+ if (!options.dryRun && installed.length > 0) {
84
+ const commit = await getRepoCommit(skill.repo);
85
+ newLockfile = updateLockfile(newLockfile, skill.repo, {
86
+ commit,
87
+ skills: skill.skills === "all" ? [] : skill.skills,
88
+ agents: skill.agents,
89
+ installedAt: new Date().toISOString(),
90
+ });
91
+ }
92
+ }
93
+ // 5. Write updated lockfile
94
+ if (!options.dryRun && !options.noLock) {
95
+ await writeLockfile(lockfilePath, newLockfile);
96
+ logger.debug(`Updated ${lockfilePath}`, options.verbose);
97
+ }
98
+ // 6. Print summary
99
+ const installed = allResults.filter((r) => r.status === "installed").length;
100
+ const skipped = allResults.filter((r) => r.status === "skipped").length;
101
+ const failed = allResults.filter((r) => r.status === "failed").length;
102
+ logger.summary(installed, skipped, failed);
103
+ // Exit with error if any failed
104
+ if (failed > 0) {
105
+ process.exit(1);
106
+ }
107
+ }
108
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACpF,OAAO,EACL,eAAe,EACf,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAExE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB;IAC1D,sBAAsB;IACtB,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;IACtD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,iBAAiB,UAAU,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7D,+BAA+B;IAC/B,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,eAAe,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACrD,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IAED,MAAM,CAAC,IAAI,CACT,SAAS,eAAe,CAAC,MAAM,gCAAgC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC1F,CAAC;IAEF,sCAAsC;IACtC,MAAM,YAAY,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,QAAQ,GAAoB,IAAI,CAAC;IACrC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,QAAQ,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,CAAC;QAC5C,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,MAAM,UAAU,GAAoB,EAAE,CAAC;IACvC,IAAI,WAAW,GAAG,QAAQ,IAAI,cAAc,EAAE,CAAC;IAE/C,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,8CAA8C;QAC9C,IACE,CAAC,OAAO,CAAC,KAAK;YACd,kBAAkB,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EACpE,CAAC;YACD,MAAM,UAAU,GACd,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,YAAY,KAAK,CAAC,IAAI,KAAK,UAAU,uBAAuB,CAAC,CAAC;YAC1E,UAAU,CAAC,IAAI,CAAC;gBACd,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,UAAU;gBACjB,MAAM,EAAE,SAAS;gBACjB,OAAO,EAAE,qBAAqB;aAC/B,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GACd,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,aAAa,CAAC,cAAc,KAAK,CAAC,IAAI,KAAK,UAAU,GAAG,CAAC,CAAC;QAE1E,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE;YAC7C,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,CAAC,CAAC;QAEH,UAAU,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;QAE5B,kCAAkC;QAClC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;QAElE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;gBACtC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;oBACvB,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC7C,CAAC;YACH,CAAC;iBAAM,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,OAAO,CAAC,OAAO,CAAC,aAAa,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,WAAW,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QAED,gDAAgD;QAChD,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/C,WAAW,GAAG,cAAc,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE;gBACpD,MAAM;gBACN,MAAM,EAAE,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;gBAClD,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACtC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QACvC,MAAM,aAAa,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC,WAAW,YAAY,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED,mBAAmB;IACnB,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,MAAM,CAAC;IAC5E,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IACxE,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IAEtE,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAE3C,gCAAgC;IAChC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type SkillpackConfig, type SkillToInstall } from "./types.js";
2
+ /**
3
+ * Find skillpack.yaml by walking up from cwd
4
+ */
5
+ export declare function findConfigPath(startDir?: string): string | null;
6
+ /**
7
+ * Parse and validate skillpack.yaml
8
+ */
9
+ export declare function loadConfig(configPath: string): Promise<SkillpackConfig>;
10
+ /**
11
+ * Transform config into normalized list of skills to install
12
+ */
13
+ export declare function parseSkillsToInstall(config: SkillpackConfig): SkillToInstall[];
14
+ /**
15
+ * Validate repo format (owner/repo)
16
+ */
17
+ export declare function isValidRepoFormat(repo: string): boolean;
18
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,eAAe,EAEpB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAIpB;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAmB9E;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAuB7E;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,cAAc,EAAE,CAmB9E;AASD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD"}
@@ -0,0 +1,86 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { parse as parseYaml } from "yaml";
5
+ import { ZodError } from "zod";
6
+ import { SkillpackConfigSchema, } from "./types.js";
7
+ const CONFIG_FILENAME = "skillpack.yaml";
8
+ /**
9
+ * Find skillpack.yaml by walking up from cwd
10
+ */
11
+ export function findConfigPath(startDir = process.cwd()) {
12
+ let dir = resolve(startDir);
13
+ const root = dirname(dir);
14
+ while (dir !== root) {
15
+ const configPath = join(dir, CONFIG_FILENAME);
16
+ if (existsSync(configPath)) {
17
+ return configPath;
18
+ }
19
+ dir = dirname(dir);
20
+ }
21
+ // Check root as well
22
+ const rootConfig = join(root, CONFIG_FILENAME);
23
+ if (existsSync(rootConfig)) {
24
+ return rootConfig;
25
+ }
26
+ return null;
27
+ }
28
+ /**
29
+ * Parse and validate skillpack.yaml
30
+ */
31
+ export async function loadConfig(configPath) {
32
+ const content = await readFile(configPath, "utf-8");
33
+ let parsed;
34
+ try {
35
+ parsed = parseYaml(content);
36
+ }
37
+ catch (err) {
38
+ const msg = err instanceof Error ? err.message : String(err);
39
+ throw new Error(`Failed to parse YAML: ${msg}`);
40
+ }
41
+ try {
42
+ return SkillpackConfigSchema.parse(parsed);
43
+ }
44
+ catch (err) {
45
+ if (err instanceof ZodError) {
46
+ const issues = err.issues.map((issue) => {
47
+ const path = issue.path.join(".");
48
+ return ` - ${path}: ${issue.message}`;
49
+ });
50
+ throw new Error(`Invalid skillpack.yaml:\n${issues.join("\n")}`);
51
+ }
52
+ throw err;
53
+ }
54
+ }
55
+ /**
56
+ * Transform config into normalized list of skills to install
57
+ */
58
+ export function parseSkillsToInstall(config) {
59
+ const result = [];
60
+ for (const [repo, entry] of Object.entries(config.skills)) {
61
+ const item = {
62
+ repo,
63
+ skills: resolveSkillsList(entry),
64
+ agents: config.agents,
65
+ };
66
+ // Extract ref if present
67
+ if (typeof entry === "object" && entry !== null && "ref" in entry) {
68
+ item.ref = entry.ref;
69
+ }
70
+ result.push(item);
71
+ }
72
+ return result;
73
+ }
74
+ function resolveSkillsList(entry) {
75
+ if (entry === "all") {
76
+ return "all";
77
+ }
78
+ return entry.skills;
79
+ }
80
+ /**
81
+ * Validate repo format (owner/repo)
82
+ */
83
+ export function isValidRepoFormat(repo) {
84
+ return /^[\w-]+\/[\w-]+$/.test(repo);
85
+ }
86
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { type Lockfile, type LockfileInstallation } from "./types.js";
2
+ /**
3
+ * Get lockfile path relative to config path
4
+ */
5
+ export declare function getLockfilePath(configPath: string): string;
6
+ /**
7
+ * Read and parse existing lockfile, or return null if not found
8
+ */
9
+ export declare function readLockfile(lockfilePath: string): Promise<Lockfile | null>;
10
+ /**
11
+ * Create a new empty lockfile
12
+ */
13
+ export declare function createLockfile(): Lockfile;
14
+ /**
15
+ * Update lockfile with new installation
16
+ */
17
+ export declare function updateLockfile(lockfile: Lockfile, repo: string, installation: LockfileInstallation): Lockfile;
18
+ /**
19
+ * Write lockfile to disk
20
+ */
21
+ export declare function writeLockfile(lockfilePath: string, lockfile: Lockfile): Promise<void>;
22
+ /**
23
+ * Check if a repo+skills combo is already installed with same commit
24
+ */
25
+ export declare function isAlreadyInstalled(lockfile: Lockfile | null, repo: string, skills: string[] | "all", agents: string[]): boolean;
26
+ //# sourceMappingURL=lockfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lockfile.d.ts","sourceRoot":"","sources":["../../src/lib/lockfile.ts"],"names":[],"mappings":"AAIA,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAItF;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAgBjF;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,QAAQ,CAKzC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,oBAAoB,GACjC,QAAQ,CAQV;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,EACxB,MAAM,EAAE,MAAM,EAAE,GACf,OAAO,CAmBT"}
@@ -0,0 +1,85 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
5
+ import { LockfileSchema } from "./types.js";
6
+ const LOCKFILE_NAME = "skillpack-lock.yaml";
7
+ /**
8
+ * Get lockfile path relative to config path
9
+ */
10
+ export function getLockfilePath(configPath) {
11
+ return join(dirname(configPath), LOCKFILE_NAME);
12
+ }
13
+ /**
14
+ * Read and parse existing lockfile, or return null if not found
15
+ */
16
+ export async function readLockfile(lockfilePath) {
17
+ if (!existsSync(lockfilePath)) {
18
+ return null;
19
+ }
20
+ const content = await readFile(lockfilePath, "utf-8");
21
+ const parsed = parseYaml(content);
22
+ // Validate with schema
23
+ const result = LockfileSchema.safeParse(parsed);
24
+ if (!result.success) {
25
+ // Invalid lockfile, treat as if it doesn't exist
26
+ return null;
27
+ }
28
+ return result.data;
29
+ }
30
+ /**
31
+ * Create a new empty lockfile
32
+ */
33
+ export function createLockfile() {
34
+ return {
35
+ generated: new Date().toISOString(),
36
+ installations: {},
37
+ };
38
+ }
39
+ /**
40
+ * Update lockfile with new installation
41
+ */
42
+ export function updateLockfile(lockfile, repo, installation) {
43
+ return {
44
+ generated: new Date().toISOString(),
45
+ installations: {
46
+ ...lockfile.installations,
47
+ [repo]: installation,
48
+ },
49
+ };
50
+ }
51
+ /**
52
+ * Write lockfile to disk
53
+ */
54
+ export async function writeLockfile(lockfilePath, lockfile) {
55
+ const header = "# Auto-generated by skillpack. Commit this file to git.\n\n";
56
+ const content = header + stringifyYaml(lockfile, {
57
+ lineWidth: 0, // Don't wrap lines
58
+ defaultStringType: "QUOTE_DOUBLE",
59
+ defaultKeyType: "PLAIN",
60
+ });
61
+ await writeFile(lockfilePath, content, "utf-8");
62
+ }
63
+ /**
64
+ * Check if a repo+skills combo is already installed with same commit
65
+ */
66
+ export function isAlreadyInstalled(lockfile, repo, skills, agents) {
67
+ if (!lockfile)
68
+ return false;
69
+ const existing = lockfile.installations[repo];
70
+ if (!existing)
71
+ return false;
72
+ // Check if all agents are covered
73
+ const allAgentsCovered = agents.every((a) => existing.agents.includes(a));
74
+ if (!allAgentsCovered)
75
+ return false;
76
+ // If requesting "all", check if we installed "all" (we track this as empty array)
77
+ if (skills === "all") {
78
+ // We can't know for sure without re-fetching, so be conservative
79
+ return false;
80
+ }
81
+ // Check if all requested skills are installed
82
+ const allSkillsCovered = skills.every((s) => existing.skills.includes(s));
83
+ return allSkillsCovered;
84
+ }
85
+ //# sourceMappingURL=lockfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../../src/lib/lockfile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { SkillToInstall, InstallResult } from "./types.js";
2
+ interface SkillsAddOptions {
3
+ dryRun: boolean;
4
+ verbose: boolean;
5
+ }
6
+ /**
7
+ * Build the npx skills add command arguments
8
+ */
9
+ export declare function buildSkillsCommand(skill: SkillToInstall): string[];
10
+ /**
11
+ * Execute a single skill installation
12
+ */
13
+ export declare function installSkill(skill: SkillToInstall, specificSkill: string | null, // null means install all from the skill.skills list
14
+ options: SkillsAddOptions): Promise<InstallResult>;
15
+ /**
16
+ * Install all skills from a skill entry
17
+ */
18
+ export declare function installSkillEntry(skill: SkillToInstall, options: SkillsAddOptions): Promise<InstallResult[]>;
19
+ /**
20
+ * Get the current commit of a cloned repo (for lockfile)
21
+ * This would require fetching repo info; for now return a placeholder
22
+ */
23
+ export declare function getRepoCommit(_repo: string): Promise<string>;
24
+ export {};
25
+ //# sourceMappingURL=skills-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-cli.d.ts","sourceRoot":"","sources":["../../src/lib/skills-cli.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhE,UAAU,gBAAgB;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,EAAE,CAgBlE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,cAAc,EACrB,aAAa,EAAE,MAAM,GAAG,IAAI,EAAE,oDAAoD;AAClF,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,aAAa,CAAC,CAiExB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,aAAa,EAAE,CAAC,CAgB1B;AAmBD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIlE"}
@@ -0,0 +1,124 @@
1
+ import { execa } from "execa";
2
+ import { logger } from "../utils/logger.js";
3
+ const MAX_RETRIES = 1;
4
+ /**
5
+ * Build the npx skills add command arguments
6
+ */
7
+ export function buildSkillsCommand(skill) {
8
+ const args = ["skills", "add", skill.repo, "-y"];
9
+ // Add agents
10
+ for (const agent of skill.agents) {
11
+ args.push("-a", agent);
12
+ }
13
+ // Add specific skills (omit for "all")
14
+ if (skill.skills !== "all") {
15
+ for (const s of skill.skills) {
16
+ args.push("-s", s);
17
+ }
18
+ }
19
+ return args;
20
+ }
21
+ /**
22
+ * Execute a single skill installation
23
+ */
24
+ export async function installSkill(skill, specificSkill, // null means install all from the skill.skills list
25
+ options) {
26
+ const skillName = specificSkill ?? (skill.skills === "all" ? "all" : skill.skills.join(", "));
27
+ const repo = skill.repo;
28
+ // Build command for this specific skill or all
29
+ const baseArgs = ["skills", "add", repo, "-y"];
30
+ // Add agents
31
+ for (const agent of skill.agents) {
32
+ baseArgs.push("-a", agent);
33
+ }
34
+ // Add specific skill if provided
35
+ if (specificSkill) {
36
+ baseArgs.push("-s", specificSkill);
37
+ }
38
+ else if (skill.skills !== "all") {
39
+ // Multiple skills at once
40
+ for (const s of skill.skills) {
41
+ baseArgs.push("-s", s);
42
+ }
43
+ }
44
+ if (options.dryRun) {
45
+ logger.info(`Would run: npx ${baseArgs.join(" ")}`);
46
+ return { repo, skill: skillName, status: "skipped", message: "dry run" };
47
+ }
48
+ logger.debug(`Running: npx ${baseArgs.join(" ")}`, options.verbose);
49
+ // Execute with retry
50
+ let lastError;
51
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
52
+ try {
53
+ const execaOpts = {
54
+ reject: false,
55
+ timeout: 120_000, // 2 minute timeout
56
+ };
57
+ const result = await execa("npx", baseArgs, execaOpts);
58
+ if (result.exitCode === 0) {
59
+ return { repo, skill: skillName, status: "installed" };
60
+ }
61
+ // Check for "already installed" pattern
62
+ const stdout = String(result.stdout ?? "");
63
+ const stderr = String(result.stderr ?? "");
64
+ const output = stdout + stderr;
65
+ if (output.includes("already installed") || output.includes("Already installed")) {
66
+ return { repo, skill: skillName, status: "skipped", message: "already installed" };
67
+ }
68
+ lastError = stderr || stdout || `Exit code ${result.exitCode}`;
69
+ }
70
+ catch (err) {
71
+ lastError = err instanceof Error ? err.message : String(err);
72
+ }
73
+ // Retry on network errors
74
+ if (attempt < MAX_RETRIES && isRetryableError(lastError)) {
75
+ logger.debug(`Retrying ${skillName} (attempt ${attempt + 2})...`, options.verbose);
76
+ await sleep(1000);
77
+ }
78
+ }
79
+ return { repo, skill: skillName, status: "failed", message: lastError };
80
+ }
81
+ /**
82
+ * Install all skills from a skill entry
83
+ */
84
+ export async function installSkillEntry(skill, options) {
85
+ // For "all" or when installing multiple skills at once,
86
+ // we run a single command and track it as one result
87
+ if (skill.skills === "all") {
88
+ const result = await installSkill(skill, null, options);
89
+ return [result];
90
+ }
91
+ // For multiple specific skills, we can run them together in one command
92
+ const result = await installSkill(skill, null, options);
93
+ // Return one result per skill for better granularity in the summary
94
+ return skill.skills.map((s) => ({
95
+ ...result,
96
+ skill: s,
97
+ }));
98
+ }
99
+ function isRetryableError(error) {
100
+ if (!error)
101
+ return false;
102
+ const retryablePatterns = [
103
+ "ECONNRESET",
104
+ "ETIMEDOUT",
105
+ "ENOTFOUND",
106
+ "network",
107
+ "timeout",
108
+ "fetch failed",
109
+ ];
110
+ return retryablePatterns.some((p) => error.toLowerCase().includes(p.toLowerCase()));
111
+ }
112
+ function sleep(ms) {
113
+ return new Promise((resolve) => setTimeout(resolve, ms));
114
+ }
115
+ /**
116
+ * Get the current commit of a cloned repo (for lockfile)
117
+ * This would require fetching repo info; for now return a placeholder
118
+ */
119
+ export async function getRepoCommit(_repo) {
120
+ // TODO: In a full implementation, we'd fetch the actual commit SHA
121
+ // For now, use a timestamp-based identifier
122
+ return `installed-${Date.now()}`;
123
+ }
124
+ //# sourceMappingURL=skills-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-cli.js","sourceRoot":"","sources":["../../src/lib/skills-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ import { z } from "zod";
2
+ declare const SkillEntrySchema: z.ZodEffects<z.ZodUnion<[z.ZodLiteral<"all">, z.ZodObject<{
3
+ ref: z.ZodOptional<z.ZodString>;
4
+ skills: z.ZodArray<z.ZodString, "many">;
5
+ }, "strip", z.ZodTypeAny, {
6
+ skills: string[];
7
+ ref?: string | undefined;
8
+ }, {
9
+ skills: string[];
10
+ ref?: string | undefined;
11
+ }>]>, "all" | {
12
+ skills: string[];
13
+ ref?: string | undefined;
14
+ }, unknown>;
15
+ export type SkillEntry = z.infer<typeof SkillEntrySchema>;
16
+ export declare const SkillpackConfigSchema: z.ZodObject<{
17
+ agents: z.ZodArray<z.ZodString, "many">;
18
+ skills: z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodUnion<[z.ZodLiteral<"all">, z.ZodObject<{
19
+ ref: z.ZodOptional<z.ZodString>;
20
+ skills: z.ZodArray<z.ZodString, "many">;
21
+ }, "strip", z.ZodTypeAny, {
22
+ skills: string[];
23
+ ref?: string | undefined;
24
+ }, {
25
+ skills: string[];
26
+ ref?: string | undefined;
27
+ }>]>, "all" | {
28
+ skills: string[];
29
+ ref?: string | undefined;
30
+ }, unknown>>;
31
+ }, "strip", z.ZodTypeAny, {
32
+ skills: Record<string, "all" | {
33
+ skills: string[];
34
+ ref?: string | undefined;
35
+ }>;
36
+ agents: string[];
37
+ }, {
38
+ skills: Record<string, unknown>;
39
+ agents: string[];
40
+ }>;
41
+ export type SkillpackConfig = z.infer<typeof SkillpackConfigSchema>;
42
+ declare const LockfileInstallationSchema: z.ZodObject<{
43
+ commit: z.ZodString;
44
+ skills: z.ZodArray<z.ZodString, "many">;
45
+ agents: z.ZodArray<z.ZodString, "many">;
46
+ installedAt: z.ZodOptional<z.ZodString>;
47
+ }, "strip", z.ZodTypeAny, {
48
+ skills: string[];
49
+ agents: string[];
50
+ commit: string;
51
+ installedAt?: string | undefined;
52
+ }, {
53
+ skills: string[];
54
+ agents: string[];
55
+ commit: string;
56
+ installedAt?: string | undefined;
57
+ }>;
58
+ export type LockfileInstallation = z.infer<typeof LockfileInstallationSchema>;
59
+ export declare const LockfileSchema: z.ZodObject<{
60
+ generated: z.ZodString;
61
+ installations: z.ZodRecord<z.ZodString, z.ZodObject<{
62
+ commit: z.ZodString;
63
+ skills: z.ZodArray<z.ZodString, "many">;
64
+ agents: z.ZodArray<z.ZodString, "many">;
65
+ installedAt: z.ZodOptional<z.ZodString>;
66
+ }, "strip", z.ZodTypeAny, {
67
+ skills: string[];
68
+ agents: string[];
69
+ commit: string;
70
+ installedAt?: string | undefined;
71
+ }, {
72
+ skills: string[];
73
+ agents: string[];
74
+ commit: string;
75
+ installedAt?: string | undefined;
76
+ }>>;
77
+ }, "strip", z.ZodTypeAny, {
78
+ generated: string;
79
+ installations: Record<string, {
80
+ skills: string[];
81
+ agents: string[];
82
+ commit: string;
83
+ installedAt?: string | undefined;
84
+ }>;
85
+ }, {
86
+ generated: string;
87
+ installations: Record<string, {
88
+ skills: string[];
89
+ agents: string[];
90
+ commit: string;
91
+ installedAt?: string | undefined;
92
+ }>;
93
+ }>;
94
+ export type Lockfile = z.infer<typeof LockfileSchema>;
95
+ export interface SkillToInstall {
96
+ repo: string;
97
+ skills: string[] | "all";
98
+ ref?: string;
99
+ agents: string[];
100
+ }
101
+ export interface InstallResult {
102
+ repo: string;
103
+ skill: string;
104
+ status: "installed" | "skipped" | "failed";
105
+ message?: string;
106
+ }
107
+ export interface InstallOptions {
108
+ dryRun: boolean;
109
+ force: boolean;
110
+ verbose: boolean;
111
+ config: string;
112
+ noLock: boolean;
113
+ }
114
+ export interface InitOptions {
115
+ force: boolean;
116
+ }
117
+ export {};
118
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,QAAA,MAAM,gBAAgB;;;;;;;;;;;;WAerB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAG1D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;EAGhC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAGpE,QAAA,MAAM,0BAA0B;;;;;;;;;;;;;;;EAK9B,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAGtD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAGD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAC;CAChB"}
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ // Schema for individual skill entry in config
3
+ // Can be:
4
+ // - "all" (install all skills from repo)
5
+ // - ["skill1", "skill2"] (list of skill names)
6
+ // - { ref: "v1.0.0", skills: ["skill1"] } (pinned version)
7
+ const SkillEntrySchema = z.preprocess((val) => {
8
+ // Normalize array shorthand to object form
9
+ if (Array.isArray(val)) {
10
+ return { skills: val };
11
+ }
12
+ return val;
13
+ }, z.union([
14
+ z.literal("all"),
15
+ z.object({
16
+ ref: z.string().optional(),
17
+ skills: z.array(z.string()).min(1),
18
+ }),
19
+ ]));
20
+ // Main skillpack.yaml schema
21
+ export const SkillpackConfigSchema = z.object({
22
+ agents: z.array(z.string()).min(1, "At least one agent must be specified"),
23
+ skills: z.record(z.string(), SkillEntrySchema),
24
+ });
25
+ // Lockfile schema for tracking installed versions
26
+ const LockfileInstallationSchema = z.object({
27
+ commit: z.string(),
28
+ skills: z.array(z.string()),
29
+ agents: z.array(z.string()),
30
+ installedAt: z.string().optional(),
31
+ });
32
+ export const LockfileSchema = z.object({
33
+ generated: z.string(),
34
+ installations: z.record(z.string(), LockfileInstallationSchema),
35
+ });
36
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,8CAA8C;AAC9C,UAAU;AACV,yCAAyC;AACzC,+CAA+C;AAC/C,2DAA2D;AAC3D,MAAM,gBAAgB,GAAG,CAAC,CAAC,UAAU,CACnC,CAAC,GAAG,EAAE,EAAE;IACN,2CAA2C;IAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACzB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,EACD,CAAC,CAAC,KAAK,CAAC;IACN,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAChB,CAAC,CAAC,MAAM,CAAC;QACP,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC1B,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;KACnC,CAAC;CACH,CAAC,CACH,CAAC;AAIF,6BAA6B;AAC7B,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,sCAAsC,CAAC;IAC1E,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC;CAC/C,CAAC,CAAC;AAIH,kDAAkD;AAClD,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC3B,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC3B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,0BAA0B,CAAC;CAChE,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type Ora } from "ora";
2
+ export declare const logger: {
3
+ info: (msg: string) => void;
4
+ success: (msg: string) => void;
5
+ warn: (msg: string) => void;
6
+ error: (msg: string) => void;
7
+ debug: (msg: string, verbose: boolean) => void;
8
+ bold: (text: string) => string;
9
+ dim: (text: string) => string;
10
+ cyan: (text: string) => string;
11
+ green: (text: string) => string;
12
+ yellow: (text: string) => string;
13
+ red: (text: string) => string;
14
+ summary: (installed: number, skipped: number, failed: number) => void;
15
+ blank: () => void;
16
+ };
17
+ export declare function createSpinner(text: string): Ora;
18
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AACA,OAAY,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAEpC,eAAO,MAAM,MAAM;gBACL,MAAM;mBACH,MAAM;gBACT,MAAM;iBACL,MAAM;iBACN,MAAM,WAAW,OAAO;iBAKxB,MAAM;gBACP,MAAM;iBACL,MAAM;kBACL,MAAM;mBACL,MAAM;gBACT,MAAM;yBAGG,MAAM,WAAW,MAAM,UAAU,MAAM;;CAU7D,CAAC;AAGF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAE/C"}
@@ -0,0 +1,37 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+ export const logger = {
4
+ info: (msg) => console.log(chalk.blue("ℹ"), msg),
5
+ success: (msg) => console.log(chalk.green("✓"), msg),
6
+ warn: (msg) => console.log(chalk.yellow("⚠"), msg),
7
+ error: (msg) => console.error(chalk.red("✗"), msg),
8
+ debug: (msg, verbose) => {
9
+ if (verbose)
10
+ console.log(chalk.gray(" →"), chalk.gray(msg));
11
+ },
12
+ // Styled text helpers
13
+ bold: (text) => chalk.bold(text),
14
+ dim: (text) => chalk.dim(text),
15
+ cyan: (text) => chalk.cyan(text),
16
+ green: (text) => chalk.green(text),
17
+ yellow: (text) => chalk.yellow(text),
18
+ red: (text) => chalk.red(text),
19
+ // Summary formatting
20
+ summary: (installed, skipped, failed) => {
21
+ const parts = [];
22
+ if (installed > 0)
23
+ parts.push(chalk.green(`${installed} installed`));
24
+ if (skipped > 0)
25
+ parts.push(chalk.yellow(`${skipped} skipped`));
26
+ if (failed > 0)
27
+ parts.push(chalk.red(`${failed} failed`));
28
+ console.log("\n" + chalk.bold("Summary:"), parts.join(", "));
29
+ },
30
+ // Blank line
31
+ blank: () => console.log(),
32
+ };
33
+ // Spinner factory
34
+ export function createSpinner(text) {
35
+ return ora({ text, color: "cyan" });
36
+ }
37
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAiB,MAAM,KAAK,CAAC;AAEpC,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACxD,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC5D,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC1D,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC1D,KAAK,EAAE,CAAC,GAAW,EAAE,OAAgB,EAAE,EAAE;QACvC,IAAI,OAAO;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,sBAAsB;IACtB,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IACxC,GAAG,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IACtC,IAAI,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IACxC,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;IAC1C,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC;IAC5C,GAAG,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IAEtC,qBAAqB;IACrB,OAAO,EAAE,CAAC,SAAiB,EAAE,OAAe,EAAE,MAAc,EAAE,EAAE;QAC9D,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,SAAS,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,SAAS,YAAY,CAAC,CAAC,CAAC;QACrE,IAAI,OAAO,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,OAAO,UAAU,CAAC,CAAC,CAAC;QAChE,IAAI,MAAM,GAAG,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,aAAa;IACb,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;CAC3B,CAAC;AAEF,kBAAkB;AAClB,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "skillpack",
3
+ "version": "0.1.0",
4
+ "description": "Package manager for skills.sh - batch install skills to AI agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "skillpack": "./dist/cli.js"
8
+ },
9
+ "main": "./dist/cli.js",
10
+ "files": [
11
+ "dist",
12
+ "templates"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/joventuraz/skillpack.git"
17
+ },
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "dev": "tsc --watch",
21
+ "start": "node dist/cli.js",
22
+ "typecheck": "tsc --noEmit",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "keywords": [
28
+ "skills",
29
+ "ai",
30
+ "claude",
31
+ "cursor",
32
+ "package-manager",
33
+ "cli"
34
+ ],
35
+ "author": "",
36
+ "license": "MIT",
37
+ "dependencies": {
38
+ "chalk": "^5.3.0",
39
+ "commander": "^12.1.0",
40
+ "execa": "^9.5.2",
41
+ "ora": "^8.1.1",
42
+ "yaml": "^2.7.0",
43
+ "zod": "^3.24.2"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^22.10.7",
47
+ "typescript": "^5.7.3",
48
+ "vitest": "^4.0.18"
49
+ },
50
+ "engines": {
51
+ "node": ">=18"
52
+ }
53
+ }
@@ -0,0 +1,23 @@
1
+ # skillpack.yaml - Package manager for skills.sh
2
+ # Run `skillpack install` to install all skills below
3
+
4
+ # Target agents to install skills to
5
+ agents:
6
+ - claude-code
7
+ # - cursor
8
+
9
+ # Skills to install (owner/repo format)
10
+ skills:
11
+ # Install specific skills from a repo
12
+ vercel-labs/agent-skills:
13
+ - vercel-react-best-practices
14
+ - web-design-guidelines
15
+
16
+ # Install all skills from a repo
17
+ # another-org/repo: all
18
+
19
+ # Pin to a specific git ref (tag, branch, or commit)
20
+ # pinned-org/skill-repo:
21
+ # ref: v1.0.0
22
+ # skills:
23
+ # - specific-skill