feat(coding-agent/core): added system info caching for faster startup

- Added caching for system environment detection to improve startup performance.
- Changed GPU detection on Linux to prioritize discrete GPUs (NVIDIA, AMD) over integrated graphics and skip server management adapters.
- Implemented SystemInfoCache interface and file-based persistence in ~/.omp/system_info.json.
This commit is contained in:
Can Bölük
2026-01-08 17:43:41 +01:00
parent df6fca373b
commit d934594aed
2 changed files with 100 additions and 11 deletions
+3
View File
@@ -1,8 +1,10 @@
# Changelog
## [Unreleased]
### Added
- Added caching for system environment detection to improve startup performance
- Added disk usage information to automatic environment detection in system prompt
- Added `compat` option for SSH hosts to wrap commands in a POSIX shell on Windows systems
- Added automatic working directory handling for PowerShell and cmd.exe on Windows SSH hosts
@@ -12,6 +14,7 @@
### Changed
- Changed GPU detection on Linux to prioritize discrete GPUs (NVIDIA, AMD) over integrated graphics and skip server management adapters
- Changed SSH host info cache to use versioned format for automatic refresh on schema changes
- Changed SSH compat shell detection to actively probe for bash/sh availability on Windows hosts
- Changed SSH tool description to show detected shell type and available commands per host
+97 -11
View File
@@ -2,7 +2,9 @@
* System prompt construction and project context loading
*/
import { existsSync, readFileSync } from "node:fs";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import chalk from "chalk";
import { contextFileCapability } from "../capability/context-file";
import type { Rule } from "../capability/rule";
@@ -293,12 +295,35 @@ function getGpuModel(): string | null {
case "linux": {
const output = execIfExists("lspci", []);
if (!output) return null;
const gpus: Array<{ name: string; priority: number }> = [];
for (const line of output.split("\n")) {
if (!/(VGA|3D|Display)/i.test(line)) continue;
const parts = line.split(":");
return parts.length > 1 ? parts.slice(1).join(":").trim() : line.trim();
const name = parts.length > 1 ? parts.slice(1).join(":").trim() : line.trim();
const nameLower = name.toLowerCase();
// Skip BMC/server management adapters
if (/aspeed|matrox g200|mgag200/i.test(name)) continue;
// Prioritize discrete GPUs
let priority = 0;
if (
nameLower.includes("nvidia") ||
nameLower.includes("geforce") ||
nameLower.includes("quadro") ||
nameLower.includes("rtx")
) {
priority = 3;
} else if (nameLower.includes("amd") || nameLower.includes("radeon") || nameLower.includes("rx ")) {
priority = 3;
} else if (nameLower.includes("intel")) {
priority = 1;
} else {
priority = 2;
}
gpus.push({ name, priority });
}
return null;
if (gpus.length === 0) return null;
gpus.sort((a, b) => b.priority - a.priority);
return gpus[0].name;
}
default:
return null;
@@ -382,6 +407,57 @@ function getWindowManager(): string {
return "unknown";
}
/** Cached system info structure */
interface SystemInfoCache {
os: string;
distro: string;
kernel: string;
arch: string;
cpu: string;
gpu: string;
disk: string;
}
function getSystemInfoCachePath(): string {
return join(homedir(), ".omp", "system_info.json");
}
function loadSystemInfoCache(): SystemInfoCache | null {
try {
const cachePath = getSystemInfoCachePath();
if (!existsSync(cachePath)) return null;
const content = readFileSync(cachePath, "utf-8");
return JSON.parse(content) as SystemInfoCache;
} catch {
return null;
}
}
function saveSystemInfoCache(info: SystemInfoCache): void {
try {
const cachePath = getSystemInfoCachePath();
const dir = join(homedir(), ".omp");
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
writeFileSync(cachePath, JSON.stringify(info, null, "\t"), "utf-8");
} catch {
// Silently ignore cache write failures
}
}
function collectSystemInfo(): SystemInfoCache {
return {
os: getOsName(),
distro: getOsDistro() ?? "unknown",
kernel: getKernelVersion(),
arch: getCpuArch(),
cpu: getCpuModel() ?? "unknown",
gpu: getGpuModel() ?? "unknown",
disk: getDiskInfo() ?? "unknown",
};
}
function formatBytes(bytes: number): string {
if (bytes < 1024) return `${bytes}B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
@@ -429,14 +505,22 @@ function getDiskInfo(): string | null {
}
function formatEnvironmentInfo(): string {
// Load cached system info or collect fresh
let sysInfo = loadSystemInfoCache();
if (!sysInfo) {
sysInfo = collectSystemInfo();
saveSystemInfoCache(sysInfo);
}
// Session-specific values (not cached)
const items: Array<[string, string]> = [
["OS", getOsName()],
["Distro", getOsDistro() ?? "unknown"],
["Kernel", getKernelVersion()],
["Arch", getCpuArch()],
["CPU", getCpuModel() ?? "unknown"],
["GPU", getGpuModel() ?? "unknown"],
["Disk", getDiskInfo() ?? "unknown"],
["OS", sysInfo.os],
["Distro", sysInfo.distro],
["Kernel", sysInfo.kernel],
["Arch", sysInfo.arch],
["CPU", sysInfo.cpu],
["GPU", sysInfo.gpu],
["Disk", sysInfo.disk],
["Shell", getShellName()],
["Terminal", getTerminalName()],
["DE", getDesktopEnvironment()],
@@ -524,7 +608,9 @@ function generateAntiBashRules(tools: ToolName[]): string | null {
const hasSSH = tools.includes("ssh");
if (hasSSH) {
lines.push("\n### SSH Command Execution");
lines.push("**Critical**: Each SSH host runs a specific shell. **You MUST match commands to the host's shell type**.");
lines.push(
"**Critical**: Each SSH host runs a specific shell. **You MUST match commands to the host's shell type**.",
);
lines.push("Check the host list in the ssh tool description. Shell types:");
lines.push("- linux/bash, linux/zsh, macos/bash, macos/zsh: ls, cat, grep, find, ps, df, uname");
lines.push("- windows/bash, windows/sh: ls, cat, grep, find (Windows with WSL/Cygwin — Unix commands)");