agent-skills-cli 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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +226 -0
  3. package/dist/cli/index.d.ts +7 -0
  4. package/dist/cli/index.d.ts.map +1 -0
  5. package/dist/cli/index.js +1181 -0
  6. package/dist/cli/index.js.map +1 -0
  7. package/dist/core/executor.d.ts +22 -0
  8. package/dist/core/executor.d.ts.map +1 -0
  9. package/dist/core/executor.js +147 -0
  10. package/dist/core/executor.js.map +1 -0
  11. package/dist/core/index.d.ts +12 -0
  12. package/dist/core/index.d.ts.map +1 -0
  13. package/dist/core/index.js +17 -0
  14. package/dist/core/index.js.map +1 -0
  15. package/dist/core/injector.d.ts +24 -0
  16. package/dist/core/injector.d.ts.map +1 -0
  17. package/dist/core/injector.js +99 -0
  18. package/dist/core/injector.js.map +1 -0
  19. package/dist/core/loader.d.ts +39 -0
  20. package/dist/core/loader.d.ts.map +1 -0
  21. package/dist/core/loader.js +161 -0
  22. package/dist/core/loader.js.map +1 -0
  23. package/dist/core/marketplace.d.ts +55 -0
  24. package/dist/core/marketplace.d.ts.map +1 -0
  25. package/dist/core/marketplace.js +399 -0
  26. package/dist/core/marketplace.js.map +1 -0
  27. package/dist/core/skillsmp.d.ts +38 -0
  28. package/dist/core/skillsmp.d.ts.map +1 -0
  29. package/dist/core/skillsmp.js +142 -0
  30. package/dist/core/skillsmp.js.map +1 -0
  31. package/dist/core/validator.d.ts +18 -0
  32. package/dist/core/validator.d.ts.map +1 -0
  33. package/dist/core/validator.js +177 -0
  34. package/dist/core/validator.js.map +1 -0
  35. package/dist/index.d.ts +5 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +5 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/types/index.d.ts +108 -0
  40. package/dist/types/index.d.ts.map +1 -0
  41. package/dist/types/index.js +6 -0
  42. package/dist/types/index.js.map +1 -0
  43. package/dist/types/marketplace.d.ts +81 -0
  44. package/dist/types/marketplace.d.ts.map +1 -0
  45. package/dist/types/marketplace.js +20 -0
  46. package/dist/types/marketplace.js.map +1 -0
  47. package/package.json +59 -0
@@ -0,0 +1,1181 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Agent Skills CLI
4
+ * Universal CLI for managing Agent Skills across Cursor, Claude Code, GitHub Copilot, OpenAI Codex
5
+ */
6
+ import { Command } from 'commander';
7
+ import chalk from 'chalk';
8
+ import inquirer from 'inquirer';
9
+ import ora from 'ora';
10
+ import { discoverSkills, loadSkill, validateMetadata, validateBody, formatValidationResult, generateSkillsPromptXML, generateFullSkillsContext, listSkillResources, listMarketplaceSkills, installSkill, uninstallSkill, getInstalledSkills, listMarketplaces, addMarketplace, checkUpdates, fetchSkillsMP, installFromGitHubUrl } from '../core/index.js';
11
+ const program = new Command();
12
+ // Main flow when running `skills` - go straight to install
13
+ async function showMainMenu() {
14
+ console.log(chalk.bold.cyan('\nšŸš€ Agent Skills CLI\n'));
15
+ // Step 1: Select target agents
16
+ const { agents } = await inquirer.prompt([
17
+ {
18
+ type: 'checkbox',
19
+ name: 'agents',
20
+ message: 'Select AI agents to install skills for:',
21
+ choices: [
22
+ { name: 'Cursor', value: 'cursor', checked: true },
23
+ { name: 'Claude Code', value: 'claude', checked: true },
24
+ { name: 'GitHub Copilot', value: 'copilot', checked: true },
25
+ { name: 'OpenAI Codex', value: 'codex', checked: false },
26
+ { name: 'Antigravity', value: 'antigravity', checked: true }
27
+ ]
28
+ }
29
+ ]);
30
+ if (agents.length === 0) {
31
+ console.log(chalk.yellow('\nNo agents selected. Exiting.\n'));
32
+ return;
33
+ }
34
+ // Step 2: Fetch skills from SkillsMP (40k+ skills, instant)
35
+ const spinner = ora('Fetching skills from SkillsMP...').start();
36
+ let marketplaceSkills = [];
37
+ let total = 0;
38
+ try {
39
+ const result = await fetchSkillsMP({ limit: 100, sortBy: 'stars' });
40
+ marketplaceSkills = result.skills;
41
+ total = result.total;
42
+ spinner.succeed(`Found ${total.toLocaleString()} skills (showing top 100 by stars)`);
43
+ }
44
+ catch (err) {
45
+ spinner.fail('SkillsMP unavailable, falling back to GitHub...');
46
+ marketplaceSkills = await listMarketplaceSkills();
47
+ }
48
+ if (marketplaceSkills.length === 0) {
49
+ console.log(chalk.yellow('No skills found.'));
50
+ return;
51
+ }
52
+ // Step 3: Select skills to install
53
+ const choices = marketplaceSkills.map((skill) => ({
54
+ name: `${skill.name} ${skill.stars ? `(⭐${skill.stars.toLocaleString()})` : ''} - ${skill.description?.slice(0, 40) || ''}...`,
55
+ value: { name: skill.name, githubUrl: skill.githubUrl || '' },
56
+ short: skill.name
57
+ }));
58
+ const { selectedSkills } = await inquirer.prompt([
59
+ {
60
+ type: 'checkbox',
61
+ name: 'selectedSkills',
62
+ message: 'Select skills to install (Space to select, Enter to confirm):',
63
+ choices,
64
+ pageSize: 20,
65
+ loop: false
66
+ }
67
+ ]);
68
+ if (selectedSkills.length === 0) {
69
+ console.log(chalk.yellow('\nNo skills selected. Exiting.\n'));
70
+ return;
71
+ }
72
+ // Step 4: Install skills from GitHub URLs
73
+ console.log('');
74
+ const homedir = (await import('os')).homedir();
75
+ const skillsDir = `${homedir}/.antigravity/skills`;
76
+ for (const skill of selectedSkills) {
77
+ const installSpinner = ora(`Installing ${skill.name}...`).start();
78
+ try {
79
+ if (skill.githubUrl) {
80
+ // Install directly from GitHub URL (SkillsMP skills)
81
+ await installFromGitHubUrl(skill.githubUrl, skillsDir);
82
+ installSpinner.succeed(`Installed: ${skill.name}`);
83
+ }
84
+ else {
85
+ // Fallback to marketplace install
86
+ await installSkill(skill.name);
87
+ installSpinner.succeed(`Installed: ${skill.name}`);
88
+ }
89
+ }
90
+ catch (err) {
91
+ installSpinner.fail(`Failed: ${skill.name} - ${err.message || err}`);
92
+ }
93
+ }
94
+ // Step 5: Export to selected agents
95
+ console.log('');
96
+ const allSkills = await discoverSkills();
97
+ const { mkdir, writeFile, appendFile } = await import('fs/promises');
98
+ const { join } = await import('path');
99
+ const { existsSync } = await import('fs');
100
+ const fs = { mkdir, writeFile, appendFile, join, existsSync };
101
+ for (const agent of agents) {
102
+ const exportSpinner = ora(`Exporting to ${agent}...`).start();
103
+ await exportToAgent(agent, allSkills, '.', fs);
104
+ exportSpinner.succeed(`Exported to ${agent}`);
105
+ }
106
+ console.log(chalk.bold.green('\n✨ Done! Skills installed and ready to use.\n'));
107
+ }
108
+ async function interactiveInstall() {
109
+ // Step 1: Select target agent(s)
110
+ const { agents } = await inquirer.prompt([
111
+ {
112
+ type: 'checkbox',
113
+ name: 'agents',
114
+ message: 'Which AI agents will you use these skills with?',
115
+ choices: [
116
+ { name: 'Cursor', value: 'cursor', checked: true },
117
+ { name: 'Claude Code', value: 'claude', checked: true },
118
+ { name: 'GitHub Copilot', value: 'copilot', checked: true },
119
+ { name: 'OpenAI Codex', value: 'codex', checked: false }
120
+ ]
121
+ }
122
+ ]);
123
+ if (agents.length === 0) {
124
+ console.log(chalk.yellow('No agents selected.'));
125
+ return;
126
+ }
127
+ // Step 2: Fetch and select skills
128
+ const spinner = ora('Fetching skills from marketplace...').start();
129
+ const skills = await listMarketplaceSkills();
130
+ spinner.stop();
131
+ if (skills.length === 0) {
132
+ console.log(chalk.yellow('No skills found.'));
133
+ return;
134
+ }
135
+ const choices = skills.map(skill => ({
136
+ name: `${skill.name} - ${skill.description?.slice(0, 45) || 'No description'}...`,
137
+ value: skill.name,
138
+ short: skill.name
139
+ }));
140
+ const { selectedSkills } = await inquirer.prompt([
141
+ {
142
+ type: 'checkbox',
143
+ name: 'selectedSkills',
144
+ message: 'Select skills to install (Space to select):',
145
+ choices,
146
+ pageSize: 12
147
+ }
148
+ ]);
149
+ if (selectedSkills.length === 0) {
150
+ console.log(chalk.yellow('No skills selected.'));
151
+ return;
152
+ }
153
+ // Step 3: Install skills
154
+ console.log('');
155
+ for (const skillName of selectedSkills) {
156
+ const installSpinner = ora(`Installing ${skillName}...`).start();
157
+ try {
158
+ await installSkill(skillName);
159
+ installSpinner.succeed(`Installed: ${skillName}`);
160
+ }
161
+ catch (err) {
162
+ installSpinner.fail(`Failed: ${skillName}`);
163
+ }
164
+ }
165
+ // Step 4: Export to selected agents
166
+ console.log('');
167
+ const exportSpinner = ora('Exporting to selected agents...').start();
168
+ const allSkills = await discoverSkills();
169
+ const { mkdir, writeFile, appendFile } = await import('fs/promises');
170
+ const { join } = await import('path');
171
+ const { existsSync } = await import('fs');
172
+ const fs = { mkdir, writeFile, appendFile, join, existsSync };
173
+ exportSpinner.stop();
174
+ for (const agent of agents) {
175
+ const agentSpinner = ora(`Exporting to ${agent}...`).start();
176
+ await exportToAgent(agent, allSkills, '.', fs);
177
+ agentSpinner.succeed(`Exported to ${agent}`);
178
+ }
179
+ console.log(chalk.bold.green('\n✨ Done! Skills installed and exported.\n'));
180
+ }
181
+ async function interactiveExport() {
182
+ const skills = await discoverSkills();
183
+ if (skills.length === 0) {
184
+ console.log(chalk.yellow('No skills found to export.'));
185
+ return;
186
+ }
187
+ const { agents } = await inquirer.prompt([
188
+ {
189
+ type: 'checkbox',
190
+ name: 'agents',
191
+ message: 'Select target AI agents:',
192
+ choices: [
193
+ { name: 'Cursor (.cursor/skills/)', value: 'cursor', checked: true },
194
+ { name: 'Claude Code (.claude/skills/)', value: 'claude', checked: true },
195
+ { name: 'GitHub Copilot (.github/skills/)', value: 'copilot', checked: true },
196
+ { name: 'OpenAI Codex (.codex/skills/)', value: 'codex', checked: false }
197
+ ]
198
+ }
199
+ ]);
200
+ if (agents.length === 0) {
201
+ console.log(chalk.yellow('No agents selected.'));
202
+ return;
203
+ }
204
+ const { mkdir, writeFile, appendFile } = await import('fs/promises');
205
+ const { join } = await import('path');
206
+ const { existsSync } = await import('fs');
207
+ const fs = { mkdir, writeFile, appendFile, join, existsSync };
208
+ console.log('');
209
+ for (const agent of agents) {
210
+ const spinner = ora(`Exporting to ${agent}...`).start();
211
+ await exportToAgent(agent, skills, '.', fs);
212
+ spinner.succeed();
213
+ }
214
+ console.log(chalk.bold.green('\nāœ“ Export complete!\n'));
215
+ }
216
+ program
217
+ .name('skills')
218
+ .description('Agent Skills CLI - Manage skills for Cursor, Claude Code, GitHub Copilot, OpenAI Codex')
219
+ .version('1.0.0')
220
+ .action(showMainMenu);
221
+ // List command
222
+ program
223
+ .command('list')
224
+ .description('List all discovered skills')
225
+ .option('-p, --paths <paths...>', 'Custom search paths')
226
+ .option('-v, --verbose', 'Show detailed information')
227
+ .action(async (options) => {
228
+ try {
229
+ const config = options.paths ? { searchPaths: options.paths } : {};
230
+ const skills = await discoverSkills(config);
231
+ if (skills.length === 0) {
232
+ console.log(chalk.yellow('No skills found.'));
233
+ console.log(chalk.gray('Skills are searched in:'));
234
+ console.log(chalk.gray(' - ~/.antigravity/skills/'));
235
+ console.log(chalk.gray(' - .antigravity/skills/'));
236
+ console.log(chalk.gray(' - ./skills/'));
237
+ return;
238
+ }
239
+ console.log(chalk.bold(`\nFound ${skills.length} skill(s):\n`));
240
+ for (const skill of skills) {
241
+ console.log(chalk.cyan(` ${skill.name}`));
242
+ if (options.verbose) {
243
+ console.log(chalk.gray(` ${skill.description}`));
244
+ console.log(chalk.gray(` Path: ${skill.path}`));
245
+ }
246
+ }
247
+ console.log('');
248
+ }
249
+ catch (error) {
250
+ console.error(chalk.red('Error listing skills:'), error);
251
+ process.exit(1);
252
+ }
253
+ });
254
+ // Validate command
255
+ program
256
+ .command('validate <path>')
257
+ .description('Validate a skill against the Agent Skills specification')
258
+ .action(async (path) => {
259
+ try {
260
+ const skill = await loadSkill(path);
261
+ if (!skill) {
262
+ console.error(chalk.red(`Skill not found at: ${path}`));
263
+ process.exit(1);
264
+ }
265
+ console.log(chalk.bold(`\nValidating: ${skill.metadata.name}\n`));
266
+ // Validate metadata
267
+ const metadataResult = validateMetadata(skill.metadata);
268
+ console.log(chalk.underline('Metadata:'));
269
+ console.log(formatValidationResult(metadataResult));
270
+ // Validate body
271
+ const bodyResult = validateBody(skill.body);
272
+ console.log(chalk.underline('\nBody Content:'));
273
+ console.log(formatValidationResult(bodyResult));
274
+ // Overall result
275
+ const isValid = metadataResult.valid && bodyResult.valid;
276
+ console.log('\n' + '─'.repeat(40));
277
+ if (isValid) {
278
+ console.log(chalk.green.bold('āœ“ Skill is valid'));
279
+ }
280
+ else {
281
+ console.log(chalk.red.bold('āœ— Skill has validation errors'));
282
+ process.exit(1);
283
+ }
284
+ }
285
+ catch (error) {
286
+ console.error(chalk.red('Error validating skill:'), error);
287
+ process.exit(1);
288
+ }
289
+ });
290
+ // Show command
291
+ program
292
+ .command('show <name>')
293
+ .description('Show detailed information about a skill')
294
+ .action(async (name) => {
295
+ try {
296
+ const skills = await discoverSkills();
297
+ const skillRef = skills.find(s => s.name === name);
298
+ if (!skillRef) {
299
+ console.error(chalk.red(`Skill not found: ${name}`));
300
+ console.log(chalk.gray('Available skills:'), skills.map(s => s.name).join(', ') || 'none');
301
+ process.exit(1);
302
+ }
303
+ const skill = await loadSkill(skillRef.path);
304
+ if (!skill) {
305
+ console.error(chalk.red(`Could not load skill: ${name}`));
306
+ process.exit(1);
307
+ }
308
+ console.log(chalk.bold(`\n${skill.metadata.name}`));
309
+ console.log('─'.repeat(40));
310
+ console.log(chalk.cyan('Description:'), skill.metadata.description);
311
+ console.log(chalk.cyan('Path:'), skill.path);
312
+ if (skill.metadata.license) {
313
+ console.log(chalk.cyan('License:'), skill.metadata.license);
314
+ }
315
+ if (skill.metadata.compatibility) {
316
+ console.log(chalk.cyan('Compatibility:'), skill.metadata.compatibility);
317
+ }
318
+ // List resources
319
+ const resources = await listSkillResources(skill.path);
320
+ if (resources.scripts.length > 0) {
321
+ console.log(chalk.cyan('\nScripts:'));
322
+ resources.scripts.forEach(s => console.log(chalk.gray(` - ${s}`)));
323
+ }
324
+ if (resources.references.length > 0) {
325
+ console.log(chalk.cyan('\nReferences:'));
326
+ resources.references.forEach(r => console.log(chalk.gray(` - ${r}`)));
327
+ }
328
+ if (resources.assets.length > 0) {
329
+ console.log(chalk.cyan('\nAssets:'));
330
+ resources.assets.forEach(a => console.log(chalk.gray(` - ${a}`)));
331
+ }
332
+ // Body preview
333
+ const bodyLines = skill.body.split('\n').slice(0, 10);
334
+ console.log(chalk.cyan('\nInstructions (preview):'));
335
+ console.log(chalk.gray(bodyLines.join('\n')));
336
+ if (skill.body.split('\n').length > 10) {
337
+ console.log(chalk.gray('...'));
338
+ }
339
+ console.log('');
340
+ }
341
+ catch (error) {
342
+ console.error(chalk.red('Error showing skill:'), error);
343
+ process.exit(1);
344
+ }
345
+ });
346
+ // Prompt command - generate system prompt XML
347
+ program
348
+ .command('prompt')
349
+ .description('Generate system prompt XML for discovered skills')
350
+ .option('-f, --full', 'Include full skill system instructions')
351
+ .action(async (options) => {
352
+ try {
353
+ const skills = await discoverSkills();
354
+ if (skills.length === 0) {
355
+ console.log(chalk.yellow('No skills found.'));
356
+ return;
357
+ }
358
+ if (options.full) {
359
+ const context = generateFullSkillsContext(skills);
360
+ console.log(context);
361
+ }
362
+ else {
363
+ const { xml, skillCount, estimatedTokens } = generateSkillsPromptXML(skills);
364
+ console.log(xml);
365
+ console.log(chalk.gray(`\n# ${skillCount} skills, ~${estimatedTokens} tokens`));
366
+ }
367
+ }
368
+ catch (error) {
369
+ console.error(chalk.red('Error generating prompt:'), error);
370
+ process.exit(1);
371
+ }
372
+ });
373
+ // Init command - create a new skill
374
+ program
375
+ .command('init <name>')
376
+ .description('Create a new skill from template')
377
+ .option('-d, --directory <dir>', 'Directory to create skill in', './skills')
378
+ .action(async (name, options) => {
379
+ try {
380
+ const { mkdir, writeFile } = await import('fs/promises');
381
+ const { join } = await import('path');
382
+ const skillDir = join(options.directory, name);
383
+ // Create directories
384
+ await mkdir(join(skillDir, 'scripts'), { recursive: true });
385
+ await mkdir(join(skillDir, 'references'), { recursive: true });
386
+ await mkdir(join(skillDir, 'assets'), { recursive: true });
387
+ // Create SKILL.md
388
+ const skillMd = `---
389
+ name: ${name}
390
+ description: Brief description of what this skill does and when to use it.
391
+ license: MIT
392
+ metadata:
393
+ author: your-name
394
+ version: "1.0"
395
+ ---
396
+
397
+ # ${name.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}
398
+
399
+ ## When to use this skill
400
+
401
+ Use this skill when the user needs to...
402
+
403
+ ## Instructions
404
+
405
+ 1. First step
406
+ 2. Second step
407
+ 3. Third step
408
+
409
+ ## Examples
410
+
411
+ ### Example 1
412
+
413
+ \`\`\`
414
+ Example input or command
415
+ \`\`\`
416
+
417
+ ## Best practices
418
+
419
+ - Best practice 1
420
+ - Best practice 2
421
+ `;
422
+ await writeFile(join(skillDir, 'SKILL.md'), skillMd);
423
+ console.log(chalk.green(`āœ“ Created skill: ${name}`));
424
+ console.log(chalk.gray(` Path: ${skillDir}`));
425
+ console.log(chalk.gray('\nNext steps:'));
426
+ console.log(chalk.gray(' 1. Edit SKILL.md with your instructions'));
427
+ console.log(chalk.gray(' 2. Add scripts to scripts/'));
428
+ console.log(chalk.gray(' 3. Run: skills validate ' + skillDir));
429
+ }
430
+ catch (error) {
431
+ console.error(chalk.red('Error creating skill:'), error);
432
+ process.exit(1);
433
+ }
434
+ });
435
+ // ============================================
436
+ // MARKETPLACE COMMANDS
437
+ // ============================================
438
+ // Market list - list skills from SkillsMP (40k+ skills)
439
+ program
440
+ .command('market-list')
441
+ .alias('ml')
442
+ .description('List skills from SkillsMP marketplace (40k+ skills)')
443
+ .option('-l, --limit <number>', 'Number of skills to show', '50')
444
+ .option('-p, --page <number>', 'Page number', '1')
445
+ .option('--legacy', 'Use legacy GitHub sources instead of SkillsMP')
446
+ .action(async (options) => {
447
+ try {
448
+ if (options.legacy) {
449
+ // Legacy mode: fetch from configured GitHub sources
450
+ console.log(chalk.bold('\nFetching skills from GitHub sources...\n'));
451
+ const skills = await listMarketplaceSkills();
452
+ if (skills.length === 0) {
453
+ console.log(chalk.yellow('No skills found.'));
454
+ return;
455
+ }
456
+ const bySource = new Map();
457
+ for (const skill of skills) {
458
+ const sourceId = skill.source.id;
459
+ if (!bySource.has(sourceId)) {
460
+ bySource.set(sourceId, []);
461
+ }
462
+ bySource.get(sourceId).push(skill);
463
+ }
464
+ for (const [sourceId, sourceSkills] of bySource) {
465
+ const source = sourceSkills[0].source;
466
+ console.log(chalk.bold.cyan(`\nšŸ“¦ ${source.name}`));
467
+ console.log(chalk.gray(` ${source.owner}/${source.repo}`));
468
+ if (source.verified) {
469
+ console.log(chalk.green(' āœ“ Verified'));
470
+ }
471
+ console.log('');
472
+ for (const skill of sourceSkills) {
473
+ console.log(chalk.white(` ${skill.name}`));
474
+ if (skill.description) {
475
+ const desc = skill.description.length > 60
476
+ ? skill.description.slice(0, 60) + '...'
477
+ : skill.description;
478
+ console.log(chalk.gray(` ${desc}`));
479
+ }
480
+ }
481
+ }
482
+ console.log(chalk.gray(`\nTotal: ${skills.length} skills from ${bySource.size} sources`));
483
+ }
484
+ else {
485
+ // SkillsMP mode: fetch from API
486
+ console.log(chalk.bold('\n🌐 SkillsMP Marketplace\n'));
487
+ const limit = parseInt(options.limit) || 50;
488
+ const page = parseInt(options.page) || 1;
489
+ const result = await fetchSkillsMP({ limit, page, sortBy: 'stars' });
490
+ console.log(chalk.gray(`Showing ${result.skills.length} of ${result.total.toLocaleString()} skills (page ${page})\n`));
491
+ for (const skill of result.skills) {
492
+ const stars = skill.stars ? chalk.yellow(`⭐${skill.stars.toLocaleString()}`) : '';
493
+ console.log(chalk.white(` ${skill.name} ${stars}`));
494
+ if (skill.description) {
495
+ const desc = skill.description.length > 55
496
+ ? skill.description.slice(0, 55) + '...'
497
+ : skill.description;
498
+ console.log(chalk.gray(` ${desc}`));
499
+ }
500
+ console.log(chalk.dim(` by ${skill.author || 'unknown'}`));
501
+ }
502
+ console.log(chalk.gray(`\nTotal: ${result.total.toLocaleString()} skills`));
503
+ if (result.hasNext) {
504
+ console.log(chalk.gray(`Next page: skills market-list --page ${page + 1}`));
505
+ }
506
+ }
507
+ console.log(chalk.gray('\nUse: skills (interactive) to install\n'));
508
+ }
509
+ catch (error) {
510
+ console.error(chalk.red('Error:'), error);
511
+ process.exit(1);
512
+ }
513
+ });
514
+ // Market search - search skills
515
+ program
516
+ .command('market-search <query>')
517
+ .alias('ms')
518
+ .description('Search skills on SkillsMP (40k+ skills)')
519
+ .option('-l, --limit <number>', 'Number of results', '20')
520
+ .action(async (query, options) => {
521
+ try {
522
+ console.log(chalk.bold(`\nšŸ” Searching SkillsMP for "${query}"...\n`));
523
+ const limit = parseInt(options.limit) || 20;
524
+ const result = await fetchSkillsMP({ search: query, limit, sortBy: 'stars' });
525
+ if (result.skills.length === 0) {
526
+ console.log(chalk.yellow(`No skills found matching "${query}"`));
527
+ return;
528
+ }
529
+ console.log(chalk.gray(`Found ${result.total.toLocaleString()} skills (showing top ${result.skills.length}):\n`));
530
+ for (const skill of result.skills) {
531
+ const stars = skill.stars ? chalk.yellow(`⭐${skill.stars.toLocaleString()}`) : '';
532
+ console.log(chalk.cyan(` ${skill.name} ${stars}`));
533
+ console.log(chalk.gray(` ${skill.description?.slice(0, 70)}${(skill.description?.length || 0) > 70 ? '...' : ''}`));
534
+ console.log(chalk.dim(` by ${skill.author || 'unknown'}`));
535
+ console.log('');
536
+ }
537
+ console.log(chalk.gray('Use: skills (interactive) to install\n'));
538
+ }
539
+ catch (error) {
540
+ console.error(chalk.red('Error searching skills:'), error);
541
+ process.exit(1);
542
+ }
543
+ });
544
+ // Install - Install a skill by name from SkillsMP
545
+ program
546
+ .command('install <name>')
547
+ .alias('i')
548
+ .description('Install a skill by name from SkillsMP')
549
+ .action(async (name) => {
550
+ try {
551
+ const homedir = (await import('os')).homedir();
552
+ const skillsDir = `${homedir}/.antigravity/skills`;
553
+ console.log(chalk.bold(`\nšŸ“¦ Searching for "${name}" on SkillsMP...\n`));
554
+ const result = await fetchSkillsMP({ search: name, limit: 20, sortBy: 'stars' });
555
+ // Find exact name match first
556
+ const exactMatch = result.skills.find(s => s.name.toLowerCase() === name.toLowerCase());
557
+ const skill = exactMatch || result.skills[0];
558
+ if (!skill) {
559
+ console.log(chalk.yellow(`No skill found matching "${name}"`));
560
+ console.log(chalk.gray('Try: skills market-search <query> to find skills\n'));
561
+ return;
562
+ }
563
+ const githubUrl = skill.githubUrl;
564
+ if (!githubUrl) {
565
+ console.log(chalk.red('Could not find GitHub URL for this skill'));
566
+ return;
567
+ }
568
+ console.log(chalk.gray(`Found: ${skill.name} by ${skill.author}`));
569
+ console.log(chalk.gray(`Installing from: ${githubUrl}\n`));
570
+ const installed = await installFromGitHubUrl(githubUrl, skillsDir);
571
+ console.log(chalk.green(`āœ“ Successfully installed: ${installed.name}`));
572
+ console.log(chalk.gray(` Path: ${installed.path}`));
573
+ console.log('');
574
+ }
575
+ catch (error) {
576
+ console.error(chalk.red('Error installing skill:'), error.message || error);
577
+ process.exit(1);
578
+ }
579
+ });
580
+ // Alias for backward compatibility
581
+ program
582
+ .command('market-install <name>')
583
+ .alias('mi')
584
+ .description('Install a skill (alias for: skills install)')
585
+ .action(async (name) => {
586
+ console.log(chalk.gray('Tip: Use `skills install <id-or-name>` directly\n'));
587
+ const { execSync } = await import('child_process');
588
+ try {
589
+ execSync(`"${process.argv[0]}" "${process.argv[1]}" install "${name}"`, { stdio: 'inherit' });
590
+ }
591
+ catch { }
592
+ });
593
+ // Install from URL - install directly from GitHub or SkillsMP URL
594
+ program
595
+ .command('install-url <url>')
596
+ .alias('iu')
597
+ .description('Install a skill from GitHub URL or SkillsMP page URL')
598
+ .action(async (url) => {
599
+ try {
600
+ let githubUrl = url;
601
+ // Convert SkillsMP URL to GitHub URL
602
+ // Format: https://skillsmp.com/skills/<id>
603
+ if (url.includes('skillsmp.com/skills/')) {
604
+ console.log(chalk.bold(`\nšŸ“¦ Fetching skill info from SkillsMP...`));
605
+ // Extract skill ID from URL
606
+ const skillId = url.split('/skills/').pop()?.replace(/\/$/, '');
607
+ // Fetch skill details from API
608
+ const response = await fetch(`https://skillsmp.com/api/skills/${skillId}`);
609
+ if (!response.ok) {
610
+ throw new Error('Could not find skill on SkillsMP');
611
+ }
612
+ const data = await response.json();
613
+ githubUrl = data.skill.githubUrl;
614
+ console.log(chalk.gray(`Found: ${data.skill.name} by ${data.skill.author}\n`));
615
+ }
616
+ // Validate GitHub URL
617
+ if (!githubUrl.includes('github.com')) {
618
+ console.log(chalk.red('Invalid URL. Please provide a GitHub URL or SkillsMP skill page URL.'));
619
+ return;
620
+ }
621
+ console.log(chalk.gray(`Installing from: ${githubUrl}\n`));
622
+ const homedir = (await import('os')).homedir();
623
+ const skillsDir = `${homedir}/.antigravity/skills`;
624
+ const installed = await installFromGitHubUrl(githubUrl, skillsDir);
625
+ console.log(chalk.green(`āœ“ Successfully installed: ${installed.name}`));
626
+ console.log(chalk.gray(` Path: ${installed.path}`));
627
+ console.log('');
628
+ }
629
+ catch (error) {
630
+ console.error(chalk.red('Error installing skill:'), error.message || error);
631
+ process.exit(1);
632
+ }
633
+ });
634
+ // Market uninstall - remove an installed skill
635
+ program
636
+ .command('market-uninstall <name>')
637
+ .alias('mu')
638
+ .description('Uninstall a marketplace-installed skill')
639
+ .action(async (name) => {
640
+ try {
641
+ await uninstallSkill(name);
642
+ console.log(chalk.green(`āœ“ Uninstalled: ${name}`));
643
+ }
644
+ catch (error) {
645
+ console.error(chalk.red('Error uninstalling skill:'), error);
646
+ process.exit(1);
647
+ }
648
+ });
649
+ // Market installed - show installed marketplace skills
650
+ program
651
+ .command('market-installed')
652
+ .alias('mind')
653
+ .description('List skills installed from marketplaces')
654
+ .action(async () => {
655
+ try {
656
+ const installed = await getInstalledSkills();
657
+ if (installed.length === 0) {
658
+ console.log(chalk.yellow('\nNo marketplace skills installed.'));
659
+ console.log(chalk.gray('Use: skills market-install <name> to install\n'));
660
+ return;
661
+ }
662
+ console.log(chalk.bold(`\nInstalled marketplace skills:\n`));
663
+ for (const skill of installed) {
664
+ console.log(chalk.cyan(` ${skill.name}`));
665
+ console.log(chalk.gray(` Path: ${skill.localPath}`));
666
+ if (skill.source) {
667
+ console.log(chalk.gray(` Source: ${skill.source.name}`));
668
+ }
669
+ if (skill.version) {
670
+ console.log(chalk.gray(` Version: ${skill.version}`));
671
+ }
672
+ console.log(chalk.gray(` Installed: ${skill.installedAt}`));
673
+ console.log('');
674
+ }
675
+ }
676
+ catch (error) {
677
+ console.error(chalk.red('Error listing installed skills:'), error);
678
+ process.exit(1);
679
+ }
680
+ });
681
+ // Market sources - list marketplace sources
682
+ program
683
+ .command('market-sources')
684
+ .description('List registered marketplace sources')
685
+ .action(async () => {
686
+ try {
687
+ // Show SkillsMP as primary
688
+ console.log(chalk.bold('\n🌐 Primary Marketplace:\n'));
689
+ console.log(chalk.cyan(` SkillsMP`) + chalk.green(' āœ“'));
690
+ console.log(chalk.gray(` URL: https://skillsmp.com`));
691
+ console.log(chalk.gray(` Skills: 40,000+`));
692
+ console.log(chalk.gray(` The largest Agent Skills marketplace`));
693
+ console.log('');
694
+ // Show legacy sources
695
+ const sources = await listMarketplaces();
696
+ if (sources.length > 0) {
697
+ console.log(chalk.bold('Legacy GitHub Sources:\n'));
698
+ for (const source of sources) {
699
+ const verified = source.verified ? chalk.green(' āœ“') : '';
700
+ console.log(chalk.cyan(` ${source.name}${verified}`));
701
+ console.log(chalk.gray(` ID: ${source.id}`));
702
+ console.log(chalk.gray(` Repo: ${source.owner}/${source.repo}`));
703
+ if (source.description) {
704
+ console.log(chalk.gray(` ${source.description}`));
705
+ }
706
+ console.log('');
707
+ }
708
+ }
709
+ }
710
+ catch (error) {
711
+ console.error(chalk.red('Error listing sources:'), error);
712
+ process.exit(1);
713
+ }
714
+ });
715
+ // Market add-source - add a new marketplace
716
+ program
717
+ .command('market-add-source')
718
+ .description('Add a custom marketplace source')
719
+ .requiredOption('--id <id>', 'Unique identifier')
720
+ .requiredOption('--name <name>', 'Display name')
721
+ .requiredOption('--owner <owner>', 'GitHub owner')
722
+ .requiredOption('--repo <repo>', 'GitHub repository')
723
+ .option('--branch <branch>', 'Branch name', 'main')
724
+ .option('--path <path>', 'Path to skills directory', 'skills')
725
+ .action(async (options) => {
726
+ try {
727
+ await addMarketplace({
728
+ id: options.id,
729
+ name: options.name,
730
+ owner: options.owner,
731
+ repo: options.repo,
732
+ branch: options.branch,
733
+ skillsPath: options.path,
734
+ verified: false
735
+ });
736
+ console.log(chalk.green(`āœ“ Added marketplace: ${options.name}`));
737
+ }
738
+ catch (error) {
739
+ console.error(chalk.red('Error adding marketplace:'), error);
740
+ process.exit(1);
741
+ }
742
+ });
743
+ // Market update-check - check for updates
744
+ program
745
+ .command('market-update-check')
746
+ .alias('muc')
747
+ .description('Check for updates to installed skills')
748
+ .action(async () => {
749
+ try {
750
+ console.log(chalk.bold('\nChecking for updates...\n'));
751
+ const updates = await checkUpdates();
752
+ if (updates.length === 0) {
753
+ console.log(chalk.yellow('No installed marketplace skills to check.'));
754
+ return;
755
+ }
756
+ const hasUpdates = updates.filter(u => u.hasUpdate);
757
+ if (hasUpdates.length === 0) {
758
+ console.log(chalk.green('All skills are up to date! āœ“'));
759
+ }
760
+ else {
761
+ console.log(chalk.yellow(`${hasUpdates.length} skill(s) have updates available:\n`));
762
+ for (const update of hasUpdates) {
763
+ console.log(chalk.cyan(` ${update.skill.name}`));
764
+ console.log(chalk.gray(` Current: ${update.currentVersion || 'unknown'}`));
765
+ console.log(chalk.green(` Latest: ${update.latestVersion}`));
766
+ console.log('');
767
+ }
768
+ console.log(chalk.gray('To update, uninstall and reinstall the skill.'));
769
+ }
770
+ }
771
+ catch (error) {
772
+ console.error(chalk.red('Error checking updates:'), error);
773
+ process.exit(1);
774
+ }
775
+ });
776
+ // ============================================
777
+ // WORKFLOW SYNC COMMAND
778
+ // ============================================
779
+ // Sync - copy skills to .agent/workflows for Antigravity auto-discovery
780
+ program
781
+ .command('sync')
782
+ .description('Sync skills to .agent/workflows/ for Antigravity auto-discovery')
783
+ .option('-d, --directory <dir>', 'Target project directory', '.')
784
+ .option('-a, --all', 'Sync all discovered skills')
785
+ .option('-n, --name <name>', 'Sync a specific skill by name')
786
+ .action(async (options) => {
787
+ try {
788
+ const { mkdir, writeFile, readFile, cp } = await import('fs/promises');
789
+ const { join } = await import('path');
790
+ const { existsSync } = await import('fs');
791
+ const workflowsDir = join(options.directory, '.agent', 'workflows');
792
+ await mkdir(workflowsDir, { recursive: true });
793
+ const skills = await discoverSkills();
794
+ if (skills.length === 0) {
795
+ console.log(chalk.yellow('No skills found to sync.'));
796
+ return;
797
+ }
798
+ // Filter skills if specific name provided
799
+ const toSync = options.name
800
+ ? skills.filter(s => s.name === options.name)
801
+ : options.all
802
+ ? skills
803
+ : skills; // Default: sync all
804
+ if (toSync.length === 0) {
805
+ console.log(chalk.yellow(`Skill not found: ${options.name}`));
806
+ return;
807
+ }
808
+ console.log(chalk.bold(`\nSyncing ${toSync.length} skill(s) to ${workflowsDir}...\n`));
809
+ for (const skillRef of toSync) {
810
+ try {
811
+ const skill = await loadSkill(skillRef.path);
812
+ if (!skill)
813
+ continue;
814
+ // Create workflow file from skill
815
+ const workflowContent = `---
816
+ description: ${skill.metadata.description.slice(0, 100)}
817
+ ---
818
+
819
+ ${skill.body}
820
+ `;
821
+ const workflowPath = join(workflowsDir, `${skill.metadata.name}.md`);
822
+ await writeFile(workflowPath, workflowContent);
823
+ console.log(chalk.green(` āœ“ ${skill.metadata.name}`));
824
+ console.log(chalk.gray(` → ${workflowPath}`));
825
+ }
826
+ catch (err) {
827
+ console.log(chalk.red(` āœ— ${skillRef.name}: ${err}`));
828
+ }
829
+ }
830
+ console.log(chalk.bold.green(`\nāœ“ Skills synced to .agent/workflows/`));
831
+ console.log(chalk.gray(`\nNow you can use: "/${toSync.map(s => s.name).join('", "/')}"`));
832
+ console.log(chalk.gray('Or just say: "Use the [skill-name] skill to..."'));
833
+ }
834
+ catch (error) {
835
+ console.error(chalk.red('Error syncing skills:'), error);
836
+ process.exit(1);
837
+ }
838
+ });
839
+ // Export - convert skills to different AI agent formats
840
+ program
841
+ .command('export')
842
+ .description('Export skills to different AI agent formats (Copilot, Cursor, Claude, Codex)')
843
+ .option('-t, --target <agent>', 'Target agent: copilot, cursor, claude, codex, antigravity, all', 'all')
844
+ .option('-d, --directory <dir>', 'Project directory', '.')
845
+ .option('-n, --name <name>', 'Export specific skill only')
846
+ .action(async (options) => {
847
+ try {
848
+ const { mkdir, writeFile, appendFile } = await import('fs/promises');
849
+ const { join } = await import('path');
850
+ const { existsSync } = await import('fs');
851
+ const skills = await discoverSkills();
852
+ const toExport = options.name
853
+ ? skills.filter(s => s.name === options.name)
854
+ : skills;
855
+ if (toExport.length === 0) {
856
+ console.log(chalk.yellow('No skills found to export.'));
857
+ return;
858
+ }
859
+ const targets = options.target === 'all'
860
+ ? ['copilot', 'cursor', 'claude', 'codex', 'antigravity']
861
+ : [options.target];
862
+ console.log(chalk.bold(`\nExporting ${toExport.length} skill(s) to: ${targets.join(', ')}\n`));
863
+ for (const target of targets) {
864
+ await exportToAgent(target, toExport, options.directory, { mkdir, writeFile, appendFile, join, existsSync });
865
+ }
866
+ console.log(chalk.bold.green('\nāœ“ Export complete!'));
867
+ console.log(chalk.gray('\nGenerated files:'));
868
+ if (targets.includes('copilot') || targets.includes('all')) {
869
+ console.log(chalk.gray(' - .github/copilot-instructions.md'));
870
+ }
871
+ if (targets.includes('cursor') || targets.includes('all')) {
872
+ console.log(chalk.gray(' - .cursor/rules/<skill>/RULE.md'));
873
+ }
874
+ if (targets.includes('claude') || targets.includes('all')) {
875
+ console.log(chalk.gray(' - CLAUDE.md'));
876
+ }
877
+ if (targets.includes('codex') || targets.includes('all')) {
878
+ console.log(chalk.gray(' - AGENTS.md'));
879
+ }
880
+ if (targets.includes('antigravity') || targets.includes('all')) {
881
+ console.log(chalk.gray(' - .agent/workflows/<skill>.md'));
882
+ }
883
+ }
884
+ catch (error) {
885
+ console.error(chalk.red('Error exporting skills:'), error);
886
+ process.exit(1);
887
+ }
888
+ });
889
+ async function exportToAgent(target, skillRefs, projectDir, fs) {
890
+ const loadedSkills = [];
891
+ for (const ref of skillRefs) {
892
+ const skill = await loadSkill(ref.path);
893
+ if (skill)
894
+ loadedSkills.push(skill);
895
+ }
896
+ switch (target) {
897
+ case 'copilot':
898
+ await exportToCopilot(loadedSkills, projectDir, fs);
899
+ break;
900
+ case 'cursor':
901
+ await exportToCursor(loadedSkills, projectDir, fs);
902
+ break;
903
+ case 'claude':
904
+ await exportToClaude(loadedSkills, projectDir, fs);
905
+ break;
906
+ case 'codex':
907
+ await exportToCodex(loadedSkills, projectDir, fs);
908
+ break;
909
+ case 'antigravity':
910
+ await exportToAntigravity(loadedSkills, projectDir, fs);
911
+ break;
912
+ }
913
+ }
914
+ async function exportToCopilot(skills, projectDir, fs) {
915
+ // GitHub Copilot now uses Agent Skills standard: .github/skills/<name>/SKILL.md
916
+ // Also supports .claude/skills/ for compatibility
917
+ const copilotDir = fs.join(projectDir, '.github', 'skills');
918
+ await fs.mkdir(copilotDir, { recursive: true });
919
+ for (const skill of skills) {
920
+ const skillDir = fs.join(copilotDir, skill.metadata.name);
921
+ await fs.mkdir(skillDir, { recursive: true });
922
+ // Create SKILL.md in Agent Skills format
923
+ const content = `---
924
+ name: ${skill.metadata.name}
925
+ description: ${skill.metadata.description}
926
+ ---
927
+
928
+ ${skill.body}
929
+ `;
930
+ await fs.writeFile(fs.join(skillDir, 'SKILL.md'), content);
931
+ }
932
+ console.log(chalk.green(` āœ“ GitHub Copilot: .github/skills/<skill>/SKILL.md`));
933
+ }
934
+ async function exportToCursor(skills, projectDir, fs) {
935
+ // Cursor now uses Agent Skills standard: .cursor/skills/<name>/SKILL.md
936
+ const cursorDir = fs.join(projectDir, '.cursor', 'skills');
937
+ await fs.mkdir(cursorDir, { recursive: true });
938
+ for (const skill of skills) {
939
+ const skillDir = fs.join(cursorDir, skill.metadata.name);
940
+ await fs.mkdir(skillDir, { recursive: true });
941
+ // Create SKILL.md in Agent Skills format
942
+ const content = `---
943
+ name: ${skill.metadata.name}
944
+ description: ${skill.metadata.description}
945
+ ---
946
+
947
+ ${skill.body}
948
+ `;
949
+ await fs.writeFile(fs.join(skillDir, 'SKILL.md'), content);
950
+ }
951
+ console.log(chalk.green(` āœ“ Cursor: .cursor/skills/<skill>/SKILL.md`));
952
+ }
953
+ async function exportToClaude(skills, projectDir, fs) {
954
+ // Claude Code now uses Agent Skills standard: .claude/skills/<name>/SKILL.md
955
+ const claudeDir = fs.join(projectDir, '.claude', 'skills');
956
+ await fs.mkdir(claudeDir, { recursive: true });
957
+ for (const skill of skills) {
958
+ const skillDir = fs.join(claudeDir, skill.metadata.name);
959
+ await fs.mkdir(skillDir, { recursive: true });
960
+ // Create SKILL.md in Agent Skills format
961
+ const content = `---
962
+ name: ${skill.metadata.name}
963
+ description: ${skill.metadata.description}
964
+ ---
965
+
966
+ ${skill.body}
967
+ `;
968
+ await fs.writeFile(fs.join(skillDir, 'SKILL.md'), content);
969
+ }
970
+ console.log(chalk.green(` āœ“ Claude Code: .claude/skills/<skill>/SKILL.md`));
971
+ }
972
+ async function exportToCodex(skills, projectDir, fs) {
973
+ // OpenAI Codex uses Agent Skills standard: .codex/skills/<name>/SKILL.md
974
+ const codexDir = fs.join(projectDir, '.codex', 'skills');
975
+ await fs.mkdir(codexDir, { recursive: true });
976
+ for (const skill of skills) {
977
+ const skillDir = fs.join(codexDir, skill.metadata.name);
978
+ await fs.mkdir(skillDir, { recursive: true });
979
+ // Create SKILL.md in Agent Skills format
980
+ const content = `---
981
+ name: ${skill.metadata.name}
982
+ description: ${skill.metadata.description}
983
+ ---
984
+
985
+ ${skill.body}
986
+ `;
987
+ await fs.writeFile(fs.join(skillDir, 'SKILL.md'), content);
988
+ }
989
+ console.log(chalk.green(` āœ“ OpenAI Codex: .codex/skills/<skill>/SKILL.md`));
990
+ }
991
+ async function exportToAntigravity(skills, projectDir, fs) {
992
+ const workflowsDir = fs.join(projectDir, '.agent', 'workflows');
993
+ await fs.mkdir(workflowsDir, { recursive: true });
994
+ for (const skill of skills) {
995
+ const content = `---
996
+ description: ${skill.metadata.description.slice(0, 100)}
997
+ ---
998
+
999
+ ${skill.body}
1000
+ `;
1001
+ await fs.writeFile(fs.join(workflowsDir, `${skill.metadata.name}.md`), content);
1002
+ }
1003
+ console.log(chalk.green(` āœ“ Antigravity: .agent/workflows/<skill>.md`));
1004
+ }
1005
+ // ============================================
1006
+ // INTERACTIVE COMMANDS
1007
+ // ============================================
1008
+ // Interactive install wizard - select skills with arrow keys
1009
+ program
1010
+ .command('install-wizard')
1011
+ .alias('iw')
1012
+ .description('Interactive skill installation wizard (legacy)')
1013
+ .action(async () => {
1014
+ try {
1015
+ const spinner = ora('Fetching skills from marketplaces...').start();
1016
+ const skills = await listMarketplaceSkills();
1017
+ spinner.stop();
1018
+ if (skills.length === 0) {
1019
+ console.log(chalk.yellow('No skills found in marketplaces.'));
1020
+ return;
1021
+ }
1022
+ const choices = skills.map(skill => ({
1023
+ name: `${skill.name} - ${skill.description?.slice(0, 50) || 'No description'}...`,
1024
+ value: skill.name,
1025
+ short: skill.name
1026
+ }));
1027
+ const { selectedSkills } = await inquirer.prompt([
1028
+ {
1029
+ type: 'checkbox',
1030
+ name: 'selectedSkills',
1031
+ message: 'Select skills to install (Space to select, Enter to confirm):',
1032
+ choices,
1033
+ pageSize: 15
1034
+ }
1035
+ ]);
1036
+ if (selectedSkills.length === 0) {
1037
+ console.log(chalk.yellow('No skills selected.'));
1038
+ return;
1039
+ }
1040
+ for (const skillName of selectedSkills) {
1041
+ const installSpinner = ora(`Installing ${skillName}...`).start();
1042
+ try {
1043
+ const result = await installSkill(skillName);
1044
+ installSpinner.succeed(`Installed: ${skillName}`);
1045
+ }
1046
+ catch (err) {
1047
+ installSpinner.fail(`Failed to install ${skillName}: ${err}`);
1048
+ }
1049
+ }
1050
+ console.log(chalk.bold.green('\nāœ“ Installation complete!'));
1051
+ console.log(chalk.gray('Run "skills export" to export to your AI agent.'));
1052
+ }
1053
+ catch (error) {
1054
+ console.error(chalk.red('Error:'), error);
1055
+ process.exit(1);
1056
+ }
1057
+ });
1058
+ // Interactive export - select target agents
1059
+ program
1060
+ .command('export-interactive')
1061
+ .alias('ei')
1062
+ .description('Interactive export with agent selection menu')
1063
+ .action(async () => {
1064
+ try {
1065
+ const skills = await discoverSkills();
1066
+ if (skills.length === 0) {
1067
+ console.log(chalk.yellow('No skills found to export.'));
1068
+ return;
1069
+ }
1070
+ const { agents } = await inquirer.prompt([
1071
+ {
1072
+ type: 'checkbox',
1073
+ name: 'agents',
1074
+ message: 'Select target AI agents:',
1075
+ choices: [
1076
+ { name: 'GitHub Copilot (.github/skills/)', value: 'copilot', checked: true },
1077
+ { name: 'Cursor (.cursor/skills/)', value: 'cursor', checked: true },
1078
+ { name: 'Claude Code (.claude/skills/)', value: 'claude', checked: true },
1079
+ { name: 'OpenAI Codex (.codex/skills/)', value: 'codex', checked: true },
1080
+ { name: 'Antigravity (.agent/workflows/)', value: 'antigravity', checked: false }
1081
+ ]
1082
+ }
1083
+ ]);
1084
+ if (agents.length === 0) {
1085
+ console.log(chalk.yellow('No agents selected.'));
1086
+ return;
1087
+ }
1088
+ const { mkdir, writeFile, appendFile } = await import('fs/promises');
1089
+ const { join } = await import('path');
1090
+ const { existsSync } = await import('fs');
1091
+ console.log(chalk.bold(`\nExporting ${skills.length} skill(s) to: ${agents.join(', ')}\n`));
1092
+ for (const target of agents) {
1093
+ const spinner = ora(`Exporting to ${target}...`).start();
1094
+ await exportToAgent(target, skills, '.', { mkdir, writeFile, appendFile, join, existsSync });
1095
+ spinner.succeed();
1096
+ }
1097
+ console.log(chalk.bold.green('\nāœ“ Export complete!'));
1098
+ }
1099
+ catch (error) {
1100
+ console.error(chalk.red('Error:'), error);
1101
+ process.exit(1);
1102
+ }
1103
+ });
1104
+ // Quick setup wizard
1105
+ program
1106
+ .command('setup')
1107
+ .description('Interactive setup wizard - install skills and export to your agents')
1108
+ .action(async () => {
1109
+ console.log(chalk.bold.cyan('\nšŸš€ Agent Skills Setup Wizard\n'));
1110
+ // Step 1: Choose what to do
1111
+ const { action } = await inquirer.prompt([
1112
+ {
1113
+ type: 'list',
1114
+ name: 'action',
1115
+ message: 'What would you like to do?',
1116
+ choices: [
1117
+ { name: 'šŸ“¦ Install skills from marketplace', value: 'install' },
1118
+ { name: 'šŸ“¤ Export installed skills to AI agents', value: 'export' },
1119
+ { name: 'šŸ”„ Both - Install and export', value: 'both' }
1120
+ ]
1121
+ }
1122
+ ]);
1123
+ if (action === 'install' || action === 'both') {
1124
+ const spinner = ora('Fetching skills from marketplaces...').start();
1125
+ const skills = await listMarketplaceSkills();
1126
+ spinner.stop();
1127
+ if (skills.length > 0) {
1128
+ const choices = skills.slice(0, 20).map(skill => ({
1129
+ name: `${skill.name} - ${skill.description?.slice(0, 40) || ''}...`,
1130
+ value: skill.name
1131
+ }));
1132
+ const { selectedSkills } = await inquirer.prompt([
1133
+ {
1134
+ type: 'checkbox',
1135
+ name: 'selectedSkills',
1136
+ message: 'Select skills to install:',
1137
+ choices,
1138
+ pageSize: 10
1139
+ }
1140
+ ]);
1141
+ for (const skillName of selectedSkills) {
1142
+ const installSpinner = ora(`Installing ${skillName}...`).start();
1143
+ try {
1144
+ await installSkill(skillName);
1145
+ installSpinner.succeed(`Installed: ${skillName}`);
1146
+ }
1147
+ catch (err) {
1148
+ installSpinner.fail(`Failed: ${skillName}`);
1149
+ }
1150
+ }
1151
+ }
1152
+ }
1153
+ if (action === 'export' || action === 'both') {
1154
+ const { agents } = await inquirer.prompt([
1155
+ {
1156
+ type: 'checkbox',
1157
+ name: 'agents',
1158
+ message: 'Which AI agents do you use?',
1159
+ choices: [
1160
+ { name: 'Cursor', value: 'cursor', checked: true },
1161
+ { name: 'Claude Code', value: 'claude', checked: true },
1162
+ { name: 'GitHub Copilot', value: 'copilot', checked: true },
1163
+ { name: 'OpenAI Codex', value: 'codex', checked: false }
1164
+ ]
1165
+ }
1166
+ ]);
1167
+ const skills = await discoverSkills();
1168
+ const { mkdir, writeFile, appendFile } = await import('fs/promises');
1169
+ const { join } = await import('path');
1170
+ const { existsSync } = await import('fs');
1171
+ for (const target of agents) {
1172
+ const spinner = ora(`Exporting to ${target}...`).start();
1173
+ await exportToAgent(target, skills, '.', { mkdir, writeFile, appendFile, join, existsSync });
1174
+ spinner.succeed();
1175
+ }
1176
+ }
1177
+ console.log(chalk.bold.green('\n✨ Setup complete!'));
1178
+ console.log(chalk.gray('Your skills are now ready to use in your AI agents.\n'));
1179
+ });
1180
+ program.parse();
1181
+ //# sourceMappingURL=index.js.map