UNPKG

ctrlshiftleft

Version:

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

124 lines 5.91 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.searchCommand = searchCommand; const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const path_1 = __importDefault(require("path")); const promises_1 = __importDefault(require("fs/promises")); const glob_1 = require("glob"); const llmService_1 = require("../core/llmService"); /** * Semantic search command for finding potential security issues */ function searchCommand(program) { program .command('search') .description('Search codebase for potential security issues using semantic search') .argument('<query>', 'Search query (e.g., "sql injection", "xss vulnerability")') .option('-d, --directory <directory>', 'Directory to search', '.') .option('-e, --extensions <extensions>', 'File extensions to include (comma separated)', 'js,jsx,ts,tsx,html,css') .option('-l, --limit <limit>', 'Maximum number of results to return', '10') .option('-o, --output <file>', 'Output results to a JSON file') .action(async (query, options) => { const spinner = (0, ora_1.default)('Searching codebase...').start(); try { // Initialize LLM service for semantic search const llmService = new llmService_1.LLMService(); // Parse extensions const extensions = options.extensions.split(',').map((ext) => ext.trim()); const extensionPattern = extensions.length > 0 ? `**/*.{${extensions.join(',')}}` : '**/*.{js,jsx,ts,tsx,html,css}'; // Resolve search directory const searchDir = path_1.default.resolve(process.cwd(), options.directory); // Find all matching files spinner.text = 'Finding files to search...'; const files = await (0, glob_1.glob)(extensionPattern, { cwd: searchDir, ignore: [ '**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**' ], absolute: true }); if (files.length === 0) { spinner.fail('No files found to search.'); return; } spinner.text = `Searching ${files.length} files for "${query}"...`; // Read all files content const searchResults = []; for (const file of files) { try { const content = await promises_1.default.readFile(file, 'utf8'); const relativePath = path_1.default.relative(process.cwd(), file); // Perform semantic search on content const matches = await llmService.performSemanticSearch(content, query); if (matches.length > 0) { // Add each match with file context for (const match of matches) { searchResults.push({ file: relativePath, ...match }); } } } catch (error) { // Skip files that can't be read continue; } } // Sort results by relevance score searchResults.sort((a, b) => b.score - a.score); // Limit results const limit = parseInt(options.limit, 10); const limitedResults = searchResults.slice(0, limit); if (limitedResults.length === 0) { spinner.succeed('Search completed. No matches found.'); return; } // Format results for display spinner.succeed(`Found ${limitedResults.length} matches.`); console.log('\nSearch Results:'); for (let i = 0; i < limitedResults.length; i++) { const result = limitedResults[i]; console.log(`\n${chalk_1.default.cyan(`${i + 1}. ${result.file}`)}`); console.log(` ${chalk_1.default.yellow('Relevance:')} ${Math.round(result.score * 100)}%`); console.log(` ${chalk_1.default.yellow('Line:')} ${result.line || 'N/A'}`); // Display snippet with highlighting if available if (result.snippet) { console.log(` ${chalk_1.default.yellow('Snippet:')}`); console.log(` ${result.snippet.trim().split('\n').join('\n ')}`); } // Display security context if available if (result.securityContext) { console.log(` ${chalk_1.default.yellow('Security Context:')}`); console.log(` ${result.securityContext}`); } } // Save results to file if requested if (options.output) { const outputPath = path_1.default.resolve(process.cwd(), options.output); await promises_1.default.writeFile(outputPath, JSON.stringify({ query, timestamp: new Date().toISOString(), totalFiles: files.length, matches: limitedResults }, null, 2), 'utf8'); console.log(`\n${chalk_1.default.green('✓')} Results saved to ${outputPath}`); } } catch (error) { spinner.fail(`Search failed: ${error.message}`); console.error(chalk_1.default.red(error.stack)); process.exit(1); } }); } //# sourceMappingURL=search.js.map