UNPKG

cursorifier

Version:

Transform GitHub repositories into cursor rules instructions using multiple LLM providers (Anthropic, OpenAI, Ollama, etc.)

140 lines 7.47 kB
import process from 'node:process'; import { Command } from 'commander'; import pc from 'picocolors'; import { rulesGenerate } from './rulesGenerate.js'; import { LLMProviderRegistry } from './providers/provider-registry.js'; export const run = async () => { try { const program = new Command(); const registry = new LLMProviderRegistry(); program .description('Cursorifier - Transform GitHub repositories into cursor rules instructions') .argument('[repo-path]', 'Path to the repository', '.') .allowExcessArguments(true) .option('--provider <provider>', 'LLM provider to use (anthropic, openai, local, bedrock)', 'anthropic') .option('--model <model>', 'Specific model to use (overrides provider default)') .option('--api-key <key>', 'API key for the provider (or set environment variable)') .option('--base-url <url>', 'Base URL for the API (useful for local providers)') .option('--max-tokens <tokens>', 'Maximum tokens for response (default: 8000)', '8000') .option('--temperature <temp>', 'Temperature for generation (0-2, default: 0.7)', '0.7') .option('--aws-profile <profile>', 'AWS profile to use for Bedrock (default: default)') .option('--aws-region <region>', 'AWS region for Bedrock (default: us-east-1)') .option('--description <text>', 'Description of what should be rulefied') .option('--rule-type <type>', 'Type of rule to generate (auto, manual, agent, always)') .option('--output-format <format>', 'Output format for rules (cursor, cline, roo)', 'cursor') .option('--chunk-size <size>', 'Chunk size for the repository to be processed in one go (default: 100000)', '100000') .option('--chunk-delay <ms>', 'Delay between chunks in milliseconds to avoid rate limits (default: 5000)', '5000') .option('--repomix-file <path>', 'Path to existing repomix output file (skips repomix execution)') .option('--list-providers', 'List available providers and their models') .allowUnknownOption(true); program.parse(process.argv); const options = program.opts(); const args = program.args; // Handle list providers option if (options.listProviders) { console.log(pc.bold('\n📋 Available LLM Providers:\n')); const providers = registry.getProviderInfo(); providers.forEach(provider => { console.log(pc.cyan(`${provider.displayName} (${provider.name}):`)); console.log(` Default Model: ${pc.green(provider.defaultModel)}`); console.log(` Requires API Key: ${provider.requiresApiKey ? pc.red('Yes') : pc.green('No')}`); console.log(` Available Models: ${provider.availableModels.slice(0, 5).join(', ')}${provider.availableModels.length > 5 ? '...' : ''}`); console.log(''); }); console.log(pc.yellow('Environment Variables:')); console.log(' ANTHROPIC_API_KEY - For Anthropic Claude'); console.log(' OPENAI_API_KEY - For OpenAI'); console.log(' LOCAL_API_KEY - For local providers (optional)'); console.log(''); return; } // Find the repository path (first argument that doesn't start with --) const repoPathIndex = args.findIndex(arg => !arg.startsWith('--')); let repoPath = repoPathIndex >= 0 ? args[repoPathIndex] : '.'; // If using repomix file, use a default repo path since we won't run repomix if (options.repomixFile) { repoPath = '.'; } if (options.repomixFile) { console.log(pc.bold(`\n🧩 Cursorifier - Generating cursor rules using repomix file: ${options.repomixFile}\n`)); } else { console.log(pc.bold(`\n🧩 Cursorifier - Generating cursor rules for ${repoPath}\n`)); } // Display provider information try { const provider = registry.getProvider(options.provider); console.log(pc.cyan(`Using provider: ${provider.displayName}`)); console.log(pc.cyan(`Model: ${options.model || provider.defaultModel}`)); if (options.baseUrl) { console.log(pc.cyan(`Base URL: ${options.baseUrl}`)); } console.log(''); } catch (error) { console.error(pc.red(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`)); process.exit(1); } if (options.description) { console.log(pc.cyan(`Rulefying with description: "${options.description}"\n`)); } // Create a dictionary for additional options const additionalOptions = {}; // Known options already handled by Commander const knownOptions = ['provider', 'model', 'api-key', 'base-url', 'max-tokens', 'temperature', 'aws-profile', 'aws-region', 'description', 'rule-type', 'output-format', 'chunk-size', 'repomix-file', 'list-providers', 'remote']; const knownOptionFlags = knownOptions.map(opt => `--${opt}`); // Parse additional options from args array for (let i = 0; i < args.length; i++) { const arg = args[i]; // Skip the repository path if (i === repoPathIndex) continue; // Check if it's an option (starts with --) if (arg.startsWith('--') && !knownOptionFlags.includes(arg)) { const optionName = arg.slice(2); // Remove '--' // Check if next argument exists and doesn't start with -- and isn't the repo path if (i + 1 < args.length && !args[i + 1].startsWith('--') && i + 1 !== repoPathIndex) { additionalOptions[optionName] = args[i + 1]; i++; // Skip the next argument since we've used it as a value } else { // Option without value (boolean flag) additionalOptions[optionName] = 'true'; } } } // Get API key from CLI option or environment variable const apiKeyEnvVar = registry.getApiKeyEnvVar(options.provider); const apiKey = options.apiKey || process.env[apiKeyEnvVar]; // Set AWS profile if provided if (options.awsProfile) { process.env.AWS_PROFILE = options.awsProfile; } await rulesGenerate(repoPath, { description: options.description, ruleType: options.ruleType, outputFormat: options.outputFormat, provider: options.provider, model: options.model, apiKey: apiKey, baseURL: options.baseUrl, maxTokens: parseInt(options.maxTokens), temperature: parseFloat(options.temperature), region: options.awsRegion, chunkSize: parseInt(options.chunkSize), chunkDelay: parseInt(options.chunkDelay), repomixFile: options.repomixFile, additionalOptions }); } catch (error) { if (error instanceof Error) { console.error('Error:', error.message); } else { console.error('Unknown error occurred'); } process.exit(1); } }; //# sourceMappingURL=index.js.map