aios-core
Version:
Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework
213 lines (189 loc) • 5.98 kB
JavaScript
/**
* Disk Space Check
*
* Verifies sufficient disk space is available.
*
* @module aios-core/health-check/checks/local/disk-space
* @version 1.0.0
* @story HCS-2 - Health Check System Implementation
*/
const { execSync } = require('child_process');
const os = require('os');
const { BaseCheck, CheckSeverity, CheckDomain } = require('../../base-check');
/**
* Minimum recommended free space (1GB)
*/
const MIN_FREE_SPACE_GB = 1;
/**
* Warning threshold (5GB)
*/
const WARNING_FREE_SPACE_GB = 5;
/**
* Disk space check
*
* @class DiskSpaceCheck
* @extends BaseCheck
*/
class DiskSpaceCheck extends BaseCheck {
constructor() {
super({
id: 'local.disk-space',
name: 'Disk Space',
description: 'Verifies sufficient disk space is available',
domain: CheckDomain.LOCAL,
severity: CheckSeverity.MEDIUM,
timeout: 5000,
cacheable: false, // Don't cache - space can change
healingTier: 3, // Manual cleanup
tags: ['disk', 'resources'],
});
}
/**
* Execute the check
* @param {Object} context - Execution context
* @returns {Promise<Object>} Check result
*/
async execute(context) {
const platform = os.platform();
const projectRoot = context.projectRoot || process.cwd();
try {
let freeSpaceGB;
let totalSpaceGB;
let usedPercent;
if (platform === 'win32') {
// Windows: use wmic or PowerShell
const diskInfo = this.getWindowsDiskSpace(projectRoot);
freeSpaceGB = diskInfo.free;
totalSpaceGB = diskInfo.total;
usedPercent = diskInfo.usedPercent;
} else {
// Unix: use df
const diskInfo = this.getUnixDiskSpace(projectRoot);
freeSpaceGB = diskInfo.free;
totalSpaceGB = diskInfo.total;
usedPercent = diskInfo.usedPercent;
}
const details = {
freeSpace: `${freeSpaceGB.toFixed(1)} GB`,
totalSpace: `${totalSpaceGB.toFixed(1)} GB`,
usedPercent: `${usedPercent}%`,
projectRoot,
};
// Critical: below minimum
if (freeSpaceGB < MIN_FREE_SPACE_GB) {
return this.fail(
`Low disk space: ${freeSpaceGB.toFixed(1)} GB free (minimum ${MIN_FREE_SPACE_GB} GB)`,
{
recommendation:
'Free up disk space by removing unused files, node_modules, or clearing caches',
healable: false,
healingTier: 3,
details,
},
);
}
// Warning: below recommended
if (freeSpaceGB < WARNING_FREE_SPACE_GB) {
return this.warning(`Disk space running low: ${freeSpaceGB.toFixed(1)} GB free`, {
recommendation:
'Consider freeing up disk space (npm cache clean, remove old node_modules)',
details,
});
}
return this.pass(`Disk space OK: ${freeSpaceGB.toFixed(1)} GB free`, {
details,
});
} catch (error) {
return this.error(`Could not check disk space: ${error.message}`, error);
}
}
/**
* Get disk space on Windows
* @private
*/
getWindowsDiskSpace(projectPath) {
try {
// Try PowerShell first
const drive = projectPath.substring(0, 2);
const output = execSync(
`powershell -Command "Get-PSDrive ${drive[0]} | Select-Object Used,Free | ConvertTo-Json"`,
{ encoding: 'utf8', timeout: 5000, windowsHide: true },
);
const info = JSON.parse(output);
const freeBytes = info.Free;
const usedBytes = info.Used;
const totalBytes = freeBytes + usedBytes;
return {
free: freeBytes / (1024 * 1024 * 1024),
total: totalBytes / (1024 * 1024 * 1024),
usedPercent: Math.round((usedBytes / totalBytes) * 100),
};
} catch {
// Fallback to wmic
try {
const drive = projectPath.substring(0, 2);
const output = execSync(
`wmic logicaldisk where "DeviceID='${drive}'" get FreeSpace,Size /format:csv`,
{ encoding: 'utf8', timeout: 5000, windowsHide: true },
);
const lines = output.trim().split('\n');
if (lines.length >= 2) {
const parts = lines[1].split(',');
const freeBytes = parseInt(parts[1], 10);
const totalBytes = parseInt(parts[2], 10);
return {
free: freeBytes / (1024 * 1024 * 1024),
total: totalBytes / (1024 * 1024 * 1024),
usedPercent: Math.round(((totalBytes - freeBytes) / totalBytes) * 100),
};
}
} catch {
// Return default estimate
}
return { free: 10, total: 100, usedPercent: 90 };
}
}
/**
* Get disk space on Unix
* @private
*/
getUnixDiskSpace(projectPath) {
const output = execSync(`df -k "${projectPath}"`, {
encoding: 'utf8',
timeout: 5000,
});
const lines = output.trim().split('\n');
if (lines.length >= 2) {
// Parse df output (1K blocks)
const parts = lines[1].split(/\s+/);
const totalKB = parseInt(parts[1], 10);
const usedKB = parseInt(parts[2], 10);
const availKB = parseInt(parts[3], 10);
return {
free: availKB / (1024 * 1024),
total: totalKB / (1024 * 1024),
usedPercent: Math.round((usedKB / totalKB) * 100),
};
}
throw new Error('Could not parse df output');
}
/**
* Get healer (manual guide)
*/
getHealer() {
return {
name: 'disk-cleanup-guide',
action: 'manual',
manualGuide: 'Free up disk space',
steps: [
'Run: npm cache clean --force',
'Remove unused node_modules: find . -name "node_modules" -type d -prune -exec rm -rf {} +',
'Clear temporary files',
'Use disk cleanup tools (Windows) or Disk Utility (macOS)',
'Consider moving large files to external storage',
],
warning: 'Be careful not to delete important files',
};
}
}
module.exports = DiskSpaceCheck;