UNPKG

accs-cli

Version:

ACCS CLI — Full-featured developer tool for scaffolding, running, building, and managing multi-language projects

123 lines (108 loc) 3.63 kB
/** * Scan command - Scan for errors and suggest fixes using Gemini */ import { logger } from '../utils/logger.js'; import { FileUtils } from '../utils/file-utils.js'; import { execa } from 'execa'; export function scanCommand(program) { program .command('scan') .option('--fix', 'Automatically apply the suggested fix') .description('Scan for errors and get AI-powered suggestions') .action(async (options) => { try { await scanForErrors(options); } catch (error) { logger.error('Scan failed:', error.message); process.exit(1); } }); } async function scanForErrors(options) { logger.info('Scanning for errors with the linter...'); let lintResults; const { stdout } = await execa('npm', ['run', 'lint', '--', '--format=json'], { reject: false }); if (!stdout) { logger.error('Failed to run the lint command.'); logger.error('Please make sure you have a `lint` script in your package.json.'); return; } try { const startIndex = stdout.indexOf('['); const jsonOutput = stdout.substring(startIndex); lintResults = JSON.parse(jsonOutput); } catch (e) { logger.error('Failed to parse lint output.'); logger.error('Please ensure your lint script can output JSON format.'); console.error(e); return; } const errors = lintResults.flatMap(result => result.messages.map(msg => ({ ...msg, filePath: result.filePath })) ).filter(msg => msg.severity === 2); if (errors.length === 0) { logger.success('No linting errors found!'); return; } const error = errors[0]; logger.info(`Found an error in ${error.filePath} on line ${error.line}`); const fileContent = await FileUtils.readFile(error.filePath); const fileLines = fileContent.split('\n'); const startLine = Math.max(0, error.line - 10); const endLine = Math.min(fileLines.length, error.line + 10); const codeSnippet = fileLines.slice(startLine, endLine).join('\n'); const prompt = options.fix ? `I have a linting error in a file. Your task is to provide a fix for the error. File Path: ${error.filePath} Code Snippet: --- ${codeSnippet} --- Linting Error: --- ${error.message} (rule: ${error.ruleId}) --- Please provide the corrected code for the given snippet.` : `I have a linting error in a file. Your task is to provide a fix for the error. File Path: ${error.filePath} Code Snippet: --- ${codeSnippet} --- Linting Error: --- ${error.message} (rule: ${error.ruleId}) --- Please explain the fix and provide the corrected code for the snippet.`; logger.info('Asking Gemini for a fix...'); try { const { execa } = await import('execa'); const { stdout } = await execa('gemini', ['-m', 'gemini-2.5-flash', '-p', prompt]); if (options.fix) { logger.success('Gemini suggests the following fix:'); console.log(stdout); const inquirer = await import('inquirer'); const { applyFix } = await inquirer.prompt([ { type: 'confirm', name: 'applyFix', message: 'Do you want to apply this fix?', default: false, }, ]); if (applyFix) { await FileUtils.writeFile(error.filePath, stdout); logger.success('The fix has been applied.'); } } else { logger.success('Gemini suggests the following fix:'); console.log(stdout); } } catch (error) { if (error.code === 'ENOENT') { logger.error('Gemini CLI not found. Please make sure it is installed and in your PATH.'); } else { logger.error('Failed to get a fix from Gemini:', error.message); } } }