UNPKG

context-forge

Version:

AI orchestration platform with autonomous teams, enhancement planning, migration tools, 25+ slash commands, checkpoints & hooks. Multi-IDE: Claude, Cursor, Windsurf, Cline, Copilot

179 lines • 7.45 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ValidationExecutor = void 0; const child_process_1 = require("child_process"); const util_1 = require("util"); const validationCommands_1 = require("../data/validationCommands"); const validationReport_1 = require("../generators/validationReport"); const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const execAsync = (0, util_1.promisify)(child_process_1.exec); class ValidationExecutor { constructor(projectPath, config) { this.results = []; this.projectPath = projectPath; this.config = config; } async runValidation(levels) { console.log(chalk_1.default.bold.blue('\nšŸ” Running validation commands...\n')); const commands = (0, validationCommands_1.getValidationCommands)(this.config.techStack); const levelsToRun = levels || ['syntax', 'lint', 'tests', 'build']; for (const level of levelsToRun) { if (level === 'syntax' && commands.syntax) { await this.runCommandSet('syntax', commands.syntax); } else if (level === 'lint' && commands.lint) { await this.runCommand('lint', commands.lint); } else if (level === 'tests' && commands.tests) { await this.runCommandSet('tests', commands.tests); } else if (level === 'build' && commands.build) { await this.runCommand('build', commands.build); } else if (level === 'coverage' && commands.coverage) { await this.runCommand('coverage', commands.coverage); } else if (level === 'security' && commands.security) { await this.runCommandSet('security', commands.security); } } const report = this.generateReport(); await this.saveReport(report); // Save markdown report const reportPath = await (0, validationReport_1.saveValidationReport)(report, this.projectPath); console.log(chalk_1.default.gray(`\nšŸ“„ Full report saved to: ${reportPath}`)); this.printSummary(report); return report; } async runCommand(level, command) { const spinner = (0, ora_1.default)(`Running ${level}: ${command}`).start(); const startTime = Date.now(); try { const { stdout } = await execAsync(command, { cwd: this.projectPath, env: { ...process.env, CI: 'true' }, }); const duration = Date.now() - startTime; this.results.push({ level, command, success: true, output: stdout, duration, }); spinner.succeed(chalk_1.default.green(`āœ“ ${level} passed (${duration}ms)`)); if (stdout && process.env.VERBOSE) { console.log(chalk_1.default.gray(stdout)); } } catch (error) { const duration = Date.now() - startTime; const errorMessage = error instanceof Error ? error.message : String(error); const errorOutput = error instanceof Error && 'stdout' in error ? error.stdout : ''; this.results.push({ level, command, success: false, error: errorMessage, output: errorOutput, duration, }); spinner.fail(chalk_1.default.red(`āœ— ${level} failed (${duration}ms)`)); if (errorOutput || (error instanceof Error && 'stderr' in error)) { const errorOutput2 = error instanceof Error && 'stderr' in error ? error.stderr : ''; console.log(chalk_1.default.red(errorOutput || errorOutput2)); } // Only throw for critical errors const levelInfo = validationCommands_1.validationLevels[level]; if (levelInfo?.critical) { throw new Error(`Critical validation failed: ${level}`); } } } async runCommandSet(level, commands) { for (const command of commands) { await this.runCommand(`${level}:${command}`, command); } } generateReport() { const passed = this.results.filter((r) => r.success).length; const failed = this.results.filter((r) => !r.success).length; return { projectName: this.config.projectName, timestamp: new Date().toISOString(), overallSuccess: failed === 0, results: this.results, summary: { total: this.results.length, passed, failed, skipped: 0, }, }; } async saveReport(report) { const reportsDir = path_1.default.join(this.projectPath, '.validation-reports'); await fs_extra_1.default.ensureDir(reportsDir); const filename = `validation-${Date.now()}.json`; const filepath = path_1.default.join(reportsDir, filename); await fs_extra_1.default.writeJson(filepath, report, { spaces: 2 }); // Also save as latest const latestPath = path_1.default.join(reportsDir, 'latest.json'); await fs_extra_1.default.writeJson(latestPath, report, { spaces: 2 }); } printSummary(report) { console.log((0, validationReport_1.generateValidationSummary)(report)); } // Generate a validation gate for PRP async generateValidationGate() { const commands = (0, validationCommands_1.getValidationCommands)(this.config.techStack); let gate = '## Validation Gate\n\n'; gate += 'Run the following commands to validate your implementation:\n\n'; gate += '### Syntax & Type Checking\n'; gate += '```bash\n'; if (commands.syntax) { commands.syntax.forEach((cmd) => { gate += `${cmd}\n`; }); } gate += '```\n\n'; gate += '### Linting\n'; gate += '```bash\n'; gate += `${commands.lint || 'npm run lint'}\n`; gate += '```\n\n'; gate += '### Tests\n'; gate += '```bash\n'; if (commands.tests) { commands.tests.forEach((cmd) => { gate += `${cmd}\n`; }); } gate += '```\n\n'; gate += '### Build\n'; gate += '```bash\n'; gate += `${commands.build}\n`; gate += '```\n\n'; gate += '### Start Application\n'; gate += '```bash\n'; gate += `${commands.start}\n`; gate += '```\n\n'; if (commands.security) { gate += '### Security Checks\n'; gate += '```bash\n'; commands.security.forEach((cmd) => { gate += `${cmd}\n`; }); gate += '```\n\n'; } gate += 'āœ… All commands must pass before considering the implementation complete.\n'; return gate; } } exports.ValidationExecutor = ValidationExecutor; //# sourceMappingURL=validationExecutor.js.map