mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 13:26:40 +00:00
The Microsoft Store variant forced HERMES_GUEST_ONBOARDING=1 into its bundle env, and commit/channel builds could bake it with --bundle-env. Nothing reads it now. - scripts/bundles/desktop_inputs.py: the Store bundle env is just the request's. - bundle_env.py / bundle-env.mjs: the key is no longer allowed for new builds. - channel-protocol.ts: the key moves to RETIRED_BUNDLE_ENV_KEYS, so preview manifests already published with it still decode (the HERMES_SKIP_INTRO precedent). - BUILDING.md example uses HERMES_PREVIEW_FULL_CONNECTORS. - Build tests use another allowed key as their sample; both validators reject the retired key and the decoder drops it. - msix-virtualization.test.mjs: every generated MSIX manifest (store, release, canary, channel) keeps filesystem and registry write virtualisation disabled, and the builder config declares unvirtualizedResources. The machine marker and the shared %LOCALAPPDATA%\hermes root depend on that.
51 lines
2.6 KiB
JavaScript
51 lines
2.6 KiB
JavaScript
// Defaults must run before bundled modules resolve paths or feature flags.
|
|
// An esbuild define would replace reads, not populate the child process env.
|
|
// Match scripts/releases/bundle_env.py and the channel request decoder.
|
|
const ALLOWED_KEYS = new Set([
|
|
'HERMES_HOME', 'HERMES_DATA_DIR_SUFFIX', 'HERMES_DESKTOP_USER_DATA_DIR',
|
|
'HERMES_SHARED_AUTH_DIR', 'HERMES_PREVIEW_FULL_CONNECTORS'
|
|
])
|
|
|
|
/** Validate a bundle environment object: plain object of identifiers to
|
|
* strings (defaults) or null (clears). Shared by the banner writer and the
|
|
* smoke driver's stamp reader.
|
|
* @param {unknown} values @returns {Record<string, string|null>} */
|
|
export function validateBundleEnvironment(values) {
|
|
if (!values || Array.isArray(values) || typeof values !== 'object') {
|
|
throw new Error('Bundle environment must be a JSON object')
|
|
}
|
|
for (const [key, value] of Object.entries(values)) {
|
|
if (!ALLOWED_KEYS.has(key) || (value !== null && (typeof value !== 'string' || value.includes('\0')))) {
|
|
throw new Error('Bundle environment requires permitted desktop keys and string values without NUL, or null to clear')
|
|
}
|
|
}
|
|
return /** @type {Record<string, string|null>} */ (values)
|
|
}
|
|
|
|
/** Apply bundle environment defaults/clears to a base environment and return a
|
|
* new object without mutating it. This is the pure twin of the side-effecting
|
|
* loop the bundled banner emits at launch — keep the two in lockstep (pinned
|
|
* by bundle-env.test.mjs). Clears (null) set the key to an empty string
|
|
* unconditionally so a stale registry or ambient value cannot win; defaults
|
|
* fill only an absent key, so an explicit runtime value always wins.
|
|
* @param {Record<string, string|undefined>} env
|
|
* @param {Record<string, string|null>} values */
|
|
export function applyBundleEnvironment(env, values) {
|
|
const result = { ...env }
|
|
for (const [key, value] of Object.entries(values)) {
|
|
if (value === null) result[key] = ''
|
|
else if (result[key] == null) result[key] = value
|
|
}
|
|
return result
|
|
}
|
|
|
|
/** @param {string} raw @returns {string} */
|
|
export function environmentDefaultsBanner(raw) {
|
|
const values = validateBundleEnvironment(JSON.parse(raw))
|
|
// Keep clears present-but-empty so path resolution cannot restore registry
|
|
// defaults. The emitted loop is the side-effecting twin of
|
|
// applyBundleEnvironment above; it cannot call it (the banner runs before
|
|
// the bundle's imports), so the two must stay in lockstep — see the test.
|
|
return `\nfor (const [key, value] of ${JSON.stringify(Object.entries(values))}) { if (value === null) process.env[key] = ''; else process.env[key] ??= value; }\n`
|
|
}
|