trace.ai-cli
Version:
A powerful AI-powered CLI tool
957 lines (846 loc) • 38.7 kB
JavaScript
const os = require('os');
const { execSync } = require('child_process');
const si = require('systeminformation');
/**
* Get basic system information
* @returns {Object} System information object
*/
async function getBasicSystemInfo() {
try {
const [osInfo, system, time] = await Promise.all([
si.osInfo().catch(() => ({})),
si.system().catch(() => ({})),
si.time().catch(() => ({}))
]);
const basicInfo = {
platform: os.platform(),
type: os.type(),
distro: osInfo.distro || 'Unknown',
release: os.release(),
codename: osInfo.codename || '',
kernel: osInfo.kernel || os.release(),
arch: os.arch(),
hostname: os.hostname(),
uptime: os.uptime(),
loadAvg: os.loadavg(),
manufacturer: system.manufacturer || 'Unknown',
model: system.model || 'Unknown',
serial: system.serial || 'N/A',
uuid: system.uuid || 'N/A',
sku: system.sku || 'N/A',
virtual: system.virtual || false,
userInfo: os.userInfo(),
tempDir: os.tmpdir(),
nodeVersion: process.version,
timestamp: new Date().toISOString(),
timezone: time.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone
};
return basicInfo;
} catch (error) {
// Fallback to basic OS information
return {
platform: os.platform(),
type: os.type(),
release: os.release(),
arch: os.arch(),
hostname: os.hostname(),
uptime: os.uptime(),
loadAvg: os.loadavg(),
userInfo: os.userInfo(),
tempDir: os.tmpdir(),
nodeVersion: process.version,
timestamp: new Date().toISOString(),
error: 'Limited information available due to system restrictions'
};
}
}
/**
* Get detailed CPU information
* @returns {Object} CPU information
*/
async function getCpuInfo() {
try {
const [cpu, cpuCurrentSpeed, cpuTemperature, currentLoad, cpuFlags] = await Promise.all([
si.cpu().catch(() => ({})),
si.cpuCurrentSpeed().catch(() => ({})),
si.cpuTemperature().catch(() => ({})),
si.currentLoad().catch(() => ({})),
si.cpuFlags().catch(() => '')
]);
const cpuInfo = {
manufacturer: cpu.manufacturer || 'Unknown',
brand: cpu.brand || 'Unknown',
vendor: cpu.vendor || cpu.manufacturer || 'Unknown',
family: cpu.family || 'Unknown',
model: cpu.model || cpu.brand || 'Unknown',
stepping: cpu.stepping || 'Unknown',
revision: cpu.revision || 'Unknown',
voltage: cpu.voltage || 'Unknown',
speed: cpu.speed || 0,
speedMin: cpu.speedMin || 0,
speedMax: cpu.speedMax || 0,
governor: cpu.governor || 'Unknown',
cores: cpu.cores || os.cpus().length,
physicalCores: cpu.physicalCores || cpu.cores || os.cpus().length,
processors: cpu.processors || 1,
socket: cpu.socket || 'Unknown',
flags: cpuFlags || cpu.flags || 'Unknown',
virtualization: cpu.virtualization || false,
cache: cpu.cache || {},
currentSpeed: cpuCurrentSpeed.avg || cpuCurrentSpeed.cores || cpu.speed || 0,
temperature: cpuTemperature.main || cpuTemperature.max || null,
load: {
currentLoad: currentLoad.currentLoad || 0,
currentLoadUser: currentLoad.currentLoadUser || 0,
currentLoadSystem: currentLoad.currentLoadSystem || 0,
currentLoadNice: currentLoad.currentLoadNice || 0,
currentLoadIdle: currentLoad.currentLoadIdle || 100,
currentLoadIrq: currentLoad.currentLoadIrq || 0,
rawCurrentLoad: currentLoad.rawCurrentLoad || 0,
rawCurrentLoadUser: currentLoad.rawCurrentLoadUser || 0,
rawCurrentLoadSystem: currentLoad.rawCurrentLoadSystem || 0,
rawCurrentLoadNice: currentLoad.rawCurrentLoadNice || 0,
rawCurrentLoadIdle: currentLoad.rawCurrentLoadIdle || 0,
rawCurrentLoadIrq: currentLoad.rawCurrentLoadIrq || 0,
cpus: currentLoad.cpus || []
},
loadAvg: os.loadavg(),
timestamp: new Date().toISOString()
};
return cpuInfo;
} catch (error) {
// Fallback to basic CPU information
const cpus = os.cpus();
return {
model: cpus[0]?.model || 'Unknown',
speed: cpus[0]?.speed || 0,
cores: cpus.length,
loadAvg: os.loadavg(),
load: {
currentLoad: 0,
currentLoadUser: 0,
currentLoadSystem: 0,
currentLoadIdle: 100
},
timestamp: new Date().toISOString(),
error: 'Limited CPU information available'
};
}
}
/**
* Get memory information in a human-readable format
* @returns {Object} Memory information
*/
async function getMemoryInfo() {
try {
const [mem, memLayout] = await Promise.all([
si.mem().catch(() => ({
total: os.totalmem(),
free: os.freemem(),
used: os.totalmem() - os.freemem()
})),
si.memLayout().catch(() => [])
]);
// Convert to human-readable format
const totalMemGB = (mem.total / (1024 * 1024 * 1024)).toFixed(2);
const freeMemGB = (mem.free / (1024 * 1024 * 1024)).toFixed(2);
const usedMemGB = (mem.used / (1024 * 1024 * 1024)).toFixed(2);
const activeMemGB = mem.active ? (mem.active / (1024 * 1024 * 1024)).toFixed(2) : 'N/A';
const availableMemGB = mem.available ? (mem.available / (1024 * 1024 * 1024)).toFixed(2) : freeMemGB;
const swapTotalGB = mem.swaptotal ? (mem.swaptotal / (1024 * 1024 * 1024)).toFixed(2) : '0.00';
const swapUsedGB = mem.swapused ? (mem.swapused / (1024 * 1024 * 1024)).toFixed(2) : '0.00';
const swapFreeGB = mem.swapfree ? (mem.swapfree / (1024 * 1024 * 1024)).toFixed(2) : '0.00';
const memoryInfo = {
total: `${totalMemGB} GB`,
free: `${freeMemGB} GB`,
used: `${usedMemGB} GB`,
active: `${activeMemGB} GB`,
available: `${availableMemGB} GB`,
usagePercent: `${((mem.used / mem.total) * 100).toFixed(1)}%`,
buffers: mem.buffers ? formatBytes(mem.buffers) : 'N/A',
cached: mem.cached ? formatBytes(mem.cached) : 'N/A',
slab: mem.slab ? formatBytes(mem.slab) : 'N/A',
swapTotal: `${swapTotalGB} GB`,
swapUsed: `${swapUsedGB} GB`,
swapFree: `${swapFreeGB} GB`,
swapUsagePercent: mem.swaptotal > 0 ? `${((mem.swapused / mem.swaptotal) * 100).toFixed(1)}%` : '0.0%',
layout: memLayout.map(module => ({
size: module.size ? formatBytes(module.size) : 'Unknown',
bank: module.bank || 'Unknown',
type: module.type || 'Unknown',
clockSpeed: module.clockSpeed ? `${module.clockSpeed} MHz` : 'Unknown',
formFactor: module.formFactor || 'Unknown',
manufacturer: module.manufacturer || 'Unknown',
partNum: module.partNum || 'Unknown',
serialNum: module.serialNum || 'Unknown',
voltageConfigured: module.voltageConfigured ? `${module.voltageConfigured} V` : 'Unknown',
voltageMin: module.voltageMin ? `${module.voltageMin} V` : 'Unknown',
voltageMax: module.voltageMax ? `${module.voltageMax} V` : 'Unknown'
})),
timestamp: new Date().toISOString()
};
return memoryInfo;
} catch (error) {
// Fallback to basic memory information
const totalMemMB = Math.round(os.totalmem() / (1024 * 1024));
const freeMemMB = Math.round(os.freemem() / (1024 * 1024));
const usedMemMB = totalMemMB - freeMemMB;
const memUsagePercent = Math.round((usedMemMB / totalMemMB) * 100);
return {
total: `${(totalMemMB / 1024).toFixed(2)} GB`,
free: `${(freeMemMB / 1024).toFixed(2)} GB`,
used: `${(usedMemMB / 1024).toFixed(2)} GB`,
usagePercent: `${memUsagePercent}%`,
timestamp: new Date().toISOString(),
error: 'Limited memory information available'
};
}
}
/**
* Get disk space information
* @returns {Object} Disk information
*/
async function getDiskInfo() {
try {
const [fsSize, blockDevices, diskLayout, diskIo] = await Promise.all([
si.fsSize().catch(() => []),
si.blockDevices().catch(() => []),
si.diskLayout().catch(() => []),
si.disksIO().catch(() => ({}))
]);
// Format file system sizes
const formattedFsSize = fsSize.map(fs => ({
fs: fs.fs || 'Unknown',
type: fs.type || 'Unknown',
size: fs.size ? formatBytes(fs.size) : 'Unknown',
used: fs.used ? formatBytes(fs.used) : 'Unknown',
available: fs.available ? formatBytes(fs.available) : 'Unknown',
usagePercent: fs.use ? `${fs.use.toFixed(1)}%` : 'Unknown',
mount: fs.mount || 'Unknown'
}));
// Format block devices info
const formattedBlockDevices = blockDevices.map(device => ({
name: device.name || 'Unknown',
type: device.type || 'Unknown',
fsType: device.fstype || 'Unknown',
mount: device.mount || 'Unknown',
size: device.size ? formatBytes(device.size) : 'Unknown',
physical: device.physical || 'Unknown',
uuid: device.uuid || 'Unknown',
label: device.label || 'Unknown',
model: device.model || 'Unknown',
serial: device.serial || 'Unknown',
removable: device.removable !== undefined ? device.removable : 'Unknown',
protocol: device.protocol || 'Unknown'
}));
// Format disk layout info
const formattedDiskLayout = diskLayout.map(disk => ({
device: disk.device || 'Unknown',
type: disk.type || 'Unknown',
name: disk.name || 'Unknown',
vendor: disk.vendor || 'Unknown',
size: disk.size ? formatBytes(disk.size) : 'Unknown',
bytesPerSector: disk.bytesPerSector || 'Unknown',
totalCylinders: disk.totalCylinders || 'Unknown',
totalHeads: disk.totalHeads || 'Unknown',
totalSectors: disk.totalSectors || 'Unknown',
totalTracks: disk.totalTracks || 'Unknown',
tracksPerCylinder: disk.tracksPerCylinder || 'Unknown',
sectorsPerTrack: disk.sectorsPerTrack || 'Unknown',
firmwareRevision: disk.firmwareRevision || 'Unknown',
serialNum: disk.serialNum || 'Unknown',
interfaceType: disk.interfaceType || 'Unknown',
smartStatus: disk.smartStatus || 'Unknown',
temperature: disk.temperature || null
}));
const diskInfo = {
fsSize: formattedFsSize,
blockDevices: formattedBlockDevices,
diskLayout: formattedDiskLayout,
io: {
rIO: diskIo.rIO || 0,
wIO: diskIo.wIO || 0,
tIO: diskIo.tIO || 0,
rIO_sec: diskIo.rIO_sec || 0,
wIO_sec: diskIo.wIO_sec || 0,
tIO_sec: diskIo.tIO_sec || 0
},
timestamp: new Date().toISOString()
};
return diskInfo;
} catch (error) {
// Enhanced fallback with better error handling
try {
const platform = os.platform();
if (platform === 'darwin' || platform === 'linux') {
const df = execSync('df -h /', { timeout: 5000 }).toString();
const lines = df.trim().split('\n');
if (lines.length >= 2) {
const parts = lines[1].split(/\s+/);
return {
filesystem: parts[0],
size: parts[1],
used: parts[2],
available: parts[3],
usagePercent: parts[4],
mountedOn: parts[5],
timestamp: new Date().toISOString()
};
}
} else if (platform === 'win32') {
const wmic = execSync('wmic logicaldisk get size,freespace,caption', { timeout: 5000 }).toString();
const lines = wmic.trim().split('\n');
const disks = [];
for (let i = 1; i < lines.length; i++) {
const parts = lines[i].trim().split(/\s+/);
if (parts.length >= 3 && parts[0] && parts[1] && parts[2]) {
const caption = parts[0];
const freeSpace = Math.round(parseInt(parts[1]) / (1024 * 1024 * 1024));
const size = Math.round(parseInt(parts[2]) / (1024 * 1024 * 1024));
const used = size - freeSpace;
const usagePercent = Math.round((used / size) * 100);
disks.push({
drive: caption,
size: `${size} GB`,
used: `${used} GB`,
free: `${freeSpace} GB`,
usagePercent: `${usagePercent}%`
});
}
}
return {
disks,
timestamp: new Date().toISOString()
};
}
} catch (fallbackError) {
}
return {
error: 'Could not retrieve disk information - system access restricted',
timestamp: new Date().toISOString()
};
}
}
/**
* Get network information
* @returns {Object} Network interfaces and connection information
*/
async function getNetworkInfo() {
try {
const [networkInterfaces, networkStats, networkConnections, wifiNetworks, internetSpeed] = await Promise.all([
si.networkInterfaces().catch(() => []),
si.networkStats().catch(() => []),
si.networkConnections().catch(() => []),
si.wifiNetworks().catch(() => []),
si.inetChecksite('https://www.google.com').catch(() => ({ ms: null }))
]);
// Get public IP address
let publicIp = 'Not available';
try {
const ipResponse = await fetch('https://api.ipify.org?format=json', { timeout: 5000 });
const ipData = await ipResponse.json();
publicIp = ipData.ip || 'Not available';
} catch (ipError) {
}
// Format network interfaces
const formattedInterfaces = networkInterfaces.map(iface => ({
iface: iface.iface || 'Unknown',
ifaceName: iface.ifaceName || iface.iface || 'Unknown',
ip4: iface.ip4 || 'None',
ip6: iface.ip6 || 'None',
mac: iface.mac || 'Unknown',
internal: iface.internal || false,
virtual: iface.virtual || false,
operstate: iface.operstate || 'Unknown',
type: iface.type || 'Unknown',
duplex: iface.duplex || 'Unknown',
speed: iface.speed ? `${iface.speed} Mbps` : 'Unknown',
dhcp: iface.dhcp || false,
dnsSuffix: iface.dnsSuffix || 'Unknown',
ieee8021xAuth: iface.ieee8021xAuth || 'Unknown',
ieee8021xState: iface.ieee8021xState || 'Unknown',
carrierChanges: iface.carrierChanges || 0
}));
// Format network stats
const formattedStats = networkStats.map(stat => ({
iface: stat.iface || 'Unknown',
operstate: stat.operstate || 'Unknown',
rx_bytes: formatBytes(stat.rx_bytes || 0),
rx_dropped: stat.rx_dropped || 0,
rx_errors: stat.rx_errors || 0,
tx_bytes: formatBytes(stat.tx_bytes || 0),
tx_dropped: stat.tx_dropped || 0,
tx_errors: stat.tx_errors || 0,
rx_sec: formatBytes(stat.rx_sec || 0),
tx_sec: formatBytes(stat.tx_sec || 0),
ms: stat.ms || 0
}));
// Format wifi networks
const formattedWifiNetworks = wifiNetworks.map(network => ({
ssid: network.ssid || 'Hidden',
bssid: network.bssid || 'Unknown',
mode: network.mode || 'Unknown',
channel: network.channel || 'Unknown',
frequency: network.frequency || 'Unknown',
signalLevel: network.signalLevel || 'Unknown',
quality: network.quality || 'Unknown',
security: Array.isArray(network.security) ? network.security : [network.security || 'Unknown'],
wpaFlags: network.wpaFlags || 'Unknown',
rsnFlags: network.rsnFlags || 'Unknown'
}));
// Format connections summary
const connectionsCount = networkConnections.length || 0;
const establishedCount = networkConnections.filter(conn => conn.state === 'ESTABLISHED').length || 0;
const listeningCount = networkConnections.filter(conn => conn.state === 'LISTEN').length || 0;
const networkInfo = {
interfaces: formattedInterfaces,
stats: formattedStats,
connections: {
total: connectionsCount,
established: establishedCount,
listening: listeningCount,
sample: networkConnections.slice(0, 5).map(conn => ({
protocol: conn.protocol || 'Unknown',
localAddress: conn.localAddress || 'Unknown',
localPort: conn.localPort || 'Unknown',
peerAddress: conn.peerAddress || 'Unknown',
peerPort: conn.peerPort || 'Unknown',
state: conn.state || 'Unknown'
}))
},
wifiNetworks: formattedWifiNetworks,
internetLatency: internetSpeed.ms !== null ? `${internetSpeed.ms} ms` : 'Unknown',
publicIp,
timestamp: new Date().toISOString()
};
return networkInfo;
} catch (error) {
// Enhanced fallback to basic network information
try {
const interfaces = os.networkInterfaces();
const result = [];
for (const [name, netInterface] of Object.entries(interfaces)) {
for (const info of netInterface) {
if (info.family === 'IPv4' || info.family === 4) {
result.push({
interface: name,
address: info.address,
netmask: info.netmask,
mac: info.mac,
internal: info.internal
});
}
}
}
return {
interfaces: result,
timestamp: new Date().toISOString(),
error: 'Limited network information available'
};
} catch (fallbackError) {
return {
error: 'Could not retrieve network information',
timestamp: new Date().toISOString()
};
}
}
}
/**
* Format bytes to human-readable format
* @param {number} bytes - Bytes to format
* @returns {string} Formatted string
*/
function formatBytes(bytes) {
if (bytes === 0 || bytes === null || bytes === undefined) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
/**
* Get process information
* @returns {Object} Process information
*/
async function getProcessInfo() {
try {
const [processes, currentProcessLoad, services] = await Promise.all([
si.processes().catch(() => ({ all: 0, running: 0, blocked: 0, sleeping: 0, list: [] })),
si.processLoad(process.pid).catch(() => ({})),
si.services('*').catch(() => [])
]);
// Get current process memory usage
const memUsage = process.memoryUsage();
// Format current process info
const formattedCurrentProcess = {
pid: process.pid,
ppid: process.ppid || 'Unknown',
title: process.title || 'Node.js Process',
name: currentProcessLoad.name || process.title || 'node',
cpu: currentProcessLoad.cpu !== undefined ? `${currentProcessLoad.cpu.toFixed(1)}%` : 'Unknown',
mem: currentProcessLoad.mem !== undefined ? `${currentProcessLoad.mem.toFixed(1)}%` : 'Unknown',
arch: process.arch,
platform: process.platform,
version: process.version,
memoryUsage: {
rss: formatBytes(memUsage.rss),
heapTotal: formatBytes(memUsage.heapTotal),
heapUsed: formatBytes(memUsage.heapUsed),
external: formatBytes(memUsage.external),
arrayBuffers: formatBytes(memUsage.arrayBuffers || 0)
},
uptime: process.uptime(),
cwd: process.cwd(),
execPath: process.execPath,
argv: process.argv,
execArgv: process.execArgv
};
// Format top processes (limited for performance and privacy)
const topProcesses = processes.list ?
processes.list
.filter(proc => proc.cpu !== undefined && proc.cpu !== null)
.sort((a, b) => (b.cpu || 0) - (a.cpu || 0))
.slice(0, 15)
.map(proc => ({
pid: proc.pid || 'Unknown',
name: proc.name || 'Unknown',
cpu: proc.cpu !== undefined ? `${proc.cpu.toFixed(1)}%` : 'Unknown',
mem: proc.mem !== undefined ? `${proc.mem.toFixed(1)}%` : 'Unknown',
priority: proc.priority || 'Unknown',
command: proc.command || 'Unknown',
state: proc.state || 'Unknown'
})) : [];
// Format system services (limited for performance and privacy)
const formattedServices = services
.slice(0, 15)
.map(service => ({
name: service.name || 'Unknown',
running: service.running || false,
startmode: service.startmode || 'Unknown',
pids: Array.isArray(service.pids) ? service.pids : [],
state: service.state || 'Unknown'
}));
const processInfo = {
currentProcess: formattedCurrentProcess,
summary: {
all: processes.all || 0,
running: processes.running || 0,
blocked: processes.blocked || 0,
sleeping: processes.sleeping || 0,
unknown: processes.unknown || 0
},
topProcesses,
services: formattedServices,
timestamp: new Date().toISOString()
};
return processInfo;
} catch (error) {
// Fallback to basic process information
const memUsage = process.memoryUsage();
return {
currentProcess: {
pid: process.pid,
ppid: process.ppid || 'Unknown',
title: process.title || 'Node.js Process',
arch: process.arch,
platform: process.platform,
version: process.version,
versions: process.versions,
memoryUsage: {
rss: formatBytes(memUsage.rss),
heapTotal: formatBytes(memUsage.heapTotal),
heapUsed: formatBytes(memUsage.heapUsed),
external: formatBytes(memUsage.external)
},
uptime: process.uptime(),
cwd: process.cwd(),
execPath: process.execPath
},
timestamp: new Date().toISOString(),
error: 'Limited process information available'
};
}
}
/**
* Get environment variables and user information (filtered for security)
* @returns {Object} Environment variables and user information
*/
async function getEnvironmentInfo() {
try {
const [users, shellInfo] = await Promise.all([
si.users().catch(() => []),
si.shell().catch(() => ({ available: false, history: [] }))
]);
// Get safe environment variables
const env = process.env;
const safeEnv = {};
// Filter out sensitive information - only include safe environment variables
const safeKeys = [
'PATH', 'LANG', 'TERM', 'SHELL', 'HOME', 'USER', 'LOGNAME',
'TMPDIR', 'TZ', 'EDITOR', 'PAGER', 'LSCOLORS', 'TERM_PROGRAM',
'TERM_PROGRAM_VERSION', 'COLORTERM', 'DISPLAY', 'LC_ALL', 'LC_CTYPE',
'SHLVL', 'PWD', 'XDG_DATA_DIRS', 'XDG_RUNTIME_DIR', 'DESKTOP_SESSION',
'GDMSESSION', 'XDG_CURRENT_DESKTOP', 'XDG_SESSION_TYPE', 'WAYLAND_DISPLAY',
'NODE_VERSION', 'npm_config_user_config', 'npm_config_cache'
];
for (const key of safeKeys) {
if (env[key]) {
safeEnv[key] = env[key];
}
}
// Add current user information
const userInfo = os.userInfo();
safeEnv['CURRENT_USER'] = userInfo.username || 'Unknown';
safeEnv['USER_HOME'] = userInfo.homedir || 'Unknown';
safeEnv['USER_SHELL'] = userInfo.shell || 'Unknown';
safeEnv['USER_UID'] = userInfo.uid || 'Unknown';
safeEnv['USER_GID'] = userInfo.gid || 'Unknown';
// Format user information (anonymized for privacy)
const formattedUsers = users.map(user => ({
user: user.user || 'Unknown',
tty: user.tty || 'Unknown',
date: user.date || 'Unknown',
time: user.time || 'Unknown',
ip: user.ip || 'Unknown',
command: user.command || 'Unknown'
}));
// Format shell history (very limited for privacy and security)
let formattedShellHistory = [];
if (shellInfo && shellInfo.history && Array.isArray(shellInfo.history)) {
formattedShellHistory = shellInfo.history
.slice(-5) // Only last 5 commands
.map(cmd => ({
date: cmd.date || '',
time: cmd.time || '',
command: cmd.command ? cmd.command.substring(0, 50) + '...' : '' // Truncate for privacy
}));
}
const environmentInfo = {
variables: safeEnv,
user: {
username: userInfo.username || 'Unknown',
uid: userInfo.uid || 'Unknown',
gid: userInfo.gid || 'Unknown',
shell: userInfo.shell || 'Unknown',
homedir: userInfo.homedir || 'Unknown'
},
users: formattedUsers.slice(0, 10), // Limit for privacy
shell: {
available: shellInfo.available || false,
history: formattedShellHistory
},
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'Unknown',
locale: Intl.DateTimeFormat().resolvedOptions().locale || 'Unknown',
timestamp: new Date().toISOString()
};
return environmentInfo;
} catch (error) {
// Fallback to basic environment information
const env = process.env;
const safeEnv = {};
const userInfo = os.userInfo();
// Filter out sensitive information
const safeKeys = [
'PATH', 'LANG', 'TERM', 'SHELL', 'HOME', 'USER', 'LOGNAME',
'TMPDIR', 'TZ', 'EDITOR', 'PAGER', 'LSCOLORS', 'TERM_PROGRAM'
];
for (const key of safeKeys) {
if (env[key]) {
safeEnv[key] = env[key];
}
}
return {
variables: safeEnv,
user: {
username: userInfo.username || 'Unknown',
uid: userInfo.uid || 'Unknown',
gid: userInfo.gid || 'Unknown',
shell: userInfo.shell || 'Unknown',
homedir: userInfo.homedir || 'Unknown'
},
timestamp: new Date().toISOString(),
error: 'Limited environment information available'
};
}
}
/**
* Get system information based on query with enhanced AI integration
* @param {string} query - The user's query or category list
* @returns {Object} Relevant system information
*/
async function getSystemInfo(query = '') {
const startTime = Date.now();
const lowerQuery = (query || '').toLowerCase().trim();
let result = {};
const categoriesToFetch = [];
// Enhanced query patterns for natural language processing
const queryPatterns = {
cpu: [
'cpu', 'processor', 'core', 'thread', 'clock', 'speed', 'ghz', 'mhz',
'intel', 'amd', 'arm', 'load', 'usage', 'temperature', 'heat', 'cooling',
'performance', 'benchmark', 'processing', 'compute', 'cores', 'threads',
'frequency', 'cache', 'instruction', 'architecture', 'microprocessor'
],
memory: [
'memory', 'ram', 'dram', 'dimm', 'stick', 'module', 'bank', 'slot',
'free', 'available', 'used', 'total', 'swap', 'virtual memory', 'page',
'allocation', 'heap', 'stack', 'buffer', 'cache', 'physical memory',
'volatile memory', 'system memory', 'memory usage', 'memory allocation'
],
disk: [
'disk', 'drive', 'storage', 'hdd', 'ssd', 'nvme', 'partition', 'volume',
'filesystem', 'mount', 'space', 'capacity', 'free space', 'used space',
'read', 'write', 'io', 'block', 'sector', 'format', 'raid', 'hard drive',
'solid state', 'storage device', 'file system', 'directory', 'folder'
],
network: [
'network', 'internet', 'wifi', 'ethernet', 'connection', 'ip', 'address',
'mac', 'interface', 'adapter', 'wireless', 'wired', 'lan', 'wan', 'dns',
'gateway', 'router', 'subnet', 'mask', 'ping', 'latency', 'bandwidth',
'speed', 'download', 'upload', 'packet', 'traffic', 'port', 'socket',
'connectivity', 'protocol', 'tcp', 'udp', 'http', 'https'
],
process: [
'process', 'running', 'task', 'application', 'app', 'program', 'service',
'daemon', 'thread', 'job', 'pid', 'kill', 'terminate', 'start', 'stop',
'restart', 'crash', 'hang', 'freeze', 'responsive', 'background', 'foreground',
'processes', 'services', 'applications', 'system process', 'user process'
],
environment: [
'environment', 'env', 'variable', 'path', 'user', 'shell', 'terminal',
'console', 'profile', 'config', 'configuration', 'setting', 'preference',
'login', 'session', 'account', 'permission', 'access', 'privilege',
'variables', 'system config', 'user config', 'bash', 'zsh', 'cmd'
],
basic: [
'os', 'system', 'platform', 'version', 'release', 'build', 'kernel',
'distribution', 'distro', 'windows', 'mac', 'linux', 'unix', 'android',
'ios', 'architecture', 'arch', 'bit', '32-bit', '64-bit', 'x86', 'x64',
'arm', 'machine', 'hardware', 'device', 'model', 'manufacturer', 'vendor',
'computer', 'info', 'information', 'details', 'specs', 'specification',
'overview', 'summary', 'general', 'basic', 'hostname', 'uptime'
]
};
// Function to check if query matches any pattern in a category
const matchesCategory = (category) => {
return queryPatterns[category].some(pattern => lowerQuery.includes(pattern));
};
// Determine what information to return based on the query
if (lowerQuery.includes('all') || lowerQuery === '' || lowerQuery.includes('everything') || lowerQuery.includes('complete')) {
// Get all information in parallel for better performance
const [basic, cpu, memory, disk, network, process, environment] = await Promise.allSettled([
getBasicSystemInfo(),
getCpuInfo(),
getMemoryInfo(),
getDiskInfo(),
getNetworkInfo(),
getProcessInfo(),
getEnvironmentInfo()
]);
// Handle results, including any that may have failed
result = {
basic: basic.status === 'fulfilled' ? basic.value : { error: basic.reason?.message || 'Failed to fetch basic info' },
cpu: cpu.status === 'fulfilled' ? cpu.value : { error: cpu.reason?.message || 'Failed to fetch CPU info' },
memory: memory.status === 'fulfilled' ? memory.value : { error: memory.reason?.message || 'Failed to fetch memory info' },
disk: disk.status === 'fulfilled' ? disk.value : { error: disk.reason?.message || 'Failed to fetch disk info' },
network: network.status === 'fulfilled' ? network.value : { error: network.reason?.message || 'Failed to fetch network info' },
process: process.status === 'fulfilled' ? process.value : { error: process.reason?.message || 'Failed to fetch process info' },
environment: environment.status === 'fulfilled' ? environment.value : { error: environment.reason?.message || 'Failed to fetch environment info' }
};
} else {
// Process categories from the query string (space-separated)
const queryCategories = lowerQuery.split(/\s+/).filter(cat =>
['basic', 'cpu', 'memory', 'disk', 'network', 'process', 'environment'].includes(cat)
);
// If specific categories were mentioned in the query, use those
if (queryCategories.length > 0) {
categoriesToFetch.push(...queryCategories);
} else {
// Use pattern matching to determine categories
if (matchesCategory('cpu')) categoriesToFetch.push('cpu');
if (matchesCategory('memory')) categoriesToFetch.push('memory');
if (matchesCategory('disk')) categoriesToFetch.push('disk');
if (matchesCategory('network')) categoriesToFetch.push('network');
if (matchesCategory('process')) categoriesToFetch.push('process');
if (matchesCategory('environment')) categoriesToFetch.push('environment');
if (matchesCategory('basic')) categoriesToFetch.push('basic');
}
// If no specific category was matched, get basic info
if (categoriesToFetch.length === 0) {
categoriesToFetch.push('basic');
}
// Remove duplicates
const uniqueCategories = [...new Set(categoriesToFetch)];
// Fetch all requested categories in parallel for better performance
const promises = [];
const promiseMap = {};
uniqueCategories.forEach(category => {
switch (category) {
case 'basic':
promises.push(getBasicSystemInfo());
promiseMap[promises.length - 1] = 'basic';
break;
case 'cpu':
promises.push(getCpuInfo());
promiseMap[promises.length - 1] = 'cpu';
break;
case 'memory':
promises.push(getMemoryInfo());
promiseMap[promises.length - 1] = 'memory';
break;
case 'disk':
promises.push(getDiskInfo());
promiseMap[promises.length - 1] = 'disk';
break;
case 'network':
promises.push(getNetworkInfo());
promiseMap[promises.length - 1] = 'network';
break;
case 'process':
promises.push(getProcessInfo());
promiseMap[promises.length - 1] = 'process';
break;
case 'environment':
promises.push(getEnvironmentInfo());
promiseMap[promises.length - 1] = 'environment';
break;
}
});
const results = await Promise.allSettled(promises);
// Assign results to the appropriate categories
results.forEach((promiseResult, index) => {
const category = promiseMap[index];
if (promiseResult.status === 'fulfilled') {
result[category] = promiseResult.value;
} else {
result[category] = {
error: promiseResult.reason?.message || `Failed to fetch ${category} information`,
timestamp: new Date().toISOString()
};
}
});
}
// Add metadata to the result
result._metadata = {
query: query,
processedAt: new Date().toISOString(),
user: 'm0v0dga_walmart',
processingTimeMs: Date.now() - startTime,
categoriesFetched: Object.keys(result).filter(key => key !== '_metadata'),
nodeVersion: process.version,
platform: os.platform(),
arch: os.arch()
};
const endTime = Date.now();
return result;
}
module.exports = {
getSystemInfo,
getBasicSystemInfo,
getCpuInfo,
getMemoryInfo,
getDiskInfo,
getNetworkInfo,
getProcessInfo,
getEnvironmentInfo,
formatBytes
};