b4fbd6fe9f
Deploy Site / deploy-vercel (push) Has been skipped
Deploy Site / deploy-docs (push) Has been skipped
Build Skills Index / build-index (push) Has been skipped
CI / Deny unrelated histories (push) Has been skipped
CI / Detect affected areas (push) Successful in 27m35s
CI / OSV scan (push) Failing after 4s
CI / Build&Test Docker image (push) Successful in 9s
CI / Supply-chain scan (push) Has been skipped
CI / Lint Docker scripts (push) Failing after 5m13s
CI / Check contributors (push) Failing after 12m8s
CI / Docs Site (push) Failing after 12m8s
CI / TypeScript (push) Failing after 12m8s
CI / Python lints (push) Failing after 12m9s
CI / Python tests (push) Failing after 12m9s
CI / Check uv.lock (push) Failing after 23m22s
CI / CI timing report (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
CI / All required checks pass (push) Has been cancelled
97 lines
2.9 KiB
TypeScript
97 lines
2.9 KiB
TypeScript
// windows-user-env.ts
|
|
//
|
|
// Read a User-scoped environment variable straight from the Windows registry
|
|
// (HKCU\Environment).
|
|
//
|
|
// A GUI app launched from Explorer inherits the environment block captured at
|
|
// login, so a variable set via `setx` AFTER login is invisible in process.env
|
|
// even though a fresh shell — and the Hermes CLI — sees it immediately. The
|
|
// desktop's HERMES_HOME resolution relies on process.env, so that stale-snapshot
|
|
// gap silently sends the backend to the default %LOCALAPPDATA%\hermes. Reading
|
|
// the live registry value closes the gap. See #45471.
|
|
|
|
import { execFileSync } from 'node:child_process'
|
|
|
|
// Parse the output of `reg query HKCU\Environment /v <name>`, which looks like:
|
|
//
|
|
// HKEY_CURRENT_USER\Environment
|
|
// HERMES_HOME REG_SZ F:\Hermes\data
|
|
//
|
|
// Returns the raw value string (spaces inside the value preserved), or null when
|
|
// the requested value line isn't present.
|
|
function parseRegQueryValue(stdout, name) {
|
|
if (!stdout || !name) {
|
|
return null
|
|
}
|
|
const typePattern = /^(\S+)\s+(?:REG_SZ|REG_EXPAND_SZ|REG_MULTI_SZ|REG_DWORD|REG_QWORD|REG_BINARY|REG_NONE)\s+(.*)$/
|
|
|
|
for (const rawLine of String(stdout).split(/\r?\n/)) {
|
|
const line = rawLine.trim()
|
|
const match = line.match(typePattern)
|
|
|
|
if (match && match[1].toLowerCase() === name.toLowerCase()) {
|
|
return match[2]
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
// Expand %VAR% references against an env map. REG_EXPAND_SZ values store
|
|
// unexpanded references; plain REG_SZ paths have none, so this is a no-op for
|
|
// the common F:\... case. Unknown references are left verbatim.
|
|
function expandWindowsEnvRefs(value, env = process.env) {
|
|
if (!value) {
|
|
return value
|
|
}
|
|
|
|
return value.replace(/%([^%]+)%/g, (whole, name) => {
|
|
const key = Object.keys(env).find(k => k.toUpperCase() === String(name).toUpperCase())
|
|
|
|
return key != null && env[key] != null ? env[key] : whole
|
|
})
|
|
}
|
|
|
|
// Read a User-scoped env var from HKCU\Environment. Windows-only: returns null
|
|
// off-Windows (without spawning), on any spawn error, when `reg` exits non-zero
|
|
// (the value doesn't exist), or when the value is empty.
|
|
function readWindowsUserEnvVar(
|
|
name,
|
|
{
|
|
platform = process.platform,
|
|
env = process.env,
|
|
exec = execFileSync
|
|
}: {
|
|
platform?: NodeJS.Platform
|
|
env?: NodeJS.ProcessEnv
|
|
exec?: typeof execFileSync | ((file?: string, args?: any) => string)
|
|
} = {}
|
|
) {
|
|
if (platform !== 'win32' || !name) {
|
|
return null
|
|
}
|
|
let stdout
|
|
|
|
try {
|
|
stdout = exec('reg', ['query', 'HKCU\\Environment', '/v', name], {
|
|
encoding: 'utf8',
|
|
windowsHide: true,
|
|
timeout: 5000
|
|
})
|
|
} catch {
|
|
// `reg` missing, or value absent (reg exits 1) — caller falls back.
|
|
return null
|
|
}
|
|
|
|
const raw = parseRegQueryValue(stdout, name)
|
|
|
|
if (raw == null) {
|
|
return null
|
|
}
|
|
const expanded = expandWindowsEnvRefs(raw, env).trim()
|
|
|
|
return expanded || null
|
|
}
|
|
|
|
export { expandWindowsEnvRefs, parseRegQueryValue, readWindowsUserEnvVar }
|