feat(system-info): improve human-readable snapshot formatting
This commit is contained in:
@@ -5624,6 +5624,18 @@
|
|||||||
"docs/plans/state.json"
|
"docs/plans/state.json"
|
||||||
],
|
],
|
||||||
"test_status": "pnpm test:run src/tools/builtin/system-info.test.ts + pnpm typecheck passing"
|
"test_status": "pnpm test:run src/tools/builtin/system-info.test.ts + pnpm typecheck passing"
|
||||||
|
},
|
||||||
|
"system-info-human-readable-formatting": {
|
||||||
|
"status": "completed",
|
||||||
|
"date": "2026-02-19",
|
||||||
|
"updated": "2026-02-19",
|
||||||
|
"summary": "Refined `system.info` output into a human-readable structured snapshot with Host/Resources/Time/Process sections, clearer labels, memory+disk usage percentages, and a compact health summary.",
|
||||||
|
"files_modified": [
|
||||||
|
"src/tools/builtin/system-info.ts",
|
||||||
|
"src/tools/builtin/system-info.test.ts",
|
||||||
|
"docs/plans/state.json"
|
||||||
|
],
|
||||||
|
"test_status": "pnpm test:run src/tools/builtin/system-info.test.ts + pnpm typecheck passing"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"overall_progress": {
|
"overall_progress": {
|
||||||
|
|||||||
@@ -34,15 +34,16 @@ describe('system.info tool', () => {
|
|||||||
const output = getOutput(result.output);
|
const output = getOutput(result.output);
|
||||||
|
|
||||||
const expectedFields = [
|
const expectedFields = [
|
||||||
'Date:',
|
'System Snapshot',
|
||||||
'Time:',
|
'Host',
|
||||||
|
'Resources',
|
||||||
|
'Storage',
|
||||||
|
'Time',
|
||||||
'Hostname:',
|
'Hostname:',
|
||||||
'Platform:',
|
'Platform:',
|
||||||
'Architecture:',
|
|
||||||
'Node.js:',
|
'Node.js:',
|
||||||
'Uptime:',
|
'Uptime:',
|
||||||
'Memory Total:',
|
'Memory:',
|
||||||
'Disk',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const field of expectedFields) {
|
for (const field of expectedFields) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ function formatBytes(bytes: number): string {
|
|||||||
return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
|
return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDiskUsageSummary(): string[] {
|
function getDiskUsageSummary(): { lines: string[]; usedPct?: number } {
|
||||||
try {
|
try {
|
||||||
const rootPath = process.platform === 'win32' ? process.cwd().slice(0, 3) : '/';
|
const rootPath = process.platform === 'win32' ? process.cwd().slice(0, 3) : '/';
|
||||||
const stat = statfsSync(rootPath);
|
const stat = statfsSync(rootPath);
|
||||||
@@ -22,7 +22,15 @@ function getDiskUsageSummary(): string[] {
|
|||||||
const freeBlocks = typeof stat.bavail === 'number' ? stat.bavail : Number(stat.bavail);
|
const freeBlocks = typeof stat.bavail === 'number' ? stat.bavail : Number(stat.bavail);
|
||||||
|
|
||||||
if (!Number.isFinite(blockSize) || !Number.isFinite(totalBlocks) || !Number.isFinite(freeBlocks)) {
|
if (!Number.isFinite(blockSize) || !Number.isFinite(totalBlocks) || !Number.isFinite(freeBlocks)) {
|
||||||
return ['Disk: unavailable'];
|
return {
|
||||||
|
lines: [
|
||||||
|
'Storage',
|
||||||
|
'- Root Path: unavailable',
|
||||||
|
'- Total: unavailable',
|
||||||
|
'- Free: unavailable',
|
||||||
|
'- Used: unavailable',
|
||||||
|
],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalBytes = totalBlocks * blockSize;
|
const totalBytes = totalBlocks * blockSize;
|
||||||
@@ -30,14 +38,26 @@ function getDiskUsageSummary(): string[] {
|
|||||||
const usedBytes = Math.max(0, totalBytes - freeBytes);
|
const usedBytes = Math.max(0, totalBytes - freeBytes);
|
||||||
const usedPct = totalBytes > 0 ? (usedBytes / totalBytes) * 100 : 0;
|
const usedPct = totalBytes > 0 ? (usedBytes / totalBytes) * 100 : 0;
|
||||||
|
|
||||||
return [
|
return {
|
||||||
`Disk Path: ${rootPath}`,
|
lines: [
|
||||||
`Disk Total: ${formatBytes(totalBytes)}`,
|
'Storage',
|
||||||
`Disk Free: ${formatBytes(freeBytes)}`,
|
`- Root Path: ${rootPath}`,
|
||||||
`Disk Used: ${formatBytes(usedBytes)} (${usedPct.toFixed(1)}%)`,
|
`- Total: ${formatBytes(totalBytes)}`,
|
||||||
];
|
`- Free: ${formatBytes(freeBytes)}`,
|
||||||
|
`- Used: ${formatBytes(usedBytes)} (${usedPct.toFixed(1)}%)`,
|
||||||
|
],
|
||||||
|
usedPct,
|
||||||
|
};
|
||||||
} catch {
|
} catch {
|
||||||
return ['Disk: unavailable'];
|
return {
|
||||||
|
lines: [
|
||||||
|
'Storage',
|
||||||
|
'- Root Path: unavailable',
|
||||||
|
'- Total: unavailable',
|
||||||
|
'- Free: unavailable',
|
||||||
|
'- Used: unavailable',
|
||||||
|
],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,24 +85,42 @@ export const systemInfoTool: Tool = {
|
|||||||
hour12: false,
|
hour12: false,
|
||||||
});
|
});
|
||||||
const isoStr = now.toISOString();
|
const isoStr = now.toISOString();
|
||||||
|
const localStr = now.toLocaleString();
|
||||||
|
|
||||||
const totalMem = os.totalmem();
|
const totalMem = os.totalmem();
|
||||||
const freeMem = os.freemem();
|
const freeMem = os.freemem();
|
||||||
|
const usedMem = Math.max(0, totalMem - freeMem);
|
||||||
|
const usedMemPct = totalMem > 0 ? (usedMem / totalMem) * 100 : 0;
|
||||||
|
const disk = getDiskUsageSummary();
|
||||||
|
const memoryHealth = usedMemPct < 75 ? 'healthy' : usedMemPct < 90 ? 'moderate' : 'high';
|
||||||
|
const diskHealth = typeof disk.usedPct === 'number'
|
||||||
|
? (disk.usedPct < 75 ? 'healthy' : disk.usedPct < 90 ? 'moderate' : 'high')
|
||||||
|
: 'unknown';
|
||||||
|
|
||||||
const lines = [
|
const lines = [
|
||||||
`Date: ${dateStr}`,
|
'System Snapshot',
|
||||||
`Time: ${timeStr}`,
|
'',
|
||||||
`ISO 8601: ${isoStr}`,
|
'Host',
|
||||||
`Hostname: ${os.hostname()}`,
|
`- Hostname: ${os.hostname()}`,
|
||||||
`Platform: ${os.platform()}`,
|
`- OS: ${os.type()} ${os.release()}`,
|
||||||
`Architecture: ${os.arch()}`,
|
`- Platform: ${os.platform()} (${os.arch()})`,
|
||||||
`OS Release: ${os.release()}`,
|
`- Node.js: ${process.version}`,
|
||||||
`Uptime: ${formatUptime(os.uptime())}`,
|
`- Uptime: ${formatUptime(os.uptime())}`,
|
||||||
`Node.js: ${process.version}`,
|
'',
|
||||||
`Memory Total: ${formatBytes(totalMem)}`,
|
'Resources',
|
||||||
`Memory Free: ${formatBytes(freeMem)}`,
|
`- Memory: ${formatBytes(usedMem)} used / ${formatBytes(totalMem)} total (${usedMemPct.toFixed(1)}% used, ${memoryHealth})`,
|
||||||
...getDiskUsageSummary(),
|
`- Memory Free: ${formatBytes(freeMem)}`,
|
||||||
`Working Dir: ${process.cwd()}`,
|
...disk.lines.map((line) => (line === 'Storage' ? line : `${line}`)),
|
||||||
|
'',
|
||||||
|
'Time',
|
||||||
|
`- Local: ${localStr}`,
|
||||||
|
`- Date: ${dateStr}`,
|
||||||
|
`- Time: ${timeStr}`,
|
||||||
|
`- ISO 8601: ${isoStr}`,
|
||||||
|
'',
|
||||||
|
'Process',
|
||||||
|
`- Working Dir: ${process.cwd()}`,
|
||||||
|
`- Health Summary: memory=${memoryHealth}, disk=${diskHealth}`,
|
||||||
];
|
];
|
||||||
|
|
||||||
return { success: true, output: lines.join('\n') };
|
return { success: true, output: lines.join('\n') };
|
||||||
|
|||||||
Reference in New Issue
Block a user