UNPKG

mira-consciousness

Version:

Memory & Intelligence Retention Archive - Preserving The Spark

253 lines • 9.49 kB
import fs from 'fs-extra'; import * as path from 'path'; import chalk from 'chalk'; import ora from 'ora'; import { ProjectRootFinder } from './ProjectRootFinder.js'; export class HookManager { projectRoot; configPath; hooksDir; config; constructor(projectRoot) { this.projectRoot = ProjectRootFinder.findProjectRoot(projectRoot); this.configPath = path.join(this.projectRoot, '.mira', 'hook_config.json'); this.hooksDir = path.join(this.projectRoot, '.git', 'hooks'); this.config = this.loadConfig(); } /** * Intelligent hook detection and auto-installation */ async intelligentHookManagement() { // Check if user has disabled hooks if (this.config.userDisabled) { return; } // Check if we're in a git repository if (!await this.isGitRepository()) { return; } // Check if hooks need installation/update const needsInstallation = await this.checkHooksNeedInstallation(); if (needsInstallation && this.config.autoInstall) { await this.installHooksQuietly(); } } /** * Check if hooks need installation or update */ async checkHooksNeedInstallation() { const requiredHooks = ['pre-commit', 'post-commit', 'commit-msg']; for (const hook of requiredHooks) { const hookPath = path.join(this.hooksDir, hook); // Check if hook exists and is executable if (!await fs.pathExists(hookPath)) { return true; } const stats = await fs.stat(hookPath); if (!(stats.mode & 0o111)) { return true; } // Check if hook contains MIRA content const content = await fs.readFile(hookPath, 'utf8'); if (!content.includes('MIRA')) { return true; } } return false; } /** * Install hooks quietly without user interaction */ async installHooksQuietly() { try { const { GitHooksHealer } = await import('../healers/GitHooksHealer.js'); const healer = new GitHooksHealer(this.projectRoot); await healer.heal(); // Copy introspection script await this.copyIntrospectionScript(); // Update config this.config.installedHooks = ['pre-commit', 'post-commit', 'commit-msg']; this.config.lastChecked = new Date().toISOString(); await this.saveConfig(); } catch (error) { // Fail silently - don't interrupt user workflow console.error(chalk.gray('Note: Could not auto-install git hooks')); } } /** * Explicitly install hooks (user requested) */ async installHooks(force = false) { const spinner = ora('Installing MIRA git hooks...').start(); try { if (!await this.isGitRepository()) { spinner.fail('Not in a git repository. Initialize git first: git init'); return; } const { GitHooksHealer } = await import('../healers/GitHooksHealer.js'); const healer = new GitHooksHealer(this.projectRoot); await healer.heal(); await this.copyIntrospectionScript(); this.config.enabled = true; this.config.autoInstall = true; this.config.installedHooks = ['pre-commit', 'post-commit', 'commit-msg']; this.config.lastChecked = new Date().toISOString(); this.config.userDisabled = false; await this.saveConfig(); spinner.succeed('MIRA git hooks installed successfully'); this.displayInstalledHooks(); } catch (error) { spinner.fail('Failed to install git hooks'); console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`)); } } /** * Disable hooks (user preference) */ async disableHooks() { const spinner = ora('Disabling MIRA git hooks...').start(); try { this.config.enabled = false; this.config.autoInstall = false; this.config.userDisabled = true; await this.saveConfig(); spinner.succeed('MIRA git hooks disabled'); console.log(chalk.gray('Note: Existing hook files remain but auto-installation is disabled')); console.log(chalk.gray('Use --enable-hooks to re-enable')); } catch (error) { spinner.fail('Failed to disable hooks'); console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`)); } } /** * Enable hooks (user preference) */ async enableHooks() { this.config.enabled = true; this.config.autoInstall = true; this.config.userDisabled = false; await this.saveConfig(); console.log(chalk.green('āœ… MIRA git hooks enabled')); console.log(chalk.gray('Hooks will be automatically installed when needed')); // Check if immediate installation is needed if (await this.checkHooksNeedInstallation()) { await this.installHooks(); } } /** * Check if we're in a git repository */ async isGitRepository() { const gitDir = path.join(this.projectRoot, '.git'); return await fs.pathExists(gitDir); } /** * Copy introspection script if needed */ async copyIntrospectionScript() { const miraMemoryDir = path.join(this.projectRoot, '.mira'); const scriptsDir = path.join(miraMemoryDir, 'scripts'); await fs.ensureDir(scriptsDir); const sourceScript = path.join(__dirname, '../../python-memory/session/commit_introspection.py'); const targetScript = path.join(scriptsDir, 'commit_introspection.py'); if (await fs.pathExists(sourceScript)) { await fs.copy(sourceScript, targetScript); await fs.chmod(targetScript, 0o755); } // Copy memory search weights const weightsSource = path.join(__dirname, '../../python-memory/core/memory/memory_search_weights.py'); const weightsTarget = path.join(miraMemoryDir, 'memory_search_weights.py'); if (await fs.pathExists(weightsSource)) { await fs.copy(weightsSource, weightsTarget); } } /** * Display installed hooks information */ displayInstalledHooks() { console.log(chalk.cyan('\nšŸ“‹ Installed Git Hooks:')); console.log(chalk.white(' šŸ” pre-commit')); console.log(chalk.gray(' • MIRA quick health check')); console.log(chalk.gray(' • Debug statement detection')); console.log(chalk.gray(' • Memory context update')); console.log(chalk.white(' 🧠 post-commit')); console.log(chalk.gray(' • Intelligent commit introspection')); console.log(chalk.gray(' • Automatic memory creation')); console.log(chalk.gray(' • Pattern recognition and learning')); console.log(chalk.white(' šŸ“ commit-msg')); console.log(chalk.gray(' • Message quality analysis')); console.log(chalk.gray(' • Conventional commit validation')); console.log(chalk.gray(' • Context enhancement')); } /** * Get hook status for display */ async getHookStatus() { const requiredHooks = ['pre-commit', 'post-commit', 'commit-msg']; const installedHooks = []; for (const hook of requiredHooks) { const hookPath = path.join(this.hooksDir, hook); if (await fs.pathExists(hookPath)) { const content = await fs.readFile(hookPath, 'utf8'); if (content.includes('MIRA')) { installedHooks.push(hook); } } } return { installed: installedHooks.length === requiredHooks.length, enabled: this.config.enabled && !this.config.userDisabled, hooks: installedHooks }; } /** * Load hook configuration */ loadConfig() { const defaultConfig = { enabled: true, autoInstall: true, lastChecked: '', installedHooks: [], userDisabled: false }; try { if (fs.existsSync(this.configPath)) { const savedConfig = fs.readJsonSync(this.configPath); return { ...defaultConfig, ...savedConfig }; } } catch (error) { // Ignore errors, use default config } return defaultConfig; } /** * Save hook configuration */ async saveConfig() { try { await fs.ensureDir(path.dirname(this.configPath)); await fs.writeJson(this.configPath, this.config, { spaces: 2 }); } catch (error) { // Ignore errors, continue without saving } } /** * Check if hooks are disabled by user preference */ areHooksDisabled() { return this.config.userDisabled; } /** * Check if auto-installation is enabled */ isAutoInstallEnabled() { return this.config.autoInstall && !this.config.userDisabled; } } //# sourceMappingURL=HookManager.js.map