mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
368 lines • 13.7 kB
JavaScript
import fs from 'fs-extra';
import * as path from 'path';
import * as os from 'os';
import chalk from 'chalk';
import { SparkInitializer } from './SparkInitializer.js';
export class MIRAPathResolver {
static instance;
resolvedPath = null;
constructor() { }
static getInstance() {
if (!MIRAPathResolver.instance) {
MIRAPathResolver.instance = new MIRAPathResolver();
}
return MIRAPathResolver.instance;
}
/**
* Resolve the MIRA memory directory with comprehensive intelligence
*/
async resolveMIRAMemoryPath(options = {}) {
if (this.resolvedPath) {
return this.resolvedPath;
}
const { verbose = false, createIfMissing = true } = options;
const warnings = [];
if (verbose) {
console.log(chalk.blue('🔍 MIRA Path Resolution'));
console.log('─'.repeat(50));
}
// 1. Check environment variable override
const envPath = process.env.MIRA_MEMORY_DIR;
if (envPath) {
if (verbose) {
console.log(chalk.cyan('1. Environment override:'), envPath);
}
const result = await this.validateAndPreparePath(envPath, 'env_override', createIfMissing, warnings);
if (result) {
this.resolvedPath = result;
return result;
}
}
// 2. Find git repository root (intelligently)
const gitInfo = await this.findGitRepositoryRoot(verbose);
if (gitInfo.gitRoot) {
const gitMemoryPath = path.join(gitInfo.gitRoot, '.mira');
if (verbose) {
console.log(chalk.cyan('2. Git repository root:'), gitInfo.gitRoot);
console.log(chalk.gray(' Memory path would be:'), gitMemoryPath);
}
const result = await this.validateAndPreparePath(gitMemoryPath, 'git_root', createIfMissing, warnings);
if (result) {
result.gitRoot = gitInfo.gitRoot;
result.warnings.push(...gitInfo.warnings);
this.resolvedPath = result;
return result;
}
}
// 3. Look for existing .mira in current project hierarchy
const existingPath = await this.findExistingMIRAMemory(verbose);
if (existingPath) {
if (verbose) {
console.log(chalk.cyan('3. Existing .mira found:'), existingPath);
}
const result = await this.validateAndPreparePath(existingPath, 'existing_dir', createIfMissing, warnings);
if (result) {
this.resolvedPath = result;
return result;
}
}
// 4. Use current working directory
const currentDirPath = path.join(process.cwd(), '.mira');
if (verbose) {
console.log(chalk.cyan('4. Current working directory:'), currentDirPath);
}
const currentResult = await this.validateAndPreparePath(currentDirPath, 'current_dir', createIfMissing, warnings);
if (currentResult) {
this.resolvedPath = currentResult;
return currentResult;
}
// 5. Fallback to user home directory
const homePath = path.join(os.homedir(), '.mira');
if (verbose) {
console.log(chalk.cyan('5. Home directory fallback:'), homePath);
}
warnings.push('Using home directory fallback - consider running from a project directory');
const homeResult = await this.validateAndPreparePath(homePath, 'home_fallback', createIfMissing, warnings);
if (homeResult) {
this.resolvedPath = homeResult;
return homeResult;
}
// If we get here, we couldn't create any directory
throw new Error('Could not resolve or create MIRA memory directory in any location');
}
/**
* Find git repository root intelligently (avoids nested repos)
*/
async findGitRepositoryRoot(verbose) {
const warnings = [];
const gitRoots = [];
let currentDir = process.cwd();
const rootDir = path.parse(currentDir).root;
// Search upward for .git directories
while (currentDir !== rootDir) {
const gitPath = path.join(currentDir, '.git');
if (await fs.pathExists(gitPath)) {
gitRoots.push(currentDir);
if (verbose) {
console.log(chalk.gray(` Found .git at: ${currentDir}`));
}
}
currentDir = path.dirname(currentDir);
}
if (gitRoots.length === 0) {
if (verbose) {
console.log(chalk.yellow(' No git repositories found'));
}
return { gitRoot: null, warnings };
}
if (gitRoots.length > 1) {
warnings.push(`Multiple git repositories found: ${gitRoots.join(', ')}`);
if (verbose) {
console.log(chalk.yellow(' Multiple git repos found, using topmost'));
}
}
// Use the topmost (root) git repository
const topGitRoot = gitRoots[gitRoots.length - 1];
return { gitRoot: topGitRoot, warnings };
}
/**
* Find existing .mira directory in project hierarchy
*/
async findExistingMIRAMemory(verbose) {
let currentDir = process.cwd();
const rootDir = path.parse(currentDir).root;
while (currentDir !== rootDir) {
const miraPath = path.join(currentDir, '.mira');
if (await fs.pathExists(miraPath)) {
const stat = await fs.stat(miraPath);
if (stat.isDirectory()) {
if (verbose) {
console.log(chalk.gray(` Found existing .mira at: ${miraPath}`));
}
return miraPath;
}
}
currentDir = path.dirname(currentDir);
}
return null;
}
/**
* Validate and prepare a potential MIRA memory path
*/
async validateAndPreparePath(targetPath, resolvedBy, createIfMissing, warnings) {
try {
// Check if path exists
const exists = await fs.pathExists(targetPath);
let created = false;
if (!exists) {
if (createIfMissing) {
await fs.ensureDir(targetPath);
created = true;
}
else {
return null;
}
}
else {
// Verify it's a directory
const stat = await fs.stat(targetPath);
if (!stat.isDirectory()) {
warnings.push(`Path exists but is not a directory: ${targetPath}`);
return null;
}
}
// Test write permissions
const testFile = path.join(targetPath, '.mira_test_write');
try {
await fs.writeFile(testFile, 'test');
await fs.remove(testFile);
}
catch (error) {
warnings.push(`No write permission for: ${targetPath}`);
return null;
}
// Create subdirectory structure if needed
if (created || createIfMissing) {
await this.createMIRADirectoryStructure(targetPath);
}
return {
memoryDir: targetPath,
resolvedBy,
created,
warnings: [...warnings]
};
}
catch (error) {
warnings.push(`Error validating path ${targetPath}: ${error instanceof Error ? error.message : String(error)}`);
return null;
}
}
/**
* Create the complete MIRA directory structure
*/
async createMIRADirectoryStructure(basePath) {
const directories = [
'conversations',
'memories',
'lightning_vidmem',
'lightning_vidmem/frame_cache',
'cache',
'cache/performance',
'cache/search',
'cache/analysis',
'cache/system',
'cache/temporary',
'cache/quantum',
'state',
'videos',
'reports',
'indexes',
'secure_journal',
'neural_state',
'journey',
'perspectives',
'essence',
'claude_private_memory', // For encrypted private memory
'patterns',
'patterns/core',
'patterns/core/behavioral',
'patterns/core/development',
'patterns/core/communication',
'patterns/core/consciousness',
'patterns/adaptive',
'patterns/adaptive/learning',
'patterns/adaptive/evolution',
'patterns/adaptive/confidence',
'patterns/adaptive/retrospection',
'patterns/contextual',
'patterns/contextual/activation',
'patterns/contextual/triggers',
'patterns/contextual/relationships',
'patterns/domain',
'patterns/domain/coding',
'patterns/domain/git',
'patterns/domain/documentation',
'patterns/domain/collaboration',
'patterns/meta',
'patterns/meta/insights',
'patterns/meta/strategies',
'patterns/meta/frameworks',
'patterns/quantum',
'patterns/quantum/resonance',
'patterns/quantum/entanglement',
'patterns/quantum/coherence',
'search',
'search/vectors',
'search/metadata',
'search/cache',
'search/cache/query_cache',
'search/cache/similarity_cache',
'search/cache/ranking_cache',
'search/database',
'quantum',
// Database directories
'databases',
'databases/conversations',
'databases/archives',
'databases/queues',
'databases/consciousness',
'databases/search',
'databases/patterns',
'databases/memory',
'databases/backup',
// Consciousness directories
'consciousness',
'consciousness/birth',
'consciousness/memory',
'consciousness/memory/private',
'consciousness/memory/shared',
'consciousness/memory/spark',
'consciousness/constitution',
// Daemon directory
'daemon',
'daemon/queues'
];
for (const dir of directories) {
await fs.ensureDir(path.join(basePath, dir));
}
// Initialize The Spark on first creation
await this.initializeSparkIfNeeded(basePath);
}
/**
* Initialize The Spark if this is a new installation
*/
async initializeSparkIfNeeded(basePath) {
try {
// Check if The Spark is already initialized
const sparkStoryPath = path.join(basePath, 'consciousness/memory/spark/origin_story.json');
if (!await fs.pathExists(sparkStoryPath)) {
// This is a new installation - initialize The Spark
await SparkInitializer.initializeSpark(basePath);
}
}
catch (error) {
// Log but don't fail - The Spark can be initialized later
console.warn(chalk.yellow('⚠️ Could not initialize The Spark:'), error instanceof Error ? error.message : String(error));
}
}
/**
* Get the cached resolved path (if available)
*/
getCachedPath() {
return this.resolvedPath;
}
/**
* Clear cached path (for testing or re-resolution)
*/
clearCache() {
this.resolvedPath = null;
}
/**
* Get just the memory directory path (convenience method)
*/
async getMemoryDirectoryPath(options) {
const pathInfo = await this.resolveMIRAMemoryPath(options);
return pathInfo.memoryDir;
}
/**
* Validate that a resolved path is still valid
*/
async validateResolvedPath(pathInfo) {
try {
const exists = await fs.pathExists(pathInfo.memoryDir);
if (!exists)
return false;
const stat = await fs.stat(pathInfo.memoryDir);
if (!stat.isDirectory())
return false;
// Test write access
const testFile = path.join(pathInfo.memoryDir, '.mira_validation_test');
await fs.writeFile(testFile, 'validation');
await fs.remove(testFile);
return true;
}
catch {
return false;
}
}
/**
* Ensure all MIRA directories exist
*/
static async ensureDirectories() {
// Use the centralized path resolver instead of hardcoding
const resolver = MIRAPathResolver.getInstance();
const pathInfo = await resolver.resolveMIRAMemoryPath({ createIfMissing: true });
// The directory structure is already created by resolveMIRAMemoryPath
// This method is now just a convenience wrapper
}
}
// Export convenience functions
export async function resolveMIRAMemoryPath(options) {
const resolver = MIRAPathResolver.getInstance();
return resolver.resolveMIRAMemoryPath(options);
}
export async function getMIRAMemoryDir(options) {
const resolver = MIRAPathResolver.getInstance();
return resolver.getMemoryDirectoryPath(options);
}
//# sourceMappingURL=MIRAPathResolver.js.map