UNPKG

ctrlshiftleft

Version:

AI-powered toolkit for embedding QA and security testing into development workflows

141 lines (121 loc) 6.25 kB
/** * AI-Enhanced Watch Command * * This command provides an intelligent file watching capability that automatically * generates tests, performs security analysis, and creates QA checklists as you code. * It's designed to work seamlessly with code generation tools like Cursor AI. */ import { Command } from 'commander'; import chalk from 'chalk'; import ora from 'ora'; import path from 'path'; // Use a compatible way to import figures const figures = { tick: '✓', cross: '✖', warning: '⚠', info: 'ℹ', pointer: '❯', line: '│' }; import { EnhancedWatcher } from '../core/enhancedWatcher'; export function watchAICommand(program: Command): void { program .command('watch-ai') .description('Watch files and automatically generate tests, security reports, and checklists as you code') .argument('[directory]', 'Directory to watch', '.') .option('-t, --tests', 'Generate tests on file changes', true) .option('-s, --security', 'Perform security analysis on file changes', true) .option('-c, --checklists', 'Generate QA checklists on file changes', true) .option('-a, --ai', 'Use AI-enhanced security analysis', false) .option('--test-output <dir>', 'Output directory for tests', './tests') .option('--security-output <dir>', 'Output directory for security reports', './security-reports') .option('--checklist-output <dir>', 'Output directory for checklists', './checklists') .option('--include <patterns...>', 'Glob patterns to include') .option('--exclude <patterns...>', 'Glob patterns to exclude') .option('--concurrent <n>', 'Maximum concurrent tasks', '3') .option('--silent', 'Run in silent mode (no progress reporting)', false) .option('--test-format <format>', 'Test format (playwright or selenium)', 'playwright') .action(async (directory, options) => { // Normalize directory path const dirPath = path.resolve(process.cwd(), directory); // Display banner console.log(chalk.cyan.bold('\n┌──────────────────────────────────────────────┐')); console.log(chalk.cyan.bold('│ ctrl.shift.left AI-Enhanced Watcher │')); console.log(chalk.cyan.bold('└──────────────────────────────────────────────┘')); console.log(chalk.dim(`Version 1.0.0 | Mode: ${options.ai ? 'AI-Enhanced' : 'Standard'}\n`)); // Check for OpenAI API key if AI mode is enabled if (options.ai && !process.env.OPENAI_API_KEY) { console.log(chalk.yellow(`${figures.warning} AI-enhanced security analysis requested, but no OpenAI API key found.`)); console.log(chalk.yellow(`${figures.line} Set the OPENAI_API_KEY environment variable to enable AI features.`)); console.log(chalk.yellow(`${figures.line} Falling back to pattern-based analysis.\n`)); } // Create watcher options const watcherOptions = { include: options.include, exclude: options.exclude, generateTests: options.tests, analyzeSecurity: options.security, useAIAnalysis: options.ai, generateChecklists: options.checklists, testOutputDir: options.testOutput, securityOutputDir: options.securityOutput, checklistOutputDir: options.checklistOutput, maxConcurrentTasks: parseInt(options.concurrent, 10), reportProgress: !options.silent, testFormat: options.testFormat as 'playwright' | 'selenium', openAIApiKey: process.env.OPENAI_API_KEY }; // Create and start the watcher const watcher = new EnhancedWatcher(watcherOptions); // Setup event handlers for real-time feedback watcher.on('ready', () => { console.log(chalk.green(`${figures.tick} Watcher ready and monitoring ${chalk.cyan(dirPath)}`)); console.log(chalk.green(`${figures.line} AI Integration: ${options.ai ? (process.env.OPENAI_API_KEY ? 'Active' : 'Disabled (no API key)') : 'Disabled'}`)); console.log(chalk.green(`${figures.line} Press Ctrl+C to stop the watcher\n`)); }); watcher.on('file:change', (event) => { if (!options.silent) { console.log(chalk.blue(`${figures.pointer} File ${event.type}: ${path.basename(event.path)}`)); } }); watcher.on('analysis:complete', (result) => { if (!options.silent && result.success) { const typeColor = result.type === 'test' ? chalk.magenta : result.type === 'security' ? chalk.yellow : chalk.blue; console.log(`${chalk.green(figures.tick)} ${typeColor(result.type.toUpperCase())} analysis complete for ${path.basename(result.filePath)} (${result.duration}ms)`); if (result.outputPath) { console.log(`${chalk.dim(figures.line)} Output: ${result.outputPath}`); } } }); watcher.on('error', (error) => { console.error(chalk.red(`${figures.cross} Error: ${error.message}`)); }); // Start watching const stopWatching = watcher.watch(dirPath); // Handle process exit const handleExit = async () => { console.log(chalk.yellow('\n\nStopping watcher...')); const spinner = ora('Cleaning up...').start(); await watcher.stop(); spinner.succeed('Watcher stopped'); console.log(chalk.green(`\n${figures.tick} Thank you for using ctrl.shift.left!`)); process.exit(0); }; // Handle interrupts process.on('SIGINT', handleExit); process.on('SIGTERM', handleExit); try { // Keep the process running await new Promise(() => {}); // Never resolves } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error(chalk.red(`${figures.cross} Error: ${errorMessage}`)); await watcher.stop(); process.exit(1); } }); } export default watchAICommand;