diff options
| author | Adam Malczewski <[email protected]> | 2026-06-24 02:04:46 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-24 02:04:46 +0900 |
| commit | 41ca91a959ae245e76e50f1b55c8b21592bc6c50 (patch) | |
| tree | 289be7c0df654e75b6bc7552dd38bf0b9bda852d /packages/system-prompt/src/resolver.ts | |
| parent | 3a688edee373cbbc291a149e50e1d2802e2e29a4 (diff) | |
| download | dispatch-41ca91a959ae245e76e50f1b55c8b21592bc6c50.tar.gz dispatch-41ca91a959ae245e76e50f1b55c8b21592bc6c50.zip | |
feat(system-prompt): rich system:os with WSL detection + Linux distro
system:os now returns a descriptive string instead of the raw platform:
- Linux: reads /etc/os-release for distro name (PRETTY_NAME or NAME+VERSION_ID)
- WSL detection: checks /proc/sys/fs/binfmt_misc/WSLInterop or 'microsoft'
in /proc/version — appends (WSL) to the distro string
- Non-Linux: returns process.platform as-is (darwin, win32, etc.)
Examples: 'Ubuntu 22.04 LTS', 'Ubuntu 22.04 LTS (WSL)', 'Debian 12',
'Linux (WSL)', 'darwin'. All file reads use injected fs adapters (testable).
7 new resolver tests. 1403 vitest pass. FE CR-9.
Diffstat (limited to 'packages/system-prompt/src/resolver.ts')
| -rw-r--r-- | packages/system-prompt/src/resolver.ts | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/packages/system-prompt/src/resolver.ts b/packages/system-prompt/src/resolver.ts index 1ef9028..f271f47 100644 --- a/packages/system-prompt/src/resolver.ts +++ b/packages/system-prompt/src/resolver.ts @@ -91,6 +91,53 @@ async function readFile(filePath: string, cwd: string, fs: ResolverFs): Promise< } /** + * Resolve a rich OS description string. + * + * - **Linux:** reads `/etc/os-release` for the distro name (PRETTY_NAME or + * NAME+VERSION_ID). Detects WSL via `/proc/sys/fs/binfmt_misc/WSLInterop` or + * "microsoft" in `/proc/version`. Returns e.g. `"Ubuntu 22.04 (WSL)"` or + * `"Ubuntu 22.04"`. + * - **Other platforms:** returns `process.platform` (e.g. `"darwin"`, `"win32"`). + * + * All file reads use the injected `fs` adapter — failures are non-fatal (fall back + * to the base platform string). The `platform` override is honored for tests. + */ +async function resolveOs(platform: string, fs: ResolverFs): Promise<string> { + if (platform !== "linux") return platform; + + let distro: string | null = null; + const osRelease = await readFile("/etc/os-release", "/", fs); + if (osRelease !== null) { + const pretty = osRelease.match(/^PRETTY_NAME="(.+)"/m); + if (pretty?.[1] !== undefined) { + distro = pretty[1]; + } else { + const name = osRelease.match(/^NAME="(.+)"/m); + const version = osRelease.match(/^VERSION_ID="(.+)"/m); + if (name?.[1] !== undefined) { + distro = version?.[1] !== undefined ? `${name[1]} ${version[1]}` : name[1]; + } + } + } + + let isWsl = false; + const wslInterop = await readFile("/proc/sys/fs/binfmt_misc/WSLInterop", "/", fs); + if (wslInterop !== null) { + isWsl = true; + } else { + const procVersion = await readFile("/proc/version", "/", fs); + if (procVersion !== null && /microsoft/i.test(procVersion)) { + isWsl = true; + } + } + + if (distro !== null) { + return isWsl ? `${distro} (WSL)` : distro; + } + return isWsl ? "Linux (WSL)" : "linux"; +} + +/** * Resolve all variables for a construction. * * Always resolves the fixed catalog (`system:*`, `prompt:*`, `git:*`), plus any @@ -110,7 +157,8 @@ export async function resolveVariables( // ── system:* ──────────────────────────────────────────────────────────── vars.set("system:time", now.toISOString()); vars.set("system:date", now.toISOString().slice(0, 10)); - vars.set("system:os", adapters.platform?.() ?? process.platform); + const platform = adapters.platform?.() ?? process.platform; + vars.set("system:os", await resolveOs(platform, adapters.fs)); vars.set("system:hostname", adapters.hostname?.() ?? osHostname()); // ── prompt:* ──────────────────────────────────────────────────────────── |
