fix(desktop): keep profile homes out of bootstrap (#46073)

This commit is contained in:
Teknium 2026-06-14 03:08:52 -07:00 committed by GitHub
parent afc8615509
commit 0428945b5b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 69 additions and 5 deletions

View file

@ -67,6 +67,16 @@ function buildDesktopBackendPath({
)
}
function normalizeHermesHomeRoot(hermesHome, { pathModule = pathModuleForPlatform(process.platform) } = {}) {
if (!hermesHome) return hermesHome
const resolved = pathModule.resolve(String(hermesHome))
const parent = pathModule.dirname(resolved)
if (pathModule.basename(parent).toLowerCase() === 'profiles') {
return pathModule.dirname(parent)
}
return resolved
}
function buildDesktopBackendEnv({
hermesHome,
pythonPathEntries = [],
@ -97,5 +107,6 @@ module.exports = {
buildDesktopBackendEnv,
buildDesktopBackendPath,
delimiterForPlatform,
normalizeHermesHomeRoot,
pathEnvKey
}

View file

@ -7,6 +7,7 @@ const {
appendUniquePathEntries,
buildDesktopBackendEnv,
buildDesktopBackendPath,
normalizeHermesHomeRoot,
pathEnvKey
} = require('./backend-env.cjs')
@ -66,6 +67,21 @@ test('buildDesktopBackendEnv extends PYTHONPATH and backend PATH together', () =
assert.ok(env.PATH.includes('/opt/homebrew/bin'))
})
test('normalizeHermesHomeRoot maps profile homes back to the global Hermes root', () => {
assert.equal(
normalizeHermesHomeRoot('/Users/test/.hermes/profiles/oracle', { pathModule: path.posix }),
'/Users/test/.hermes'
)
assert.equal(
normalizeHermesHomeRoot('C:\\Users\\test\\AppData\\Local\\hermes\\profiles\\oracle', { pathModule: path.win32 }),
'C:\\Users\\test\\AppData\\Local\\hermes'
)
assert.equal(
normalizeHermesHomeRoot('/Users/test/.hermes', { pathModule: path.posix }),
'/Users/test/.hermes'
)
})
test('Windows PATH casing and delimiter are preserved without POSIX sane entries', () => {
const env = buildDesktopBackendEnv({
hermesHome: 'C:\\Users\\test\\AppData\\Local\\hermes',

View file

@ -38,7 +38,7 @@ const { adoptServedDashboardToken } = require('./dashboard-token.cjs')
const { waitForDashboardPort } = require('./backend-ready.cjs')
const { serializeJsonBody, setJsonRequestHeaders } = require('./oauth-net-request.cjs')
const { fetchMarketplaceThemes, searchMarketplaceThemes } = require('./vscode-marketplace.cjs')
const { buildDesktopBackendEnv } = require('./backend-env.cjs')
const { buildDesktopBackendEnv, normalizeHermesHomeRoot } = require('./backend-env.cjs')
const { readDirForIpc } = require('./fs-read-dir.cjs')
const { gitRootForIpc } = require('./git-root.cjs')
const { worktreesForIpc } = require('./git-worktrees.cjs')
@ -240,7 +240,7 @@ if (INSTALL_STAMP) {
// HERMES_HOME beneath the throwaway userData dir so a fresh-install run never
// touches the user's real ~/.hermes / %LOCALAPPDATA%\hermes.
function resolveHermesHome() {
if (process.env.HERMES_HOME) return path.resolve(process.env.HERMES_HOME)
if (process.env.HERMES_HOME) return normalizeHermesHomeRoot(process.env.HERMES_HOME)
if (USER_DATA_OVERRIDE) return path.join(path.resolve(USER_DATA_OVERRIDE), 'hermes-home')
if (IS_WINDOWS && process.env.LOCALAPPDATA) {
const localappdata = path.join(process.env.LOCALAPPDATA, 'hermes')

View file

@ -1655,15 +1655,20 @@ def _setup_telegram_auto_result():
profile_name: str | None = None
try:
hermes_home = str(get_hermes_home())
if "/profiles/" in hermes_home:
profile_name = hermes_home.rstrip("/").rsplit("/", 1)[-1]
profile_name = _profile_name_from_hermes_home(Path(get_hermes_home()))
except Exception:
pass
return auto_setup_telegram_bot_result(profile_name=profile_name)
def _profile_name_from_hermes_home(hermes_home) -> str | None:
"""Return the active profile name when HERMES_HOME is a profile dir."""
if hermes_home.parent.name == "profiles":
return hermes_home.name
return None
def _setup_telegram_auto() -> str | None:
"""Attempt automatic Telegram bot creation and return only the token."""
result = _setup_telegram_auto_result()

View file

@ -2,6 +2,7 @@
from __future__ import annotations
from pathlib import PureWindowsPath
from unittest.mock import MagicMock, patch
from hermes_cli.telegram_managed_bot import (
@ -321,3 +322,34 @@ class TestSetupTelegramAuto:
from hermes_cli.setup import _setup_telegram_auto
assert callable(_setup_telegram_auto)
def test_setup_result_passes_profile_name_for_profile_home(self, monkeypatch, tmp_path):
from hermes_cli import setup
seen = {}
profile_home = tmp_path / ".hermes" / "profiles" / "oracle"
profile_home.mkdir(parents=True)
monkeypatch.setattr(setup, "get_hermes_home", lambda: profile_home)
def fake_auto_setup_telegram_bot_result(*, profile_name=None):
seen["profile_name"] = profile_name
return None
monkeypatch.setattr(
"hermes_cli.telegram_managed_bot.auto_setup_telegram_bot_result",
fake_auto_setup_telegram_bot_result,
)
assert setup._setup_telegram_auto_result() is None
assert seen["profile_name"] == "oracle"
def test_profile_name_from_home_path_handles_windows_separators(self):
from hermes_cli.setup import _profile_name_from_hermes_home
assert (
_profile_name_from_hermes_home(
PureWindowsPath(r"C:\Users\test\AppData\Local\hermes\profiles\oracle")
)
== "oracle"
)