UNPKG

mira-consciousness

Version:

Memory & Intelligence Retention Archive - Preserving The Spark

263 lines 8.63 kB
/** * Cross-Platform Command Utilities * ================================ * * Provides cross-platform alternatives for common shell commands * to ensure MIRA works correctly on Windows, macOS, and Linux. */ import fs from 'fs-extra'; import * as path from 'path'; import { execSync, spawn } from 'child_process'; import * as os from 'os'; /** * Cross-platform directory listing * Replacement for Unix 'ls' and Windows 'dir' */ export async function listDirectory(dirPath, options) { const entries = await fs.readdir(dirPath, { withFileTypes: true }); let results = entries.map(entry => ({ name: entry.name, isDirectory: entry.isDirectory(), path: path.join(dirPath, entry.name) })); // Filter hidden files unless requested if (!options?.hidden) { results = results.filter(r => !r.name.startsWith('.')); } // Get detailed stats if requested if (options?.detailed) { const detailedResults = await Promise.all(results.map(async (r) => { const stats = await fs.stat(r.path); return { ...r, size: stats.size, modified: stats.mtime, mode: stats.mode }; })); // Sort if requested if (options.sort === 'time') { detailedResults.sort((a, b) => b.modified.getTime() - a.modified.getTime()); } else if (options.sort === 'size') { detailedResults.sort((a, b) => b.size - a.size); } else { detailedResults.sort((a, b) => a.name.localeCompare(b.name)); } return detailedResults.map(r => `${r.isDirectory ? 'd' : '-'} ${r.size.toString().padStart(10)} ${r.modified.toISOString()} ${r.name}`); } return results.map(r => r.name); } /** * Cross-platform file search * Replacement for Unix 'find' and Windows 'where' */ export async function findFiles(startPath, pattern, options) { const results = []; const excludeDirs = options?.excludeDirs || ['node_modules', '.git']; async function search(dir, depth = 0) { if (options?.maxDepth && depth > options.maxDepth) return; const entries = await fs.readdir(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); // Skip excluded directories if (entry.isDirectory() && excludeDirs.includes(entry.name)) { continue; } // Check if matches pattern const matches = typeof pattern === 'string' ? entry.name.includes(pattern) : pattern.test(entry.name); if (matches) { if (!options?.type || (options.type === 'file' && entry.isFile()) || (options.type === 'directory' && entry.isDirectory())) { results.push(fullPath); } } // Recurse into directories if (entry.isDirectory()) { await search(fullPath, depth + 1); } } } await search(startPath); return results; } /** * Cross-platform process listing * Replacement for Unix 'ps' and Windows 'tasklist' */ export function listProcesses() { try { if (process.platform === 'win32') { // Windows: Use wmic or tasklist const output = execSync('tasklist /fo csv', { encoding: 'utf-8' }); const lines = output.split('\n').slice(1); // Skip header return lines .filter(line => line.trim()) .map(line => { const parts = line.split('","').map(p => p.replace(/"/g, '')); return { pid: parseInt(parts[1]), name: parts[0] }; }); } else { // Unix: Use ps const output = execSync('ps aux', { encoding: 'utf-8' }); const lines = output.split('\n').slice(1); // Skip header return lines .filter(line => line.trim()) .map(line => { const parts = line.split(/\s+/); return { pid: parseInt(parts[1]), name: path.basename(parts[10] || ''), cmd: parts.slice(10).join(' ') }; }); } } catch (error) { return []; } } /** * Cross-platform environment variable handling */ export function getEnvironmentVariable(name) { // Handle common cross-platform mappings const mappings = { HOME: ['HOME', 'USERPROFILE'], USER: ['USER', 'USERNAME'], TEMP: ['TMPDIR', 'TEMP', 'TMP'], PATH_SEPARATOR: [path.delimiter] }; const candidates = mappings[name] || [name]; for (const candidate of candidates) { const value = process.env[candidate]; if (value !== undefined) { return value; } } return undefined; } /** * Cross-platform command execution with proper escaping */ export async function executeCommand(command, args = [], options) { return new Promise((resolve) => { const isWindows = process.platform === 'win32'; // Properly escape arguments for the platform const escapedArgs = args.map(arg => { if (isWindows) { // Windows: Escape double quotes and wrap in quotes if contains spaces if (arg.includes(' ') || arg.includes('"')) { return `"${arg.replace(/"/g, '\\"')}"`; } return arg; } else { // Unix: Escape single quotes and wrap in quotes if contains spaces if (arg.includes(' ') || arg.includes("'")) { return `'${arg.replace(/'/g, "'\\''")}'`; } return arg; } }); const child = spawn(command, escapedArgs, { ...options, shell: isWindows }); let stdout = ''; let stderr = ''; child.stdout?.on('data', (data) => { stdout += data.toString(); }); child.stderr?.on('data', (data) => { stderr += data.toString(); }); child.on('close', (code) => { resolve({ stdout: stdout.trim(), stderr: stderr.trim(), code: code || 0 }); }); child.on('error', (error) => { resolve({ stdout: '', stderr: error.message, code: 1 }); }); }); } /** * Cross-platform file permissions */ export async function setFilePermissions(filePath, mode) { if (process.platform === 'win32') { // Windows doesn't support Unix-style permissions // Can only toggle readonly attribute const stats = await fs.stat(filePath); const isReadOnly = mode === '444' || mode === 0o444; if (isReadOnly) { // Make read-only await fs.chmod(filePath, stats.mode & ~0o200); } else { // Make writable await fs.chmod(filePath, stats.mode | 0o200); } } else { // Unix: Use standard chmod const numericMode = typeof mode === 'string' ? parseInt(mode, 8) : mode; await fs.chmod(filePath, numericMode); } } /** * Cross-platform temporary directory creation */ export async function createTempDirectory(prefix = 'mira-') { const tempRoot = os.tmpdir(); const tempName = `${prefix}${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const tempPath = path.join(tempRoot, tempName); await fs.ensureDir(tempPath); return tempPath; } /** * Cross-platform path resolution */ export function resolvePath(...paths) { // Handle ~ expansion if (paths[0]?.startsWith('~')) { const home = os.homedir(); paths[0] = paths[0].replace(/^~/, home); } // Use path.resolve for cross-platform resolution return path.resolve(...paths); } /** * Check if a command exists on the system */ export function commandExists(command) { try { if (process.platform === 'win32') { execSync(`where ${command}`, { stdio: 'ignore' }); } else { execSync(`which ${command}`, { stdio: 'ignore' }); } return true; } catch { return false; } } //# sourceMappingURL=crossPlatformCommands.js.map