add-skill-kit 1.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.
package/README.md ADDED
@@ -0,0 +1,194 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/agentskillkit/add-skill-kit/main/.github/logo.svg" height="128">
3
+ <h1 align="center">add-skill-kit</h1>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <a href="https://www.npmjs.com/package/add-skill-kit"><img src="https://img.shields.io/npm/v/add-skill-kit?style=flat&colorA=18181b&colorB=7c3aed" alt="npm version"></a>
8
+ <a href="https://www.npmjs.com/package/add-skill-kit"><img src="https://img.shields.io/npm/d18m/add-skill-kit?style=flat&colorA=18181b&colorB=7c3aed" alt="npm downloads"></a>
9
+ <a href="https://github.com/agentskillkit/add-skill-kit/blob/main/LICENSE"><img src="https://img.shields.io/github/license/agentskillkit/add-skill-kit?style=flat&colorA=18181b&colorB=7c3aed" alt="license"></a>
10
+ </p>
11
+
12
+ <p align="center">
13
+ The enterprise-grade package manager for AI Agent Skills.<br/>
14
+ Designed for the <strong>Antigravity Skills</strong> specification.
15
+ </p>
16
+
17
+ <p align="center">
18
+ <a href="#installation">Installation</a> •
19
+ <a href="#quick-start">Quick Start</a> •
20
+ <a href="#commands">Commands</a> •
21
+ <a href="#features">Features</a> •
22
+ <a href="#documentation">Docs</a>
23
+ </p>
24
+
25
+ ---
26
+
27
+ ## What is add-skill-kit?
28
+
29
+ `add-skill-kit` is a CLI tool for managing **Agent Skills**—immutable, verifiable intelligence artifacts that extend your AI agent's capabilities. Think of it as `npm` for AI agents.
30
+
31
+ ```bash
32
+ npx add-skill-kit agentskillkit/agent-skills
33
+ ```
34
+
35
+ Skills are **data, not code**. They won't execute on your system—they're read by your agent to enhance its behavior.
36
+
37
+ ---
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ # Using npm
43
+ npm install -g add-skill-kit
44
+
45
+ # Using pnpm
46
+ pnpm add -g add-skill-kit
47
+
48
+ # Using Yarn
49
+ yarn global add add-skill-kit
50
+
51
+ # Or run directly with npx
52
+ npx add-skill-kit <command>
53
+ ```
54
+
55
+ > **Requirements:** Node.js 18.0.0 or later
56
+
57
+ ---
58
+
59
+ ## Quick Start
60
+
61
+ ### 1. Initialize your workspace
62
+
63
+ ```bash
64
+ npx add-skill-kit init
65
+ ```
66
+
67
+ This creates the `.agent/skills` directory structure in your project.
68
+
69
+ ### 2. Install a skill
70
+
71
+ Install from GitHub with optional version pinning:
72
+
73
+ ```bash
74
+ # Latest version
75
+ npx add-skill-kit agentskillkit/agent-skills
76
+
77
+ # Specific skill
78
+ npx add-skill-kit agentskillkit/agent-skills#react-patterns
79
+
80
+ # Specific version
81
+ npx add-skill-kit agentskillkit/agent-skills#react-patterns@v1.0.0
82
+ ```
83
+
84
+ ### 3. List installed skills
85
+
86
+ ```bash
87
+ npx add-skill-kit list
88
+ ```
89
+
90
+ ### 4. Validate compliance
91
+
92
+ ```bash
93
+ npx add-skill-kit validate
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Commands
99
+
100
+ | Command | Description |
101
+ | :--- | :--- |
102
+ | `init` | Initialize `.agent/skills` workspace |
103
+ | `install <spec>` | Install a skill from GitHub or registry |
104
+ | `uninstall <name>` | Remove an installed skill |
105
+ | `update <name>` | Update a skill to latest version |
106
+ | `upgrade-all` | Upgrade all skills in workspace |
107
+ | `list` | List installed skills with metadata |
108
+ | `validate` | Check Antigravity compliance |
109
+ | `analyze <name>` | Inspect skill structure & Progressive Disclosure |
110
+ | `doctor` | Check health & integrity |
111
+ | `lock` | Generate `skill-lock.json` |
112
+ | `cache clear` | Clear local cache |
113
+
114
+ ---
115
+
116
+ ## Features
117
+
118
+ ### Progressive Disclosure
119
+
120
+ Skills follow a structured hierarchy that lets agents read only what they need:
121
+
122
+ ```
123
+ skill/
124
+ ├── SKILL.md # Core instructions (always read)
125
+ ├── resources/ # Reference materials (on-demand)
126
+ ├── examples/ # Implementation patterns (when coding)
127
+ ├── scripts/ # Helper utilities (when needed)
128
+ ├── constitution/ # Governing rules
129
+ └── doctrines/ # Behavioral policies
130
+ ```
131
+
132
+ ### Deterministic Locking
133
+
134
+ Pin exact versions for reproducible builds across your team:
135
+
136
+ ```bash
137
+ # Generate lockfile
138
+ npx add-skill-kit lock
139
+
140
+ # Install from lockfile
141
+ npx add-skill-kit install --locked
142
+ ```
143
+
144
+ ### Security by Design
145
+
146
+ | Feature | Description |
147
+ | :--- | :--- |
148
+ | **No Execution** | Skills are data artifacts, never executed |
149
+ | **SHA-256 Hashing** | Every skill is verified against its Merkle hash |
150
+ | **Integrity Checks** | `doctor` command detects tampering |
151
+ | **Audit Trail** | Full provenance tracking in `.skill-source.json` |
152
+
153
+ ---
154
+
155
+ ## Documentation
156
+
157
+ <table>
158
+ <tbody>
159
+ <tr>
160
+ <td><a href="https://github.com/agentskillkit/add-skill-kit/blob/main/specs/SKILL_V1.md">Skill Spec v1.0</a></td>
161
+ <td>The Antigravity Skills specification</td>
162
+ </tr>
163
+ <tr>
164
+ <td><a href="https://github.com/agentskillkit/add-skill-kit/tree/main/examples">Examples</a></td>
165
+ <td>Example skills and integration patterns</td>
166
+ </tr>
167
+ <tr>
168
+ <td><a href="https://github.com/agentskillkit/add-skill-kit/issues">Issues</a></td>
169
+ <td>Report bugs or request features</td>
170
+ </tr>
171
+ </tbody>
172
+ </table>
173
+
174
+ ---
175
+
176
+ ## Community
177
+
178
+ We welcome contributions! See our [Contributing Guide](https://github.com/agentskillkit/add-skill-kit/blob/main/CONTRIBUTING.md) to get started.
179
+
180
+ <a href="https://github.com/agentskillkit/add-skill-kit/graphs/contributors">
181
+ <img src="https://contrib.rocks/image?repo=agentskillkit/add-skill-kit" />
182
+ </a>
183
+
184
+ ---
185
+
186
+ <p align="center">
187
+ <sub>Built with ❤️ by <a href="https://github.com/agentskillkit">Agent Skill Kit</a></sub>
188
+ </p>
189
+
190
+ <p align="center">
191
+ <a href="https://github.com/agentskillkit/add-skill-kit">GitHub</a> •
192
+ <a href="https://www.npmjs.com/package/add-skill-kit">npm</a> •
193
+ <a href="https://github.com/agentskillkit/add-skill-kit/blob/main/LICENSE">License</a>
194
+ </p>
package/bin/cli.js ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Install Agent Skill v1.0.0
4
+ */
5
+ import { c, step, fatal, intro, outro } from "./lib/ui.js";
6
+ import { command, params, flags, VERSION } from "./lib/config.js";
7
+
8
+ // --- MAIN ---
9
+ async function main() {
10
+ intro(c.bgBlue(c.white(` Add Skill Kit v${VERSION} `)));
11
+
12
+ // Basic command routing
13
+ let cmdModule;
14
+
15
+ try {
16
+ switch (command) {
17
+ case "list":
18
+ case "ls":
19
+ case "init":
20
+ cmdModule = await import("./lib/commands/init.js");
21
+ await cmdModule.run();
22
+ break;
23
+ case "install":
24
+ case "add":
25
+ case "i":
26
+ cmdModule = await import("./lib/commands/install.js");
27
+ await cmdModule.run(params[0]);
28
+ break;
29
+ case "uninstall":
30
+ case "remove":
31
+ case "rm":
32
+ cmdModule = await import("./lib/commands/uninstall.js");
33
+ await cmdModule.run(params[0]);
34
+ break;
35
+ case "update":
36
+ cmdModule = await import("./lib/commands/update.js");
37
+ await cmdModule.run(params[0]);
38
+ break;
39
+ case "lock":
40
+ cmdModule = await import("./lib/commands/lock.js");
41
+ await cmdModule.run();
42
+ break;
43
+ case "verify":
44
+ cmdModule = await import("./lib/commands/verify.js");
45
+ await cmdModule.run();
46
+ break;
47
+ case "doctor":
48
+ cmdModule = await import("./lib/commands/doctor.js");
49
+ await cmdModule.run();
50
+ break;
51
+ case "cache":
52
+ cmdModule = await import("./lib/commands/cache.js");
53
+ await cmdModule.run(params[0]);
54
+ break;
55
+ case "validate":
56
+ case "check":
57
+ cmdModule = await import("./lib/commands/validate.js");
58
+ await cmdModule.run(params[0]);
59
+ break;
60
+ case "analyze":
61
+ cmdModule = await import("./lib/commands/analyze.js");
62
+ await cmdModule.run(params[0]);
63
+ break;
64
+ case "info":
65
+ case "show":
66
+ cmdModule = await import("./lib/commands/info.js");
67
+ await cmdModule.run(params[0]);
68
+ break;
69
+ case "help":
70
+ case "--help":
71
+ case "-h":
72
+ cmdModule = await import("./lib/commands/help.js");
73
+ await cmdModule.run();
74
+ break;
75
+ case "--version":
76
+ case "-V":
77
+ console.log(VERSION);
78
+ break;
79
+ default:
80
+ // Handle direct install via org/repo syntax
81
+ if (command.includes("/")) {
82
+ cmdModule = await import("./lib/commands/install.js");
83
+ await cmdModule.run(command);
84
+ } else {
85
+ console.log(`Unknown command: ${command}`);
86
+ cmdModule = await import("./lib/commands/help.js");
87
+ await cmdModule.run();
88
+ }
89
+ }
90
+ } catch (err) {
91
+ console.error(c.red("\nError: " + err.message));
92
+ if (process.env.DEBUG) console.error(err.stack);
93
+ process.exit(1);
94
+ }
95
+ }
96
+
97
+ main().catch(err => {
98
+ console.error(c.red("\nFatal Error: " + err.message));
99
+ process.exit(1);
100
+ });
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @fileoverview Analyze command - Skill structure analysis
3
+ */
4
+
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import { resolveScope, getDirSize } from "../helpers.js";
8
+ import { parseSkillMdFrontmatter, detectSkillStructure } from "../skills.js";
9
+ import { step, stepLine, S, c, fatal } from "../ui.js";
10
+
11
+ /**
12
+ * Analyze skill structure
13
+ * @param {string} skillName - Skill to analyze
14
+ */
15
+ export async function run(skillName) {
16
+ if (!skillName) fatal("Missing skill name");
17
+
18
+ const scope = resolveScope();
19
+ const skillDir = path.join(scope, skillName);
20
+
21
+ if (!fs.existsSync(skillDir)) fatal(`Skill not found: ${skillName}`);
22
+
23
+ stepLine();
24
+ step(c.bold(`Skill Analysis: ${skillName}`), S.diamondFilled, "cyan");
25
+ console.log(`${c.gray(S.branch)} ${c.dim("Path: " + skillDir)}`);
26
+ stepLine();
27
+
28
+ // SKILL.md frontmatter
29
+ const smp = path.join(skillDir, "SKILL.md");
30
+ if (fs.existsSync(smp)) {
31
+ const m = parseSkillMdFrontmatter(smp);
32
+ console.log(`${c.gray(S.branch)} ${c.cyan("SKILL.md Frontmatter:")}`);
33
+ console.log(`${c.gray(S.branch)} Name: ${m.name || c.dim("(not set)")}`);
34
+ console.log(`${c.gray(S.branch)} Description: ${m.description ? m.description.substring(0, 60) : c.red("(MISSING)")}`);
35
+ if (m.tags) console.log(`${c.gray(S.branch)} Tags: ${m.tags.join(", ")}`);
36
+ stepLine();
37
+ }
38
+
39
+ // Structure
40
+ const structure = detectSkillStructure(skillDir);
41
+ console.log(`${c.gray(S.branch)} ${c.cyan("Structure:")}`);
42
+
43
+ const items = [
44
+ ["resources", structure.hasResources],
45
+ ["examples", structure.hasExamples],
46
+ ["scripts", structure.hasScripts],
47
+ ["constitution", structure.hasConstitution],
48
+ ["doctrines", structure.hasDoctrines]
49
+ ];
50
+
51
+ items.forEach(([n, has]) => {
52
+ console.log(`${c.gray(S.branch)} ${has ? c.green(S.check) : c.dim("○")} ${has ? c.bold(n) : c.dim(n)}`);
53
+ });
54
+
55
+ stepLine();
56
+
57
+ // Antigravity Score
58
+ let score = 0;
59
+ if (fs.existsSync(smp)) score += 20;
60
+ const m = parseSkillMdFrontmatter(smp);
61
+ if (m.description) score += 25;
62
+ if (m.tags && m.tags.length > 0) score += 10;
63
+ if (structure.hasResources || structure.hasExamples || structure.hasScripts) score += 20;
64
+ if (fs.existsSync(path.join(skillDir, ".skill-source.json"))) score += 10;
65
+ if (structure.hasConstitution || structure.hasDoctrines) score += 15;
66
+
67
+ const scoreColor = score >= 80 ? c.green : score >= 50 ? c.yellow : c.red;
68
+ console.log(`${c.gray(S.branch)} ${c.cyan("Antigravity Score:")} ${scoreColor(score + "/100")}`);
69
+ stepLine();
70
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @fileoverview Cache command
3
+ */
4
+
5
+ import fs from "fs";
6
+ import { step, stepLine, S, c, fatal, success } from "../ui.js";
7
+ import { getDirSize, formatBytes, listBackups } from "../helpers.js";
8
+ import { CACHE_ROOT, REGISTRY_CACHE, BACKUP_DIR, DRY } from "../config.js";
9
+
10
+ /**
11
+ * Manage cache
12
+ * @param {string} [sub] - Subcommand: info, clear, backups
13
+ */
14
+ export async function run(sub) {
15
+ stepLine();
16
+
17
+ if (sub === "clear") {
18
+ if (DRY) {
19
+ step(`Would clear: ${CACHE_ROOT}`, S.diamond);
20
+ return;
21
+ }
22
+ if (fs.existsSync(CACHE_ROOT)) {
23
+ const size = getDirSize(CACHE_ROOT);
24
+ fs.rmSync(CACHE_ROOT, { recursive: true, force: true });
25
+ success(`Cache cleared (${formatBytes(size)})`);
26
+ } else {
27
+ step("Cache already empty", S.diamond);
28
+ }
29
+ return;
30
+ }
31
+
32
+ if (sub === "info" || !sub) {
33
+ if (!fs.existsSync(CACHE_ROOT)) {
34
+ step("Cache is empty", S.diamond);
35
+ return;
36
+ }
37
+
38
+ const rs = fs.existsSync(REGISTRY_CACHE) ? getDirSize(REGISTRY_CACHE) : 0;
39
+ const bs = fs.existsSync(BACKUP_DIR) ? getDirSize(BACKUP_DIR) : 0;
40
+
41
+ step(c.bold("Cache Info"), S.diamondFilled, "cyan");
42
+ console.log(`${c.gray(S.branch)} Location: ${CACHE_ROOT}`);
43
+ console.log(`${c.gray(S.branch)} Registries: ${formatBytes(rs)}`);
44
+ console.log(`${c.gray(S.branch)} Backups: ${formatBytes(bs)}`);
45
+ console.log(`${c.gray(S.branch)} Total: ${formatBytes(getDirSize(CACHE_ROOT))}`);
46
+ stepLine();
47
+ return;
48
+ }
49
+
50
+ if (sub === "backups") {
51
+ const backups = listBackups();
52
+ if (backups.length === 0) {
53
+ step("No backups found", S.diamond);
54
+ return;
55
+ }
56
+
57
+ step(c.bold("Backups"), S.diamondFilled, "cyan");
58
+ stepLine();
59
+ backups.forEach(b => console.log(`${c.gray(S.branch)} ${b.name} (${formatBytes(b.size)})`));
60
+ stepLine();
61
+ return;
62
+ }
63
+
64
+ fatal(`Unknown cache subcommand: ${sub}`);
65
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @fileoverview Doctor command - Health check
3
+ */
4
+
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import { resolveScope, merkleHash, loadSkillLock } from "../helpers.js";
8
+ import { step, stepLine, S, c } from "../ui.js";
9
+ import { STRICT, FIX, DRY, cwd } from "../config.js";
10
+
11
+ /**
12
+ * Run health check on installed skills
13
+ */
14
+ export async function run() {
15
+ const scope = resolveScope();
16
+
17
+ if (!fs.existsSync(scope)) {
18
+ stepLine();
19
+ step("No skills directory found", S.diamond);
20
+ return;
21
+ }
22
+
23
+ stepLine();
24
+ step(c.bold("Health Check"), S.diamondFilled, "cyan");
25
+ stepLine();
26
+
27
+ let errors = 0, warnings = 0;
28
+ const lock = fs.existsSync(path.join(cwd, ".agent", "skill-lock.json")) ? loadSkillLock() : null;
29
+
30
+ for (const name of fs.readdirSync(scope)) {
31
+ const dir = path.join(scope, name);
32
+ if (!fs.statSync(dir).isDirectory()) continue;
33
+
34
+ // Check SKILL.md
35
+ if (!fs.existsSync(path.join(dir, "SKILL.md"))) {
36
+ step(`${name}: ${c.red("missing SKILL.md")}`, S.cross, "red");
37
+ errors++;
38
+ continue;
39
+ }
40
+
41
+ // Check metadata
42
+ const mf = path.join(dir, ".skill-source.json");
43
+ if (!fs.existsSync(mf)) {
44
+ step(`${name}: ${c.red("missing metadata")}`, S.cross, "red");
45
+ errors++;
46
+ continue;
47
+ }
48
+
49
+ const m = JSON.parse(fs.readFileSync(mf, "utf-8"));
50
+ const actual = merkleHash(dir);
51
+
52
+ // Check checksum
53
+ if (actual !== m.checksum) {
54
+ if (FIX && !DRY) {
55
+ m.checksum = actual;
56
+ fs.writeFileSync(mf, JSON.stringify(m, null, 2));
57
+ step(`${name}: ${c.yellow("checksum fixed")}`, S.diamond, "yellow");
58
+ } else {
59
+ step(`${name}: ${c.yellow("checksum drift")}`, S.diamond, "yellow");
60
+ STRICT ? errors++ : warnings++;
61
+ }
62
+ } else if (lock && !lock.skills[name]) {
63
+ step(`${name}: ${c.yellow("not in lock")}`, S.diamond, "yellow");
64
+ STRICT ? errors++ : warnings++;
65
+ } else {
66
+ step(`${name}: ${c.green("healthy")}`, S.check, "green");
67
+ }
68
+ }
69
+
70
+ stepLine();
71
+ console.log(`${c.gray(S.branch)} Errors: ${errors}, Warnings: ${warnings}`);
72
+ stepLine();
73
+
74
+ if (STRICT && errors) process.exit(1);
75
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @fileoverview Help command
3
+ */
4
+
5
+ import { c } from "../ui.js";
6
+ import { VERSION } from "../config.js";
7
+
8
+ /**
9
+ * Show help
10
+ */
11
+ export async function run() {
12
+ console.log(`
13
+ ${c.bold("add-skill-kit")} ${c.dim("v" + VERSION)}
14
+
15
+ ${c.bold("Usage")}
16
+ $ add-skill-kit <command> [options]
17
+
18
+ ${c.bold("Commands")}
19
+ <org/repo> Install all skills from repository
20
+ <org/repo#skill> Install specific skill
21
+ list List installed skills
22
+ uninstall <skill> Remove a skill
23
+ update <skill> Update a skill
24
+ verify Verify checksums
25
+ doctor Check health
26
+ lock Generate skill-lock.json
27
+ init Initialize skills directory
28
+ validate [skill] Validate against Antigravity spec
29
+ analyze <skill> Analyze skill structure
30
+ cache [info|clear] Manage cache
31
+ info <skill> Show skill info
32
+
33
+ ${c.bold("Options")}
34
+ --global, -g Use global scope
35
+ --force, -f Force operation
36
+ --strict Fail on violations
37
+ --fix Auto-fix issues
38
+ --dry-run Preview only
39
+ --verbose, -v Detailed output
40
+ --json JSON output
41
+ `);
42
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @fileoverview Info command
3
+ */
4
+
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import { resolveScope, formatDate } from "../helpers.js";
8
+ import { step, stepLine, S, c, fatal } from "../ui.js";
9
+
10
+ /**
11
+ * Show skill info
12
+ * @param {string} name
13
+ */
14
+ export async function run(name) {
15
+ if (!name) fatal("Missing skill name");
16
+
17
+ const scope = resolveScope();
18
+ const localDir = path.join(scope, name);
19
+
20
+ stepLine();
21
+
22
+ if (fs.existsSync(localDir)) {
23
+ step(`${c.bold(name)} ${c.green("(installed)")}`, S.diamondFilled, "cyan");
24
+ console.log(`${c.gray(S.branch)} ${c.dim("Path: " + localDir)}`);
25
+
26
+ const mf = path.join(localDir, ".skill-source.json");
27
+ if (fs.existsSync(mf)) {
28
+ const m = JSON.parse(fs.readFileSync(mf, "utf-8"));
29
+ console.log(`${c.gray(S.branch)} Repo: ${m.repo || "local"}`);
30
+ console.log(`${c.gray(S.branch)} Installed: ${formatDate(m.installedAt)}`);
31
+ }
32
+ stepLine();
33
+ return;
34
+ }
35
+
36
+ step(`Skill not installed: ${name}`, S.diamond, "yellow");
37
+ stepLine();
38
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @fileoverview Init command
3
+ */
4
+
5
+ import fs from "fs";
6
+ import { step, stepLine, S, success } from "../ui.js";
7
+ import { GLOBAL, GLOBAL_DIR, WORKSPACE, DRY, cwd } from "../config.js";
8
+ import path from "path";
9
+
10
+ /**
11
+ * Initialize skills directory
12
+ */
13
+ export async function run() {
14
+ stepLine();
15
+
16
+ const targetDir = GLOBAL ? GLOBAL_DIR : WORKSPACE;
17
+
18
+ if (fs.existsSync(targetDir)) {
19
+ step(`Skills directory already exists: ${targetDir}`, S.check, "green");
20
+ return;
21
+ }
22
+
23
+ if (DRY) {
24
+ step(`Would create: ${targetDir}`, S.diamond);
25
+ return;
26
+ }
27
+
28
+ fs.mkdirSync(targetDir, { recursive: true });
29
+
30
+ // Create .gitignore if workspace
31
+ if (!GLOBAL) {
32
+ const gi = path.join(cwd, ".agent", ".gitignore");
33
+ if (!fs.existsSync(gi)) {
34
+ fs.writeFileSync(gi, "# Skill caches\nskills/*/.skill-source.json\n");
35
+ }
36
+ }
37
+
38
+ success(`Initialized: ${targetDir}`);
39
+ }