From 7a966ec353402af6876b4e821aadcdd1f8077fc7 Mon Sep 17 00:00:00 2001 From: samzong Date: Tue, 4 Aug 2026 13:14:33 -0400 Subject: [PATCH] fix(sdk): resolve home via platform APIs Use os.homedir() in TypeScript and HOME/USERPROFILE fallback in Rust so host path expansion works on Windows without relying on HOME alone. ## Considered and deferred - testdata/cases [BOT-SCOPE]: Default-home / Windows USERPROFILE path is not covered by golden cases; fixtures inject home explicitly and adding cases is outside this commit's file set. - rust/src/lib.rs:1471 [BOT-NIT]: HOME/USERPROFILE env fallback is shallower than Go os.UserHomeDir (go/kitup.go:1262) and Python Path.home (python/src/kitup/hosts.py:64); Rust std has no home API and a new crate is out of scope. - ts/src/index.ts:419 [BOT-NIT]: os.homedir() can throw when home is unresolvable vs previous empty-string fallback; empty home previously produced wrong ~/ expansion, so throw is acceptable platform behavior. Signed-off-by: samzong --- rust/src/lib.rs | 6 +++++- ts/src/index.ts | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 162cccd..11c560e 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1467,7 +1467,11 @@ fn expand_host_path(path: &str, home: &Path, cwd: &Path) -> PathBuf { fn defaults(options: &BaseOptions) -> io::Result<(PathBuf, PathBuf)> { let home = match &options.home { Some(home) => home.clone(), - None => PathBuf::from(std::env::var("HOME").unwrap_or_default()), + None => PathBuf::from( + std::env::var("HOME") + .or_else(|_| std::env::var("USERPROFILE")) + .unwrap_or_default(), + ), }; let cwd = match &options.cwd { Some(cwd) => cwd.clone(), diff --git a/ts/src/index.ts b/ts/src/index.ts index 71b69da..dc0ff21 100644 --- a/ts/src/index.ts +++ b/ts/src/index.ts @@ -10,6 +10,7 @@ import { stat, writeFile, } from "node:fs/promises"; +import { homedir } from "node:os"; import { dirname, join, relative, resolve, sep } from "node:path"; import { fileURLToPath } from "node:url"; import { defaultHostsSpecJson } from "./hosts.generated.js"; @@ -415,7 +416,7 @@ export async function detectHosts( options: BaseOptions & { scope?: Scope } = {}, ): Promise { const spec = await loadHostSpec(options.hostsFile); - const home = options.home ?? process.env.HOME ?? ""; + const home = options.home ?? homedir(); const cwd = options.cwd ?? process.cwd(); const detected: Host[] = []; @@ -678,7 +679,7 @@ export async function resolveInstallTargets( detectedHostIds: string[]; }> { const spec = await loadHostSpec(options.hostsFile); - const home = options.home ?? process.env.HOME ?? ""; + const home = options.home ?? homedir(); const cwd = options.cwd ?? process.cwd(); const agents = options.agents ?? defaultAgents; const resolved =