import { Command } from 'commander' import { spawn } from 'node:child_process' import { access } from 'node:fs/promises' import { join } from 'node:path' import { homedir } from 'node:os' import { colors, logError } from '../utils/output.js' const BITCH_DATA_DIR = join(homedir(), '.local', 'share', 'bitch') const COMMITS_SCRIPT_PATH = join(BITCH_DATA_DIR, 'commits-daemon.sh') const OLD_COMMITS_PATH = join(homedir(), '.local', 'bin', 'commits') /** * Check if commits script exists at a path */ async function scriptExists(path: string): Promise { try { await access(path) return true } catch { return false } } /** * Find the commits script location */ async function findCommitsScript(): Promise { // Check bitch's copy first if (await scriptExists(COMMITS_SCRIPT_PATH)) { return COMMITS_SCRIPT_PATH } // Fall back to standalone if (await scriptExists(OLD_COMMITS_PATH)) { return OLD_COMMITS_PATH } return null } /** * Run the commits script with the 'commit' subcommand */ function runCommit(scriptPath: string, args: string[]): void { const child = spawn('bash', [scriptPath, 'commit', ...args], { stdio: 'inherit', env: process.env, }) child.on('close', (code) => { process.exit(code || 0) }) child.on('error', (err) => { logError(`Failed to run commit: ${err.message}`) process.exit(1) }) } export function createCommitCommand(): Command { const cmd = new Command('commit') .description('One-shot AI-generated commit (uses daemon if running, otherwise standalone)') .option('-A, --all', 'Commit all configured repos (default: current directory only)') .option('-p, --push', 'Push after committing (default: true)') .option('--no-push', 'Commit without pushing') .option('-n, --dry-run', 'Preview what would be committed without committing') .allowUnknownOption(true) .action(async (options, command) => { // Build args for the Python CLI const args: string[] = [] if (options.all) { args.push('--all') } if (options.push === false) { args.push('--no-push') } if (options.dryRun) { args.push('--dry-run') } // Add any additional unknown args const extraArgs = command.args.filter((arg: string) => !['commit'].includes(arg)) args.push(...extraArgs) // Find the commits script const scriptPath = await findCommitsScript() if (!scriptPath) { logError('Commits script not found.') console.log() console.log('To install:') console.log('1. Install auto-commit-service:') console.log(colors.dim(' cd ~/Code/@applications/@ml/auto-commit-service')) console.log(colors.dim(' pip install -e .')) console.log() console.log('2. Copy the commits CLI script to ~/.local/bin/commits') console.log() console.log('3. Run:') console.log(colors.cyan(' bitch commits install')) process.exit(1) } runCommit(scriptPath, args) }) return cmd }