claude-hooks/bin/claude-hooks.js
Ryan Malloy 9445e09c48 Add NPM distribution support with hybrid installation approach
Major changes:
- Add package.json with NPM packaging configuration
- Create Node.js CLI interface (bin/claude-hooks.js) with full command set
- Convert bash scripts to Python for better npm integration
- Add npm postinstall/preuninstall hooks for automatic setup
- Update bootstrap prompt to recommend NPM method with git fallback
- Enhance README with NPM-first documentation
- Maintain backward compatibility with existing git installation

Features:
- npm install -g claude-hooks for easy distribution
- claude-hooks init/status/test/backup/uninstall commands
- Automatic Python dependency installation
- Conflict detection and prevention
- Hybrid approach supporting both npm and git workflows

This resolves installation complexity while maintaining developer flexibility.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-19 21:03:13 -06:00

127 lines
3.8 KiB
JavaScript

#!/usr/bin/env node
const { Command } = require('commander');
const chalk = require('chalk');
const { execSync, spawn } = require('child_process');
const path = require('path');
const fs = require('fs');
const os = require('os');
const program = new Command();
const packageRoot = path.dirname(__dirname);
// Helper to run Python scripts
function runPythonScript(scriptName, args = []) {
const scriptPath = path.join(packageRoot, 'scripts', scriptName);
return spawn('python3', [scriptPath, ...args], {
stdio: 'inherit',
cwd: packageRoot
});
}
// Helper to check installation status
function checkStatus() {
const hooksConfig = path.join(os.homedir(), '.config', 'claude', 'hooks.json');
const hasHooks = fs.existsSync(hooksConfig);
console.log(chalk.blue('Claude Hooks Status:'));
console.log(hasHooks ? chalk.green('✓ Hooks configuration installed') : chalk.red('✗ No hooks configuration found'));
try {
execSync('python3 --version', { stdio: 'pipe' });
console.log(chalk.green('✓ Python 3 available'));
} catch {
console.log(chalk.red('✗ Python 3 not found'));
}
return hasHooks;
}
program
.name('claude-hooks')
.description('Intelligent hooks system for Claude Code')
.version(require('../package.json').version);
program
.command('init')
.description('Initialize Claude Hooks (run after npm install)')
.option('--force', 'Force reinstallation even if already configured')
.action((options) => {
console.log(chalk.blue('Initializing Claude Hooks...'));
if (!options.force && checkStatus()) {
console.log(chalk.yellow('⚠️ Claude Hooks already configured. Use --force to reinstall.'));
return;
}
const initScript = runPythonScript('install.py');
initScript.on('close', (code) => {
if (code === 0) {
console.log(chalk.green('\n🎉 Claude Hooks initialized successfully!'));
console.log(chalk.blue('Next steps:'));
console.log('1. Restart Claude Code to activate hooks');
console.log('2. Try: claude-hooks test');
} else {
console.log(chalk.red('❌ Initialization failed'));
process.exit(1);
}
});
});
program
.command('status')
.description('Show Claude Hooks installation status')
.action(() => {
checkStatus();
});
program
.command('test')
.description('Run Claude Hooks tests')
.action(() => {
console.log(chalk.blue('Running Claude Hooks tests...'));
const testScript = runPythonScript('test.py');
testScript.on('close', (code) => {
if (code === 0) {
console.log(chalk.green('✅ All tests passed!'));
} else {
console.log(chalk.red('❌ Some tests failed'));
process.exit(1);
}
});
});
program
.command('uninstall')
.description('Remove Claude Hooks configuration')
.action(() => {
console.log(chalk.blue('Uninstalling Claude Hooks...'));
const uninstallScript = runPythonScript('uninstall.py');
uninstallScript.on('close', (code) => {
if (code === 0) {
console.log(chalk.green('✅ Claude Hooks uninstalled successfully'));
console.log(chalk.yellow('Note: To completely remove, run: npm uninstall -g claude-hooks'));
} else {
console.log(chalk.red('❌ Uninstall failed'));
process.exit(1);
}
});
});
program
.command('backup')
.description('Manually trigger a backup')
.action(() => {
console.log(chalk.blue('Creating manual backup...'));
const backupScript = runPythonScript('manual-backup.py');
backupScript.on('close', (code) => {
if (code === 0) {
console.log(chalk.green('✅ Backup created successfully'));
} else {
console.log(chalk.red('❌ Backup failed'));
process.exit(1);
}
});
});
program.parse();