UNPKG

ctrlshiftleft

Version:

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

156 lines (135 loc) 4.06 kB
#!/usr/bin/env node /** * ctrl.shift.left CLI * Unified command-line interface for security analysis, test generation, and QA checklists */ const fs = require('fs'); const path = require('path'); const { spawn } = require('child_process'); // Configuration const TOOLS_DIR = __dirname; // Command definitions const COMMANDS = { 'analyze': { script: path.join(TOOLS_DIR, 'analyze-security.js'), description: 'Analyze a file for security vulnerabilities', usage: 'analyze <file-path>', examples: [ 'analyze src/components/LoginForm.js', 'analyze src/utils/validation.ts' ] }, 'gen': { script: path.join(TOOLS_DIR, 'generate-tests.js'), description: 'Generate Playwright tests for a component', usage: 'gen <file-path> [output-dir]', examples: [ 'gen src/components/PaymentForm.tsx', 'gen src/components/Form.js tests/e2e' ] }, 'checklist': { script: path.join(TOOLS_DIR, 'generate-checklist.js'), description: 'Create a QA and security checklist for a component', usage: 'checklist <file-path> [output-file]', examples: [ 'checklist src/components/PaymentForm.tsx', 'checklist src/App.js qa/app-checklist.json' ] }, 'run': { description: 'Run generated tests (shortcut to npx playwright test)', usage: 'run [test-file-or-dir]', examples: [ 'run', 'run generated-tests/LoginForm.spec.ts' ] }, 'watch': { description: 'Watch files and run security analysis on changes', usage: 'watch <directory> [--exclude=pattern]', examples: [ 'watch src/components', 'watch src --exclude=node_modules' ] } }; /** * Display help information */ function showHelp(command) { console.log('\x1b[36m%s\x1b[0m', '🛡️ ctrl.shift.left - Shift Security & QA Left'); console.log('\x1b[36m%s\x1b[0m', '=========================================='); if (command && COMMANDS[command]) { const cmd = COMMANDS[command]; console.log(`\n\x1b[33m${command}\x1b[0m: ${cmd.description}`); console.log(`\nUsage: \x1b[32mctrlshiftleft ${cmd.usage}\x1b[0m`); console.log('\nExamples:'); cmd.examples.forEach(example => { console.log(` ctrlshiftleft ${example}`); }); } else { console.log('\nAvailable commands:'); Object.keys(COMMANDS).forEach(cmd => { console.log(` \x1b[33m${cmd.padEnd(10)}\x1b[0m ${COMMANDS[cmd].description}`); }); console.log('\nFor help with a specific command:'); console.log(' ctrlshiftleft help <command>'); } } /** * Execute a command with arguments */ function executeCommand(command, args) { if (command === 'help') { showHelp(args[0]); return; } if (command === 'run') { console.log('Running tests...'); const testArgs = ['playwright', 'test'].concat(args); const proc = spawn('npx', testArgs, { stdio: 'inherit' }); proc.on('close', (code) => { if (code !== 0) { console.error(`Tests exited with code ${code}`); } }); return; } if (command === 'watch') { console.log('Watch mode is not implemented in this demo version'); console.log('Use the analyze command to analyze files on demand'); return; } const cmdConfig = COMMANDS[command]; if (!cmdConfig || !cmdConfig.script) { console.error(`Unknown command: ${command}`); showHelp(); return; } // Execute the appropriate script const scriptPath = cmdConfig.script; if (!fs.existsSync(scriptPath)) { console.error(`Error: Script not found: ${scriptPath}`); return; } const proc = spawn('node', [scriptPath].concat(args), { stdio: 'inherit' }); proc.on('close', (code) => { if (code !== 0) { console.error(`Command exited with code ${code}`); } }); } /** * Main function */ function main() { const [,, command, ...args] = process.argv; if (!command || command === '--help' || command === '-h') { showHelp(); return; } executeCommand(command, args); } // Run the CLI main();