UNPKG

claudekit

Version:

CLI tools for Claude Code development workflow

126 lines (106 loc) 3.63 kB
import { Logger } from '../utils/logger.js'; import { loadConfig, saveConfig } from '../utils/config.js'; import * as path from 'node:path'; import fs from 'fs-extra'; interface UpdateOptions { config?: string; file?: string; verbose?: boolean; quiet?: boolean; dryRun?: boolean; } /** * Update a hook or command configuration */ export async function update( type: string, name: string, options: UpdateOptions = {} ): Promise<void> { const logger = new Logger(); if (options.verbose === true) { logger.setLevel('debug'); } else if (options.quiet === true) { logger.setLevel('error'); } logger.debug(`Updating ${type} "${name}" with options:`, options); // Validate type const validTypes = ['command', 'config']; if (!validTypes.includes(type)) { throw new Error( `Invalid type "${type}". Must be one of: ${validTypes.join(', ')} (hooks are now embedded in claudekit).` ); } if (type === 'config') { // Update configuration await updateConfig(name, options); } else { // Update command file await updateFile(type, name, options); } logger.success(`Successfully updated ${type} "${name}"`); } async function updateConfig(configKey: string, options: UpdateOptions): Promise<void> { const logger = new Logger(); const config = await loadConfig(process.cwd()); // Parse configuration updates let updates: unknown; if (options.config !== undefined && options.config !== '') { try { updates = JSON.parse(options.config); } catch (error) { throw new Error(`Invalid JSON in --config: ${error}`); } } else if (options.file !== undefined && options.file !== '') { const content = await fs.readFile(options.file, 'utf8'); try { updates = JSON.parse(content); } catch (error) { throw new Error(`Invalid JSON in file ${options.file}: ${error}`); } } else { throw new Error('Either --config or --file must be provided'); } // Apply updates to config // Handle nested keys like "hooks.PostToolUse" const keys = configKey.split('.'); let target: Record<string, unknown> = config as Record<string, unknown>; for (let i = 0; i < keys.length - 1; i++) { const key = keys[i]; if (key !== undefined && key !== '' && target !== undefined) { if (target[key] === undefined || target[key] === null) { target[key] = {}; } target = target[key] as Record<string, unknown>; } } const finalKey = keys[keys.length - 1]; if (finalKey !== undefined && finalKey !== '' && target !== undefined) { target[finalKey] = updates; } // Save updated config await saveConfig(process.cwd(), config); logger.debug('Configuration updated successfully'); } async function updateFile(type: string, name: string, options: UpdateOptions): Promise<void> { const logger = new Logger(); // Determine target path const targetDir = '.claude/commands'; const targetPath = path.join(targetDir, `${name}.md`); // Check if file exists if (!(await fs.pathExists(targetPath))) { throw new Error(`${type} "${name}" not found at ${targetPath}`); } // Read new content let newContent: string; if (options.config !== undefined && options.config !== '') { newContent = options.config; } else if (options.file !== undefined && options.file !== '') { newContent = await fs.readFile(options.file, 'utf8'); } else { throw new Error('Either --config or --file must be provided'); } // Update the file await fs.writeFile(targetPath, newContent, 'utf8'); logger.debug(`Updated ${type} file at ${targetPath}`); }