fix(desktop): preserve custom Linux launcher entries when opted out

Salvage #101453 (03a3f466d38134ba416764185884b3d655197a1d). Preserve its opt-out and first-run behavior; replace predicate-mocked tests with one native config/filesystem invariant and clarify XDG docs. Real venv/XDG probe: base clobbers custom entry, fix preserves it; targeted suite 94 passed.
This commit is contained in:
HoneyTyagii
2026-09-07 00:28:25 -07:00
committed by Teknium
parent 94ff4fe8f9
commit 381d6064d7
4 changed files with 77 additions and 1 deletions

View File

@@ -548,8 +548,31 @@ def _install_icon_to_hicolor(icon: Path) -> bool:
return False
def _launcher_entry_management_enabled() -> bool:
"""Whether config.yaml allows rewriting an EXISTING launcher entry.
``desktop.manage_launcher_entry: false`` opts out of the every-launch
rewrite: a hand-edited ``hermes.desktop`` is then left alone instead
of silently reverting (#101097's clobber complaint). A MISSING entry
is still created regardless — the opt-out protects user edits, not
first-run presence. Any config error reads as enabled (default).
"""
try:
from hermes_cli.config import load_config_readonly
desktop_cfg = (load_config_readonly() or {}).get("desktop") or {}
raw = desktop_cfg.get("manage_launcher_entry", True)
if isinstance(raw, bool):
return raw
if isinstance(raw, str):
return raw.strip().lower() not in ("false", "0", "no", "off")
return True
except Exception:
return True
def install_desktop_entry(project_root: Path) -> Optional[Path]:
"""Write (or refresh) the Hermes desktop entry and return its path.
"""Create or refresh the entry, respecting the opt-out for existing entries.
``None`` on non-Linux platforms or when the write fails — a convenience, never a reason to
fail a launch.
@@ -558,6 +581,12 @@ def install_desktop_entry(project_root: Path) -> Optional[Path]:
return None
entry_path = desktop_entry_path()
# Opt-out honored only for an entry that already exists: the flag
# stops the every-launch clobber, not first-run creation.
if entry_path.is_file() and not _launcher_entry_management_enabled():
return entry_path
icon = icon_path(project_root)
# Prefer the themed name: the icon is COPIED into the hicolor tree, so the entry outlives the
# checkout (an absolute Icon= path breaks when the checkout moves). Absolute path only when