mira-consciousness
Version:
Memory & Intelligence Retention Archive - Preserving The Spark
263 lines • 8.63 kB
JavaScript
/**
* 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