mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
253 lines ⢠9.49 kB
JavaScript
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