mirror of
https://github.com/harivansh-afk/evaluclaude-harness.git
synced 2026-04-16 07:04:27 +00:00
ui polish
This commit is contained in:
parent
ff5300f4e0
commit
69c08c9d6b
12 changed files with 1430 additions and 308 deletions
|
|
@ -2,6 +2,7 @@ import { Command } from 'commander';
|
|||
import { readFileSync, existsSync } from 'fs';
|
||||
import { renderSpec, detectFramework, type Framework } from '../../renderers/index.js';
|
||||
import type { EvalSpec } from '../../analyzer/types.js';
|
||||
import { style, icons, Spinner, formatError, nextSteps, keyValue } from '../theme.js';
|
||||
|
||||
export const renderCommand = new Command('render')
|
||||
.description('Render EvalSpec JSON into runnable test files')
|
||||
|
|
@ -11,19 +12,41 @@ export const renderCommand = new Command('render')
|
|||
.option('--fixtures', 'Generate fixture stubs', false)
|
||||
.option('--mocks', 'Generate mock stubs', false)
|
||||
.option('--dry-run', 'Preview without writing files', false)
|
||||
.addHelpText('after', `
|
||||
${style.bold('Examples:')}
|
||||
${style.command('evaluclaude render spec.json')} ${style.dim('Render with auto-detected framework')}
|
||||
${style.command('evaluclaude render spec.json -f vitest')} ${style.dim('Use Vitest framework')}
|
||||
${style.command('evaluclaude render spec.json --dry-run')} ${style.dim('Preview output without writing')}
|
||||
${style.command('evaluclaude render spec.json --fixtures')} ${style.dim('Include fixture stubs')}
|
||||
`)
|
||||
.action(async (specPath: string, options) => {
|
||||
try {
|
||||
if (!existsSync(specPath)) {
|
||||
console.error(`Error: Spec file not found: ${specPath}`);
|
||||
console.error(formatError(`Spec file not found: ${style.path(specPath)}`, [
|
||||
'Check that the spec file exists',
|
||||
'Run `evaluclaude analyze` to generate a spec file first',
|
||||
'Verify the path is correct',
|
||||
]));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const specContent = readFileSync(specPath, 'utf-8');
|
||||
const spec: EvalSpec = JSON.parse(specContent);
|
||||
let spec: EvalSpec;
|
||||
|
||||
try {
|
||||
spec = JSON.parse(specContent);
|
||||
} catch {
|
||||
console.error(formatError('Invalid JSON in spec file', [
|
||||
'Ensure the file contains valid JSON',
|
||||
'Check for syntax errors in the spec file',
|
||||
]));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const framework = (options.framework as Framework) || detectFramework(spec);
|
||||
|
||||
console.log(`Rendering ${spec.scenarios.length} scenarios with ${framework}...`);
|
||||
const spinner = new Spinner(`Rendering ${style.number(String(spec.scenarios.length))} scenarios with ${style.highlight(framework)}...`);
|
||||
spinner.start();
|
||||
|
||||
const result = await renderSpec(spec, {
|
||||
outputDir: options.output,
|
||||
|
|
@ -33,29 +56,44 @@ export const renderCommand = new Command('render')
|
|||
dryRun: options.dryRun,
|
||||
});
|
||||
|
||||
spinner.succeed(`Rendered ${style.number(String(spec.scenarios.length))} scenarios with ${style.highlight(framework)}`);
|
||||
|
||||
if (options.dryRun) {
|
||||
console.log('\n--- DRY RUN ---\n');
|
||||
console.log(`\n${style.warning('DRY RUN')} ${style.dim('─ Preview only, no files written')}\n`);
|
||||
for (const file of result.files) {
|
||||
console.log(`📄 ${file.path}`);
|
||||
console.log('---');
|
||||
console.log(file.content);
|
||||
console.log('---\n');
|
||||
console.log(`${icons.file} ${style.path(file.path)}`);
|
||||
console.log(style.dim('─'.repeat(50)));
|
||||
console.log(style.muted(file.content));
|
||||
console.log(style.dim('─'.repeat(50)) + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n✅ Rendered ${result.stats.scenarioCount} scenarios`);
|
||||
console.log(` 📁 ${result.stats.fileCount} test files`);
|
||||
console.log(` 🔍 ${result.stats.assertionCount} assertions`);
|
||||
console.log(`\n${style.success(icons.check)} ${style.bold('Render complete')}`);
|
||||
console.log(keyValue(` ${icons.spec} Scenarios`, style.number(String(result.stats.scenarioCount)), 0));
|
||||
console.log(keyValue(` ${icons.file} Test files`, style.number(String(result.stats.fileCount)), 0));
|
||||
console.log(keyValue(` ${icons.magnify} Assertions`, style.number(String(result.stats.assertionCount)), 0));
|
||||
|
||||
if (result.stats.skippedCount > 0) {
|
||||
console.log(` ⏭️ ${result.stats.skippedCount} scenarios skipped (LLM rubric assertions)`);
|
||||
console.log(keyValue(` ${icons.skipped} Skipped`, `${style.number(String(result.stats.skippedCount))} ${style.dim('(LLM rubric assertions)')}`, 0));
|
||||
}
|
||||
|
||||
if (!options.dryRun) {
|
||||
console.log(`\n📂 Output: ${options.output}`);
|
||||
console.log(`\n${icons.folder} ${style.label('Output:')} ${style.path(options.output)}`);
|
||||
|
||||
console.log(nextSteps([
|
||||
{ command: `evaluclaude run ${options.output}`, description: 'Run the generated tests' },
|
||||
{ command: `evaluclaude render ${specPath} --dry-run`, description: 'Preview changes before writing' },
|
||||
]));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error rendering spec:', error instanceof Error ? error.message : error);
|
||||
console.error(formatError(
|
||||
error instanceof Error ? error.message : String(error),
|
||||
[
|
||||
'Check that the spec file is valid',
|
||||
'Ensure the output directory is writable',
|
||||
'Try running with --dry-run to debug',
|
||||
]
|
||||
));
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue