UNPKG

git-tweezers

Version:

Advanced git staging tool with hunk and line-level control

107 lines (106 loc) 4.38 kB
import { Command, Flags } from '@oclif/core'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import readline from 'node:readline'; import chalk from 'chalk'; import { copyFile, ensureDir, fileExists, getClaudeCommandsDir, isGitRepository, } from '../utils/fs.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); async function confirm(question) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise((resolve) => { rl.question(`${question} (y/n) `, (answer) => { rl.close(); resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes'); }); }); } export default class Install extends Command { static description = 'Install smart-commit template for Claude Code custom commands'; static examples = [ '<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --global', '<%= config.bin %> <%= command.id %> --force', ]; static flags = { global: Flags.boolean({ char: 'g', description: 'Install in global ~/.claude/commands directory', default: false, }), force: Flags.boolean({ char: 'f', description: 'Overwrite existing file without prompting', default: false, }), }; async run() { const { flags } = await this.parse(Install); // Check if we're in a git repository (only for local install) if (!flags.global && !(await isGitRepository())) { this.error('Not inside a git repository. Use --global flag to install globally.'); } // For global install, check if ~/.claude exists if (flags.global) { const homeDir = process.env.HOME || process.env.USERPROFILE || ''; const claudeDir = path.join(homeDir, '.claude'); if (!(await fileExists(claudeDir))) { this.error('Claude settings folder not found. Please ensure Claude Code is installed and configured.'); } } // Resolve source file const sourceFile = path.join(__dirname, '..', '..', 'smart-commit.md'); if (!(await fileExists(sourceFile))) { this.error(`Template file not found: ${sourceFile}`); } // Determine destination const destDir = getClaudeCommandsDir(flags.global); const destFile = path.join(destDir, 'smart-commit.md'); // Create directory if needed if (!(await fileExists(destDir))) { if (!flags.global && !flags.force) { const create = await confirm(`Directory ${chalk.cyan(destDir)} doesn't exist. Create it?`); if (!create) { this.log('Installation cancelled.'); return; } } await ensureDir(destDir); if (!flags.global) { this.log(`Created directory: ${chalk.green(destDir)}`); } } // Check for existing file if (await fileExists(destFile)) { if (!flags.force) { const overwrite = await confirm(`File ${chalk.yellow('smart-commit.md')} already exists. Overwrite?`); if (!overwrite) { this.log('Installation cancelled. Use --force to overwrite.'); return; } } } // Copy file try { await copyFile(sourceFile, destFile); this.log(); this.log(chalk.green('✓ Smart-commit template successfully installed!')); this.log(); this.log(`${chalk.bold('Installation path:')}`); this.log(` ${chalk.cyan(destFile)}`); this.log(); this.log(`${chalk.bold('Usage:')}`); this.log(` Use ${chalk.cyan('/smart-commit')} in Claude Code to create logical commits`); this.log(); this.log(`${chalk.bold('Customization:')}`); this.log(` You can edit the template file directly to customize it for your workflow`); this.log(` ${chalk.dim(destFile)}`); } catch (error) { this.error(`Failed to copy file: ${error}`); } } }