claudewatch
Version:
Automated validation and self-healing system for Claude Code projects
179 lines (162 loc) • 5.45 kB
JavaScript
#!/usr/bin/env node
const { program } = require('commander');
const chalk = require('chalk');
const ora = require('ora');
const prompts = require('prompts');
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const {
initProject,
runValidation,
runSelfHealing,
showStatus,
generateReport,
cleanup
} = require('../lib');
program
.name('claudewatch')
.description('Automated validation and self-healing for Claude Code projects')
.version(require('../package.json').version);
program
.command('init')
.description('Initialize ClaudeWatch in your project')
.option('-y, --yes', 'Skip prompts and use defaults')
.action(async (options) => {
console.log(chalk.blue('\nInitializing ClaudeWatch...\n'));
if (!options.yes) {
const response = await prompts([
{
type: 'text',
name: 'baseUrl',
message: 'What is your development server URL?',
initial: 'http://localhost:3000'
},
{
type: 'confirm',
name: 'selfHealing',
message: 'Enable self-healing mode?',
initial: true
},
{
type: 'multiselect',
name: 'validationTypes',
message: 'Which validation types to enable?',
choices: [
{ title: 'Visual Elements', value: 'visual', selected: true },
{ title: 'Accessibility', value: 'accessibility', selected: true },
{ title: 'Performance', value: 'performance', selected: true },
{ title: 'Forms', value: 'forms', selected: true },
{ title: 'APIs', value: 'api', selected: true },
{ title: 'Console Errors', value: 'console', selected: true },
{ title: 'Broken Links', value: 'links', selected: true }
]
}
]);
await initProject(response);
} else {
await initProject({});
}
});
program
.command('validate')
.alias('test')
.description('Run validation tests')
.option('-c, --config <path>', 'Path to custom config file')
.action(async (options) => {
const spinner = ora('Running validation tests...').start();
try {
const result = await runValidation(options.config);
if (result.success) {
spinner.succeed(chalk.green('All validations passed!'));
} else {
spinner.fail(chalk.red('Validation failed'));
process.exit(1);
}
} catch (error) {
spinner.fail(chalk.red(`Error: ${error.message}`));
process.exit(1);
}
});
program
.command('self-heal')
.alias('heal')
.description('Run self-healing validation (auto-fixes issues)')
.option('-m, --max-attempts <number>', 'Maximum healing attempts', '5')
.action(async (options) => {
console.log(chalk.blue('\nStarting self-healing validation...\n'));
try {
const result = await runSelfHealing({
maxAttempts: parseInt(options.maxAttempts)
});
if (result.success) {
console.log(chalk.green('\nAll issues fixed!'));
} else {
console.log(chalk.yellow('\nSome issues remain'));
process.exit(1);
}
} catch (error) {
console.error(chalk.red(`Error: ${error.message}`));
process.exit(1);
}
});
program
.command('status')
.description('Show ClaudeWatch status and configuration')
.action(async () => {
await showStatus();
});
program
.command('report')
.description('Show validation reports and history')
.option('-n, --number <count>', 'Number of recent reports to show', '10')
.action(async (options) => {
await generateReport(parseInt(options.number));
});
program
.command('cleanup')
.description('Clean up old validation logs and screenshots')
.option('-d, --days <number>', 'Keep files from last N days', '7')
.option('--dry-run', 'Show what would be deleted without deleting')
.action(async (options) => {
await cleanup({
keepDays: parseInt(options.days),
dryRun: options.dryRun
});
});
program
.command('config')
.description('Open ClaudeWatch configuration file')
.action(() => {
const configPath = path.join(process.cwd(), '.claudewatch', 'config.js');
if (fs.existsSync(configPath)) {
console.log(chalk.blue(`Opening config at: ${configPath}`));
try {
execSync(`${process.env.EDITOR || 'code'} ${configPath}`);
} catch (error) {
console.log(chalk.yellow('Could not open in editor. Config location:'));
console.log(configPath);
}
} else {
console.log(chalk.red('Config file not found. Run `claudewatch init` first.'));
}
});
program
.command('claude-setup')
.description('Quick setup optimized for Claude Code')
.action(async () => {
console.log(chalk.blue('\nSetting up ClaudeWatch for Claude Code...\n'));
await initProject({
baseUrl: 'http://localhost:3000',
selfHealing: true,
validationTypes: ['visual', 'accessibility', 'performance', 'forms', 'api', 'console', 'links'],
claudeOptimized: true
});
console.log(chalk.green('\nClaudeWatch is ready for Claude Code!'));
console.log(chalk.gray('\nClaude will now automatically validate your work.'));
console.log(chalk.gray('The self-healing system will fix common issues.\n'));
});
program.parse(process.argv);
if (!process.argv.slice(2).length) {
program.outputHelp();
}