lmskills-cli 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,185 @@
1
+ # lmskills-cli
2
+
3
+ A command-line tool to easily fetch and install Claude skills from GitHub repositories.
4
+
5
+ ## Installation
6
+
7
+ ### Option 1: Use with npx (Recommended)
8
+
9
+ No installation required! Run directly:
10
+
11
+ ```bash
12
+ npx lmskills-cli <command>
13
+ ```
14
+
15
+ ### Option 2: Install Globally
16
+
17
+ ```bash
18
+ npm install -g lmskills-cli
19
+ ```
20
+
21
+ Then use the shorter command:
22
+
23
+ ```bash
24
+ lmskills <command>
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### Install a Skill
30
+
31
+ Install a skill from a GitHub subdirectory URL:
32
+
33
+ ```bash
34
+ # Install locally (project-specific .claude directory)
35
+ lmskills install https://github.com/owner/repo/tree/main/path/to/skill
36
+
37
+ # Install globally (user-wide .claude directory)
38
+ lmskills install https://github.com/owner/repo/tree/main/path/to/skill --global
39
+ ```
40
+
41
+ The CLI will:
42
+ - Parse the GitHub URL to identify the repository and subdirectory
43
+ - Download all files from that subdirectory
44
+ - Copy them to `.claude/skills/<skill-name>/` (local or global)
45
+ - Track the installation in metadata for easy management
46
+
47
+ ### List Installed Skills
48
+
49
+ View all installed skills:
50
+
51
+ ```bash
52
+ # List local skills
53
+ lmskills list
54
+
55
+ # List global skills
56
+ lmskills list --global
57
+ ```
58
+
59
+ ### Remove a Skill
60
+
61
+ Uninstall a skill:
62
+
63
+ ```bash
64
+ # Remove local skill
65
+ lmskills remove <skill-name>
66
+
67
+ # Remove global skill
68
+ lmskills remove <skill-name> --global
69
+ ```
70
+
71
+ Alias: `lmskills rm <skill-name>`
72
+
73
+ ## Examples
74
+
75
+ ### Using npx (no installation required)
76
+
77
+ ```bash
78
+ # Install a skill locally
79
+ npx lmskills-cli install https://github.com/anthropics/claude-code/tree/main/skills/example-skill
80
+
81
+ # Install a skill globally
82
+ npx lmskills-cli install https://github.com/user/skills/tree/main/my-awesome-skill -g
83
+
84
+ # List all local skills
85
+ npx lmskills-cli list
86
+
87
+ # Remove a skill
88
+ npx lmskills-cli rm example-skill
89
+ ```
90
+
91
+ ### Using global installation
92
+
93
+ ```bash
94
+ # Install a skill locally
95
+ lmskills install https://github.com/anthropics/claude-code/tree/main/skills/example-skill
96
+
97
+ # Install a skill globally
98
+ lmskills install https://github.com/user/skills/tree/main/my-awesome-skill -g
99
+
100
+ # List all local skills
101
+ lmskills list
102
+
103
+ # Remove a skill
104
+ lmskills rm example-skill
105
+ ```
106
+
107
+ ## Directory Structure
108
+
109
+ ### Local Installation
110
+ Skills are installed to `.claude/skills/` in your current working directory:
111
+
112
+ ```
113
+ your-project/
114
+ └── .claude/
115
+ └── skills/
116
+ ├── .lmskills-metadata.json
117
+ ├── skill-one/
118
+ │ ├── SKILL.md
119
+ │ └── ...
120
+ └── skill-two/
121
+ ├── SKILL.md
122
+ └── ...
123
+ ```
124
+
125
+ ### Global Installation
126
+ Skills are installed to `.claude/skills/` in your home directory:
127
+
128
+ ```
129
+ ~/.claude/
130
+ └── skills/
131
+ ├── .lmskills-metadata.json
132
+ └── skill-name/
133
+ ├── SKILL.md
134
+ └── ...
135
+ ```
136
+
137
+ ## Metadata
138
+
139
+ The CLI maintains a `.lmskills-metadata.json` file in the skills directory to track:
140
+ - Skill name
141
+ - Source GitHub URL
142
+ - Installation timestamp
143
+ - Installation path
144
+ - Whether it's a global or local installation
145
+
146
+ ## Requirements
147
+
148
+ - Node.js 18.0.0 or higher
149
+ - Git repository URL must be in the format: `https://github.com/owner/repo/tree/branch/path/to/skill`
150
+
151
+ ## GitHub API
152
+
153
+ The CLI uses the GitHub API without authentication, which has rate limits:
154
+ - 60 requests per hour for unauthenticated requests
155
+ - To increase the limit, you can set a GitHub personal access token as an environment variable (feature coming soon)
156
+
157
+ ## Development
158
+
159
+ To work on the CLI locally:
160
+
161
+ ```bash
162
+ # Clone the repository
163
+ git clone https://github.com/your-org/lmskills.git
164
+ cd lmskills/cli
165
+
166
+ # Install dependencies
167
+ npm install
168
+
169
+ # Build the TypeScript code
170
+ npm run build
171
+
172
+ # Link for local testing
173
+ npm link
174
+
175
+ # Now you can use 'lmskills' command globally
176
+ lmskills --help
177
+ ```
178
+
179
+ ## License
180
+
181
+ MIT
182
+
183
+ ## Contributing
184
+
185
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,13 @@
1
+ import { ParsedGitHubUrl } from './types';
2
+ /**
3
+ * Parse a GitHub URL to extract owner, repo, branch, and path
4
+ * Supports formats like:
5
+ * - https://github.com/owner/repo/tree/branch/path/to/skill
6
+ * - https://github.com/owner/repo/tree/main/path/to/skill
7
+ */
8
+ export declare function parseGitHubUrl(url: string): ParsedGitHubUrl;
9
+ /**
10
+ * Download an entire subdirectory from a GitHub repository
11
+ */
12
+ export declare function downloadGitHubDirectory(parsedUrl: ParsedGitHubUrl, targetDir: string): Promise<void>;
13
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAsC,MAAM,SAAS,CAAC;AAE9E;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAkB3D;AAuGD;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,eAAe,EAC1B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAyCf"}
package/dist/github.js ADDED
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.parseGitHubUrl = parseGitHubUrl;
40
+ exports.downloadGitHubDirectory = downloadGitHubDirectory;
41
+ const node_fetch_1 = __importDefault(require("node-fetch"));
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ /**
45
+ * Parse a GitHub URL to extract owner, repo, branch, and path
46
+ * Supports formats like:
47
+ * - https://github.com/owner/repo/tree/branch/path/to/skill
48
+ * - https://github.com/owner/repo/tree/main/path/to/skill
49
+ */
50
+ function parseGitHubUrl(url) {
51
+ const regex = /github\.com\/([^\/]+)\/([^\/]+)\/tree\/([^\/]+)\/(.+)/;
52
+ const match = url.match(regex);
53
+ if (!match) {
54
+ throw new Error('Invalid GitHub URL format. Expected: https://github.com/owner/repo/tree/branch/path/to/skill');
55
+ }
56
+ const [, owner, repo, branch, pathStr] = match;
57
+ return {
58
+ owner,
59
+ repo,
60
+ branch,
61
+ path: pathStr,
62
+ };
63
+ }
64
+ /**
65
+ * Fetch the Git tree for a specific path in a repository
66
+ */
67
+ async function fetchGitTree(owner, repo, treeSha) {
68
+ const url = `https://api.github.com/repos/${owner}/${repo}/git/trees/${treeSha}?recursive=1`;
69
+ const response = await (0, node_fetch_1.default)(url, {
70
+ headers: {
71
+ 'Accept': 'application/vnd.github.v3+json',
72
+ 'User-Agent': 'lmskills-cli',
73
+ },
74
+ });
75
+ if (!response.ok) {
76
+ throw new Error(`GitHub API error: ${response.statusText}`);
77
+ }
78
+ return await response.json();
79
+ }
80
+ /**
81
+ * Get the SHA for a specific branch
82
+ */
83
+ async function getBranchSha(owner, repo, branch) {
84
+ const url = `https://api.github.com/repos/${owner}/${repo}/git/ref/heads/${branch}`;
85
+ const response = await (0, node_fetch_1.default)(url, {
86
+ headers: {
87
+ 'Accept': 'application/vnd.github.v3+json',
88
+ 'User-Agent': 'lmskills-cli',
89
+ },
90
+ });
91
+ if (!response.ok) {
92
+ throw new Error(`Failed to fetch branch: ${response.statusText}`);
93
+ }
94
+ const data = await response.json();
95
+ return data.object.sha;
96
+ }
97
+ /**
98
+ * Get the tree SHA for a commit
99
+ */
100
+ async function getCommitTreeSha(owner, repo, commitSha) {
101
+ const url = `https://api.github.com/repos/${owner}/${repo}/git/commits/${commitSha}`;
102
+ const response = await (0, node_fetch_1.default)(url, {
103
+ headers: {
104
+ 'Accept': 'application/vnd.github.v3+json',
105
+ 'User-Agent': 'lmskills-cli',
106
+ },
107
+ });
108
+ if (!response.ok) {
109
+ throw new Error(`Failed to fetch commit: ${response.statusText}`);
110
+ }
111
+ const data = await response.json();
112
+ return data.tree.sha;
113
+ }
114
+ /**
115
+ * Download a blob (file) from GitHub
116
+ */
117
+ async function downloadBlob(owner, repo, sha) {
118
+ const url = `https://api.github.com/repos/${owner}/${repo}/git/blobs/${sha}`;
119
+ const response = await (0, node_fetch_1.default)(url, {
120
+ headers: {
121
+ 'Accept': 'application/vnd.github.v3+json',
122
+ 'User-Agent': 'lmskills-cli',
123
+ },
124
+ });
125
+ if (!response.ok) {
126
+ throw new Error(`Failed to download file: ${response.statusText}`);
127
+ }
128
+ const data = await response.json();
129
+ // GitHub returns base64-encoded content
130
+ return Buffer.from(data.content, 'base64');
131
+ }
132
+ /**
133
+ * Download an entire subdirectory from a GitHub repository
134
+ */
135
+ async function downloadGitHubDirectory(parsedUrl, targetDir) {
136
+ const { owner, repo, branch, path: subPath } = parsedUrl;
137
+ // Get the commit SHA for the branch
138
+ const commitSha = await getBranchSha(owner, repo, branch);
139
+ // Get the tree SHA for this commit
140
+ const treeSha = await getCommitTreeSha(owner, repo, commitSha);
141
+ // Fetch the full repository tree
142
+ const tree = await fetchGitTree(owner, repo, treeSha);
143
+ // Filter tree items that are within the target subdirectory
144
+ // Must match exact path or be inside the directory (with trailing slash)
145
+ const relevantItems = tree.tree.filter(item => item.path === subPath || item.path.startsWith(subPath + '/'));
146
+ if (relevantItems.length === 0) {
147
+ throw new Error(`No files found at path: ${subPath}`);
148
+ }
149
+ // Download each file
150
+ for (const item of relevantItems) {
151
+ if (item.type === 'blob') {
152
+ // Calculate relative path within the skill directory
153
+ const relativePath = item.path.substring(subPath.length + 1);
154
+ if (!relativePath)
155
+ continue; // Skip if empty
156
+ const targetPath = path.join(targetDir, relativePath);
157
+ // Ensure directory exists
158
+ const dir = path.dirname(targetPath);
159
+ fs.mkdirSync(dir, { recursive: true });
160
+ // Download and save the file
161
+ const content = await downloadBlob(owner, repo, item.sha);
162
+ fs.writeFileSync(targetPath, content);
163
+ }
164
+ }
165
+ }
166
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const install_1 = require("./install");
10
+ const list_1 = require("./list");
11
+ const remove_1 = require("./remove");
12
+ const program = new commander_1.Command();
13
+ program
14
+ .name('lmskills')
15
+ .description('CLI tool to fetch and install Claude skills from GitHub')
16
+ .version('0.1.0');
17
+ program
18
+ .command('install <github-url>')
19
+ .description('Install a skill from a GitHub subdirectory URL')
20
+ .option('-g, --global', 'Install globally instead of in the current project')
21
+ .action(async (githubUrl, options) => {
22
+ await (0, install_1.installSkill)(githubUrl, options);
23
+ });
24
+ program
25
+ .command('list')
26
+ .description('List installed skills')
27
+ .option('-g, --global', 'List global skills instead of local')
28
+ .action((options) => {
29
+ (0, list_1.listSkills)(options);
30
+ });
31
+ program
32
+ .command('remove <skill-name>')
33
+ .alias('rm')
34
+ .description('Remove an installed skill')
35
+ .option('-g, --global', 'Remove from global skills instead of local')
36
+ .action((skillName, options) => {
37
+ (0, remove_1.removeSkill)(skillName, options);
38
+ });
39
+ // Handle unknown commands with helpful error messages
40
+ program.on('command:*', (operands) => {
41
+ const unknownCommand = operands[0];
42
+ console.error(chalk_1.default.red(`\nError: Unknown command '${unknownCommand}'`));
43
+ // Check if it looks like a GitHub URL
44
+ if (unknownCommand.includes('github.com')) {
45
+ console.log(chalk_1.default.yellow('\nIt looks like you provided a GitHub URL.'));
46
+ console.log(chalk_1.default.yellow('Did you mean to run:\n'));
47
+ console.log(chalk_1.default.cyan(` lmskills install ${unknownCommand}`));
48
+ console.log(chalk_1.default.gray('\nOr with npx:'));
49
+ console.log(chalk_1.default.cyan(` npx lmskills-cli install ${unknownCommand}`));
50
+ }
51
+ else {
52
+ console.log(chalk_1.default.gray('\nRun "lmskills --help" to see available commands.'));
53
+ }
54
+ process.exit(1);
55
+ });
56
+ program.parse(process.argv);
57
+ // Show help if no command provided
58
+ if (!process.argv.slice(2).length) {
59
+ program.outputHelp();
60
+ }
61
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAEA,yCAAoC;AACpC,kDAA0B;AAC1B,uCAAyC;AACzC,iCAAoC;AACpC,qCAAuC;AAEvC,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,yDAAyD,CAAC;KACtE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,sBAAsB,CAAC;KAC/B,WAAW,CAAC,gDAAgD,CAAC;KAC7D,MAAM,CAAC,cAAc,EAAE,oDAAoD,CAAC;KAC5E,MAAM,CAAC,KAAK,EAAE,SAAiB,EAAE,OAA6B,EAAE,EAAE;IACjE,MAAM,IAAA,sBAAY,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,uBAAuB,CAAC;KACpC,MAAM,CAAC,cAAc,EAAE,qCAAqC,CAAC;KAC7D,MAAM,CAAC,CAAC,OAA6B,EAAE,EAAE;IACxC,IAAA,iBAAU,EAAC,OAAO,CAAC,CAAC;AACtB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,qBAAqB,CAAC;KAC9B,KAAK,CAAC,IAAI,CAAC;KACX,WAAW,CAAC,2BAA2B,CAAC;KACxC,MAAM,CAAC,cAAc,EAAE,4CAA4C,CAAC;KACpE,MAAM,CAAC,CAAC,SAAiB,EAAE,OAA6B,EAAE,EAAE;IAC3D,IAAA,oBAAW,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAClC,CAAC,CAAC,CAAC;AAEL,sDAAsD;AACtD,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,EAAE;IACnC,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEnC,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,6BAA6B,cAAc,GAAG,CAAC,CAAC,CAAC;IAEzE,sCAAsC;IACtC,IAAI,cAAc,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,4CAA4C,CAAC,CAAC,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,sBAAsB,cAAc,EAAE,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,8BAA8B,cAAc,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5B,mCAAmC;AACnC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,OAAO,CAAC,UAAU,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function installSkill(githubUrl: string, options: {
2
+ global?: boolean;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAcA,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5B,OAAO,CAAC,IAAI,CAAC,CAyEf"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.installSkill = installSkill;
40
+ const path = __importStar(require("path"));
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const ora_1 = __importDefault(require("ora"));
43
+ const github_1 = require("./github");
44
+ const utils_1 = require("./utils");
45
+ async function installSkill(githubUrl, options) {
46
+ const isGlobal = options.global || false;
47
+ const spinner = (0, ora_1.default)();
48
+ try {
49
+ // Parse the GitHub URL
50
+ spinner.start('Parsing GitHub URL...');
51
+ const parsedUrl = (0, github_1.parseGitHubUrl)(githubUrl);
52
+ spinner.succeed(`Parsed: ${parsedUrl.owner}/${parsedUrl.repo} (${parsedUrl.path})`);
53
+ // Derive skill name from the path
54
+ const skillName = (0, utils_1.getSkillDirName)(parsedUrl.path);
55
+ // Check if already installed
56
+ const metadata = (0, utils_1.readMetadata)(isGlobal);
57
+ const existing = metadata.find(s => s.name === skillName);
58
+ if (existing) {
59
+ console.log(chalk_1.default.yellow(`\nSkill "${skillName}" is already installed at: ${existing.path}`));
60
+ console.log(chalk_1.default.yellow('Reinstalling will overwrite the existing skill.\n'));
61
+ }
62
+ // Ensure skills directory exists
63
+ (0, utils_1.ensureSkillsDir)(isGlobal);
64
+ // Determine target directory
65
+ const skillsPath = (0, utils_1.getSkillsPath)(isGlobal);
66
+ const targetDir = path.join(skillsPath, skillName);
67
+ // Remove existing installation if present
68
+ if (existing) {
69
+ (0, utils_1.deleteDirectory)(targetDir);
70
+ }
71
+ // Download the skill
72
+ spinner.start(`Downloading skill from GitHub...`);
73
+ await (0, github_1.downloadGitHubDirectory)(parsedUrl, targetDir);
74
+ spinner.succeed(`Downloaded skill to ${targetDir}`);
75
+ // Save metadata
76
+ const skillMetadata = {
77
+ name: skillName,
78
+ source: githubUrl,
79
+ installedAt: new Date().toISOString(),
80
+ path: targetDir,
81
+ isGlobal,
82
+ };
83
+ (0, utils_1.addSkillMetadata)(skillMetadata, isGlobal);
84
+ console.log(chalk_1.default.green(`\n✓ Successfully installed "${skillName}" ${isGlobal ? 'globally' : 'locally'}`));
85
+ console.log(chalk_1.default.gray(` Path: ${targetDir}`));
86
+ }
87
+ catch (error) {
88
+ spinner.fail('Installation failed');
89
+ if (error instanceof Error) {
90
+ console.error(chalk_1.default.red(`\nError: ${error.message}`));
91
+ }
92
+ else {
93
+ console.error(chalk_1.default.red('\nAn unknown error occurred'));
94
+ }
95
+ process.exit(1);
96
+ }
97
+ }
98
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
package/dist/list.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export declare function listSkills(options: {
2
+ global?: boolean;
3
+ }): void;
4
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"AAGA,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAyB9D"}
package/dist/list.js ADDED
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.listSkills = listSkills;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const utils_1 = require("./utils");
9
+ function listSkills(options) {
10
+ const isGlobal = options.global || false;
11
+ const metadata = (0, utils_1.readMetadata)(isGlobal);
12
+ const scope = isGlobal ? 'global' : 'local';
13
+ if (metadata.length === 0) {
14
+ console.log(chalk_1.default.yellow(`No ${scope} skills installed.`));
15
+ console.log(chalk_1.default.gray(`\nTo install a skill, run:\n lmskills install <github-url> ${isGlobal ? '--global' : ''}`));
16
+ return;
17
+ }
18
+ console.log(chalk_1.default.bold(`\n${scope.toUpperCase()} SKILLS (${metadata.length}):\n`));
19
+ metadata.forEach(skill => {
20
+ console.log(chalk_1.default.cyan(` ${skill.name}`));
21
+ console.log(chalk_1.default.gray(` Source: ${skill.source}`));
22
+ console.log(chalk_1.default.gray(` Installed: ${new Date(skill.installedAt).toLocaleString()}`));
23
+ console.log(chalk_1.default.gray(` Path: ${skill.path}`));
24
+ console.log();
25
+ });
26
+ }
27
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":";;;;;AAGA,gCAyBC;AA5BD,kDAA0B;AAC1B,mCAAuC;AAEvC,SAAgB,UAAU,CAAC,OAA6B;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAA,oBAAY,EAAC,QAAQ,CAAC,CAAC;IAExC,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IAE5C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,MAAM,KAAK,oBAAoB,CAAC,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,IAAI,CACR,+DAA+D,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5F,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,WAAW,EAAE,YAAY,QAAQ,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC;IAEnF,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QACvB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,eAAe,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1F,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,aAAa,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function removeSkill(skillName: string, options: {
2
+ global?: boolean;
3
+ }): void;
4
+ //# sourceMappingURL=remove.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../src/remove.ts"],"names":[],"mappings":"AAOA,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5B,IAAI,CAsCN"}
package/dist/remove.js ADDED
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.removeSkill = removeSkill;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const utils_1 = require("./utils");
9
+ function removeSkill(skillName, options) {
10
+ const isGlobal = options.global || false;
11
+ const metadata = (0, utils_1.readMetadata)(isGlobal);
12
+ const skill = metadata.find(s => s.name === skillName);
13
+ if (!skill) {
14
+ console.error(chalk_1.default.red(`\nSkill "${skillName}" not found in ${isGlobal ? 'global' : 'local'} installations.`));
15
+ console.log(chalk_1.default.gray(`\nRun "lmskills list${isGlobal ? ' --global' : ''}" to see installed skills.`));
16
+ process.exit(1);
17
+ }
18
+ try {
19
+ // Delete the skill directory
20
+ (0, utils_1.deleteDirectory)(skill.path);
21
+ // Remove from metadata
22
+ (0, utils_1.removeSkillMetadata)(skillName, isGlobal);
23
+ console.log(chalk_1.default.green(`\n✓ Successfully removed "${skillName}" from ${isGlobal ? 'global' : 'local'} installations`));
24
+ }
25
+ catch (error) {
26
+ console.error(chalk_1.default.red(`\nError removing skill: ${error instanceof Error ? error.message : 'Unknown error'}`));
27
+ process.exit(1);
28
+ }
29
+ }
30
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../src/remove.ts"],"names":[],"mappings":";;;;;AAOA,kCAyCC;AAhDD,kDAA0B;AAC1B,mCAIiB;AAEjB,SAAgB,WAAW,CACzB,SAAiB,EACjB,OAA6B;IAE7B,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAA,oBAAY,EAAC,QAAQ,CAAC,CAAC;IAExC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAEvD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CACX,eAAK,CAAC,GAAG,CACP,YAAY,SAAS,kBAAkB,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,iBAAiB,CACtF,CACF,CAAC;QACF,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,IAAI,CACR,uBAAuB,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,4BAA4B,CAC/E,CACF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,6BAA6B;QAC7B,IAAA,uBAAe,EAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE5B,uBAAuB;QACvB,IAAA,2BAAmB,EAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEzC,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,KAAK,CACT,6BAA6B,SAAS,UAAU,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,gBAAgB,CAC9F,CACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CACX,eAAK,CAAC,GAAG,CAAC,2BAA2B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CACjG,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,28 @@
1
+ export interface SkillMetadata {
2
+ name: string;
3
+ source: string;
4
+ installedAt: string;
5
+ path: string;
6
+ isGlobal: boolean;
7
+ }
8
+ export interface GitHubTreeItem {
9
+ path: string;
10
+ mode: string;
11
+ type: 'blob' | 'tree';
12
+ sha: string;
13
+ size?: number;
14
+ url: string;
15
+ }
16
+ export interface GitHubTreeResponse {
17
+ sha: string;
18
+ url: string;
19
+ tree: GitHubTreeItem[];
20
+ truncated: boolean;
21
+ }
22
+ export interface ParsedGitHubUrl {
23
+ owner: string;
24
+ repo: string;
25
+ branch: string;
26
+ path: string;
27
+ }
28
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,48 @@
1
+ import { SkillMetadata } from './types';
2
+ export declare const SKILLS_DIR = "skills";
3
+ export declare const METADATA_FILE = ".lmskills-metadata.json";
4
+ /**
5
+ * Get the path to the local .claude directory (project-specific)
6
+ */
7
+ export declare function getLocalClaudePath(): string;
8
+ /**
9
+ * Get the path to the global .claude directory (user-wide)
10
+ */
11
+ export declare function getGlobalClaudePath(): string;
12
+ /**
13
+ * Get the skills directory path
14
+ */
15
+ export declare function getSkillsPath(isGlobal: boolean): string;
16
+ /**
17
+ * Ensure the skills directory exists
18
+ */
19
+ export declare function ensureSkillsDir(isGlobal: boolean): void;
20
+ /**
21
+ * Get metadata file path
22
+ */
23
+ export declare function getMetadataPath(isGlobal: boolean): string;
24
+ /**
25
+ * Read metadata for all installed skills
26
+ */
27
+ export declare function readMetadata(isGlobal: boolean): SkillMetadata[];
28
+ /**
29
+ * Write metadata for installed skills
30
+ */
31
+ export declare function writeMetadata(metadata: SkillMetadata[], isGlobal: boolean): void;
32
+ /**
33
+ * Add a skill to metadata
34
+ */
35
+ export declare function addSkillMetadata(skill: SkillMetadata, isGlobal: boolean): void;
36
+ /**
37
+ * Remove a skill from metadata
38
+ */
39
+ export declare function removeSkillMetadata(skillName: string, isGlobal: boolean): void;
40
+ /**
41
+ * Get a skill's directory name from its source URL
42
+ */
43
+ export declare function getSkillDirName(source: string): string;
44
+ /**
45
+ * Delete a directory recursively
46
+ */
47
+ export declare function deleteDirectory(dirPath: string): void;
48
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAExC,eAAO,MAAM,UAAU,WAAW,CAAC;AACnC,eAAO,MAAM,aAAa,4BAA4B,CAAC;AAEvD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAGvD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAGvD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAGzD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,aAAa,EAAE,CAc/D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAGhF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAQ9E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI,CAI9E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOtD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAIrD"}
package/dist/utils.js ADDED
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.METADATA_FILE = exports.SKILLS_DIR = void 0;
37
+ exports.getLocalClaudePath = getLocalClaudePath;
38
+ exports.getGlobalClaudePath = getGlobalClaudePath;
39
+ exports.getSkillsPath = getSkillsPath;
40
+ exports.ensureSkillsDir = ensureSkillsDir;
41
+ exports.getMetadataPath = getMetadataPath;
42
+ exports.readMetadata = readMetadata;
43
+ exports.writeMetadata = writeMetadata;
44
+ exports.addSkillMetadata = addSkillMetadata;
45
+ exports.removeSkillMetadata = removeSkillMetadata;
46
+ exports.getSkillDirName = getSkillDirName;
47
+ exports.deleteDirectory = deleteDirectory;
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const os = __importStar(require("os"));
51
+ exports.SKILLS_DIR = 'skills';
52
+ exports.METADATA_FILE = '.lmskills-metadata.json';
53
+ /**
54
+ * Get the path to the local .claude directory (project-specific)
55
+ */
56
+ function getLocalClaudePath() {
57
+ const cwd = process.cwd();
58
+ return path.join(cwd, '.claude');
59
+ }
60
+ /**
61
+ * Get the path to the global .claude directory (user-wide)
62
+ */
63
+ function getGlobalClaudePath() {
64
+ return path.join(os.homedir(), '.claude');
65
+ }
66
+ /**
67
+ * Get the skills directory path
68
+ */
69
+ function getSkillsPath(isGlobal) {
70
+ const claudePath = isGlobal ? getGlobalClaudePath() : getLocalClaudePath();
71
+ return path.join(claudePath, exports.SKILLS_DIR);
72
+ }
73
+ /**
74
+ * Ensure the skills directory exists
75
+ */
76
+ function ensureSkillsDir(isGlobal) {
77
+ const skillsPath = getSkillsPath(isGlobal);
78
+ fs.mkdirSync(skillsPath, { recursive: true });
79
+ }
80
+ /**
81
+ * Get metadata file path
82
+ */
83
+ function getMetadataPath(isGlobal) {
84
+ const skillsPath = getSkillsPath(isGlobal);
85
+ return path.join(skillsPath, exports.METADATA_FILE);
86
+ }
87
+ /**
88
+ * Read metadata for all installed skills
89
+ */
90
+ function readMetadata(isGlobal) {
91
+ const metadataPath = getMetadataPath(isGlobal);
92
+ if (!fs.existsSync(metadataPath)) {
93
+ return [];
94
+ }
95
+ try {
96
+ const content = fs.readFileSync(metadataPath, 'utf-8');
97
+ return JSON.parse(content);
98
+ }
99
+ catch (error) {
100
+ console.error(`Error reading metadata: ${error}`);
101
+ return [];
102
+ }
103
+ }
104
+ /**
105
+ * Write metadata for installed skills
106
+ */
107
+ function writeMetadata(metadata, isGlobal) {
108
+ const metadataPath = getMetadataPath(isGlobal);
109
+ fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
110
+ }
111
+ /**
112
+ * Add a skill to metadata
113
+ */
114
+ function addSkillMetadata(skill, isGlobal) {
115
+ const metadata = readMetadata(isGlobal);
116
+ // Remove existing entry if it exists
117
+ const filtered = metadata.filter(s => s.name !== skill.name);
118
+ filtered.push(skill);
119
+ writeMetadata(filtered, isGlobal);
120
+ }
121
+ /**
122
+ * Remove a skill from metadata
123
+ */
124
+ function removeSkillMetadata(skillName, isGlobal) {
125
+ const metadata = readMetadata(isGlobal);
126
+ const filtered = metadata.filter(s => s.name !== skillName);
127
+ writeMetadata(filtered, isGlobal);
128
+ }
129
+ /**
130
+ * Get a skill's directory name from its source URL
131
+ */
132
+ function getSkillDirName(source) {
133
+ // Extract a clean name from the GitHub URL
134
+ const parts = source.split('/').filter(Boolean);
135
+ const lastPart = parts[parts.length - 1];
136
+ // Remove .git suffix if present
137
+ return lastPart.replace(/\.git$/, '');
138
+ }
139
+ /**
140
+ * Delete a directory recursively
141
+ */
142
+ function deleteDirectory(dirPath) {
143
+ if (fs.existsSync(dirPath)) {
144
+ fs.rmSync(dirPath, { recursive: true, force: true });
145
+ }
146
+ }
147
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "lmskills-cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI tool to fetch and install Claude skills from GitHub",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "lmskills": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsc --watch",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "keywords": [
15
+ "claude",
16
+ "skills",
17
+ "cli",
18
+ "ai",
19
+ "llm"
20
+ ],
21
+ "author": "",
22
+ "license": "MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/flinstonedev/lmskills.git",
26
+ "directory": "cli"
27
+ },
28
+ "homepage": "https://github.com/flinstonedev/lmskills/tree/main/cli#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/flinstonedev/lmskills/issues"
31
+ },
32
+ "dependencies": {
33
+ "commander": "^12.1.0",
34
+ "chalk": "^4.1.2",
35
+ "node-fetch": "^2.7.0",
36
+ "ora": "^5.4.1"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^22.10.5",
40
+ "@types/node-fetch": "^2.6.12",
41
+ "typescript": "^5.7.2"
42
+ },
43
+ "engines": {
44
+ "node": ">=18.0.0"
45
+ }
46
+ }