import { Command } from 'commander'; import chalk from 'chalk'; import { parseGitHubUrl } from '../utils/git'; import { installSkill } from '../utils/install'; import { CLIType } from '../types'; export const addCommand = new Command('add') .description('Add a skill from GitHub') .argument('', 'GitHub URL or owner/repo/path') .option('-c, --cli ', 'Target CLI (antigravity, claude, codex, cursor, gemini, kiro, opencode)') .option('-y, --yes', 'Skip confirmation') .action(async (skillPathArg: string, options) => { try { // Parse GitHub URL let repoUrl: string; let gitPath: string; if (skillPathArg.includes('github.com')) { const parsed = parseGitHubUrl(skillPathArg); repoUrl = `https://github.com/${parsed.owner}/${parsed.repo}.git`; gitPath = parsed.path; } else { // Assume it's owner/repo[/path] or owner/repo/tree|blob/branch/path const parts = skillPathArg.split('/').filter(Boolean); if (parts.length < 2) { console.error(chalk.red('Invalid path format. Use owner/repo/path or full GitHub URL')); process.exit(1); } repoUrl = `https://github.com/${parts[0]}/${parts[1]}.git`; if (parts.length <= 2) { gitPath = ''; } else if (parts[2] === 'tree' || parts[2] === 'blob') { if (parts.length < 5) { console.error(chalk.red('Invalid path format. Use owner/repo/tree/branch/path or full GitHub URL')); process.exit(1); } gitPath = parts.slice(4).join('/'); } else { gitPath = parts.slice(2).join('/'); } } // Parse CLI options const cliTargets: CLIType[] = options.cli ? [options.cli as CLIType] : []; // Call install skill await installSkill({ repoUrl, gitPath, cliTargets, skipConfirmation: options.yes, }); } catch (error: any) { console.error(chalk.red(`\nError: ${error.message}`)); process.exit(1); } });