Skip to main content
Glama
hardware.ts5.64 kB
import si from "systeminformation"; import os from "os"; /** * 过滤主要磁盘分区(跨平台) */ function filterMainDisks(disks: any[]) { const platform = os.platform(); return disks.filter(d => { const mount = d.mount.toLowerCase(); const fs = d.fs.toLowerCase(); // 排除太小的分区(小于 1GB,通常是系统分区) if (d.size < 1024 * 1024 * 1024) return false; if (platform === 'darwin') { // macOS: 只保留用户数据分区和外部磁盘 return mount === '/system/volumes/data' || (mount.startsWith('/volumes/') && !mount.includes('preboot') && !mount.includes('recovery') && !mount.includes('vm')); } else if (platform === 'win32') { // Windows: 保留所有盘符(C:, D:, E: 等) return mount.match(/^[a-z]:\\/i) !== null; } else { // Linux: 排除系统内部挂载点 const systemMounts = ['/boot', '/dev', '/proc', '/sys', '/run', '/snap']; const isSystemMount = systemMounts.some(sm => mount.startsWith(sm)); // 保留根目录、home、用户挂载点 return !isSystemMount && ( mount === '/' || mount === '/home' || mount.startsWith('/mnt/') || mount.startsWith('/media/') ); } }); } /** * 过滤活跃的网络接口(跨平台) */ function filterActiveNetworks(interfaces: any[]) { const platform = os.platform(); return interfaces .filter(iface => { // 排除内部回环接口 if (iface.internal) return false; const name = iface.iface.toLowerCase(); // 平台特定的虚拟接口过滤 if (platform === 'darwin') { // macOS: 排除 AirDrop、VPN、虚拟机等接口 if (name.startsWith('awdl') || name.startsWith('llw') || name.startsWith('utun') || name.startsWith('bridge') || name.startsWith('vmenet') || name.startsWith('anpi')) { return false; } } else if (platform === 'win32') { // Windows: 排除虚拟适配器 if (name.includes('loopback') || name.includes('tunnel') || name.includes('isatap') || name.includes('teredo')) { return false; } } else { // Linux: 排除虚拟接口 if (name.startsWith('veth') || name.startsWith('docker') || name.startsWith('br-') || name.startsWith('virbr') || name.startsWith('tun') || name.startsWith('tap')) { return false; } } // 必须有真实的 IPv4 地址,或者有非 link-local 的 IPv6 地址 const hasRealIp4 = iface.ip4 && iface.ip4.length > 0; const hasRealIp6 = iface.ip6 && iface.ip6.length > 0 && !iface.ip6.startsWith('fe80::') && !iface.ip6.startsWith('::1'); return hasRealIp4 || hasRealIp6; }) .map(iface => ({ iface: iface.iface, ip4: iface.ip4, ip6: iface.ip6 && !iface.ip6.startsWith('fe80::') ? iface.ip6 : undefined, mac: iface.mac, type: iface.type, speed: iface.speed, })); } export async function getHardwareInfo(detailed: boolean = false) { try { const cpu = await si.cpu(); const mem = await si.mem(); const disk = await si.fsSize(); const networkInterfaces = await si.networkInterfaces(); // 使用跨平台过滤函数 const mainDisks = filterMainDisks(disk); const activeNetworks = filterActiveNetworks(networkInterfaces); const basicInfo = { cpu: { manufacturer: cpu.manufacturer, brand: cpu.brand, speed: cpu.speed, cores: cpu.cores, physicalCores: cpu.physicalCores, processors: cpu.processors, }, memory: { total: formatBytes(mem.total), totalBytes: mem.total, free: formatBytes(mem.free), freeBytes: mem.free, used: formatBytes(mem.used), usedBytes: mem.used, usagePercent: ((mem.used / mem.total) * 100).toFixed(2), }, disk: mainDisks.map(d => ({ fs: d.fs, type: d.type, size: formatBytes(d.size), sizeBytes: d.size, used: formatBytes(d.used), usedBytes: d.used, available: formatBytes(d.available), availableBytes: d.available, usagePercent: d.use.toFixed(2), mount: d.mount, })), network: activeNetworks, }; if (detailed) { const cpuTemp = await si.cpuTemperature(); const battery = await si.battery(); const graphics = await si.graphics(); return { ...basicInfo, cpuTemperature: cpuTemp.main ? `${cpuTemp.main}°C` : "N/A", battery: battery.hasBattery ? { hasBattery: battery.hasBattery, percent: battery.percent, isCharging: battery.isCharging, timeRemaining: battery.timeRemaining, } : null, graphics: graphics.controllers.map(g => ({ model: g.model, vendor: g.vendor, vram: g.vram, vramDynamic: g.vramDynamic, })), }; } return basicInfo; } catch (error) { if (error instanceof Error) { throw new Error(`获取硬件信息失败: ${error.message}`); } throw error; } } function formatBytes(bytes: number): string { if (bytes === 0) return "0 B"; const k = 1024; const sizes = ["B", "KB", "MB", "GB", "TB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pepedd864/agent-sense'

If you have feedback or need assistance with the MCP directory API, please join our Discord server