Skip to content

fix(desktop): stop telling installer users they installed Hermes from the command line - #66287

Closed
stantheman0128 wants to merge 5 commits into
NousResearch:mainfrom
stantheman0128:fix/66095-windows-updater-detection
Closed

fix(desktop): stop telling installer users they installed Hermes from the command line#66287
stantheman0128 wants to merge 5 commits into
NousResearch:mainfrom
stantheman0128:fix/66095-windows-updater-detection

Conversation

@stantheman0128

Copy link
Copy Markdown
Contributor

What does this PR do?

Windows users who installed Hermes with an official installer get a false dialog when they click Update: "You installed Hermes from the command line, so updates run there too." (#66095, reported with filesystem evidence.)

Root cause: the manual fallback in applyUpdates() (apps/desktop/electron/main.ts) treats a missing staged updater (HERMES_HOME/hermes-setup.exe) as proof of a CLI install. Two installer flows land in that branch:

  • The electron-builder NSIS/MSI desktop installer puts Hermes.exe outside the managed checkout, and its first-launch bootstrap (bootstrap-runner.ts driving install.ps1) never stages hermes-setup.exe. Only the Tauri Hermes-Setup installer stages that binary (paths::copy_self_to_hermes_home). This matches the reporter's evidence exactly: repo cloned under %LOCALAPPDATA%\hermes\hermes-agent, no hermes-setup.exe, no .install_method in HERMES_HOME.
  • The Tauri installer's self-copy is best-effort (bootstrap.rs logs a warning and continues on failure), so that flow can also end up without the staged updater.

This PR tells the two cases apart and shows an honest explanation. The recovery command (branch-pinned hermes update) stays the same because it works for installer users too: install.ps1's Set-PathVariable persists the venv Scripts dir to the user PATH.

Detection lives in a new pure module, apps/desktop/electron/update-install-kind.ts:

  • a packaged desktop whose process.execPath is outside resolveUpdateRoot() is installer-deployed (a CLI hermes desktop launch always runs the packed exe from <checkout>/apps/desktop/release/*-unpacked/, per _desktop_packaged_executable in hermes_cli/main.py);
  • HERMES_HOME/logs/bootstrap-installer.log is a Hermes-Setup breadcrumb, created by init_logging() at installer startup, so it exists even when the self-copy failed;
  • everything else keeps today's CLI message, including unpackaged dev runs.

Scope notes: this PR does not make the installers stage hermes-setup.exe (a packaging pipeline change; the NSIS shell would have to ship the separate Tauri updater binary), and it does not touch the backend's .install_method detection (#61827). The adjacent updater PRs solve different failure modes: #37748 validates a staged updater that exists, #61093 finds one staged in a different Hermes home. Here the updater never existed.

Related Issue

Fixes #66095

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • apps/desktop/electron/update-install-kind.ts (new): pure classifyWindowsManualUpdate() with win32 path-containment semantics (case-insensitive, both separators, no sibling-prefix false positives).
  • apps/desktop/electron/update-install-kind.test.ts (new): 7 unit tests covering the NSIS layout from the issue, the failed-self-copy Tauri case, case/separator variance, sibling-prefix dirs, dev runs, and missing inputs.
  • apps/desktop/electron/main.ts: the manual fallback computes installKind and carries it on the apply result and the hermes:updates:progress payload; the log line now records which kind was detected.
  • apps/desktop/src/global.d.ts, apps/desktop/src/store/updates.ts: thread installKind through UpdateApplyState on both the result and progress paths.
  • apps/desktop/src/app/updates-overlay.tsx: ManualView shows the missing-updater body when installKind === 'installer'.
  • apps/desktop/src/i18n/{types,en,zh,zh-hant,ja}.ts: new updates.manualBodyMissingUpdater string.
  • apps/desktop/src/store/updates.test.ts: 3 store cases (cli kind, installer kind, and null default when an older main process omits the field).

How to Test

  1. On Windows, install Hermes with the official desktop installer (or delete %LOCALAPPDATA%\hermes\hermes-setup.exe from a Hermes-Setup install to simulate the failed self-copy).
  2. Open Hermes and click the update button when an update is available.
  3. Before: the dialog claims you installed from the command line. After: the dialog says the install is missing its updater helper and offers the same hermes update command.

Verification I actually ran (Windows 11, this branch):

$ npx vitest run --project electron update-install-kind
 Test Files  1 passed (1)
      Tests  7 passed (7)

$ npx vitest run --project ui src/store/updates.test.ts
 Test Files  1 passed (1)
      Tests  27 passed (27)

$ npm run typecheck
> tsc -p . --noEmit && tsc -p tsconfig.electron.json --noEmit
(clean)

$ npx eslint electron/update-install-kind.ts electron/update-install-kind.test.ts electron/main.ts \
    src/store/updates.ts src/store/updates.test.ts src/app/updates-overlay.tsx src/global.d.ts \
    src/i18n/en.ts src/i18n/zh.ts src/i18n/zh-hant.ts src/i18n/ja.ts src/i18n/types.ts
(clean)

$ npx prettier --check electron/main.ts electron/update-install-kind.ts electron/update-install-kind.test.ts \
    src/app/updates-overlay.tsx src/global.d.ts src/i18n/en.ts src/i18n/ja.ts src/i18n/types.ts \
    src/i18n/zh-hant.ts src/i18n/zh.ts src/store/updates.test.ts src/store/updates.ts
Checking formatting...
All matched files use Prettier code style!

(An earlier revision of this branch had one log line in main.ts over the Prettier print width; the last commit wraps it, and the check above is from the final tree.)

A full vitest run in apps/desktop shows 6 failing test files (scripts/before-pack.test.mjs, scripts/stage-native-deps.test.mjs, electron/update-relaunch.test.ts, electron/windows-hermes-path.test.ts, src/app/messaging/index.test.tsx, src/app/skills/index.test.tsx). I stashed my changes and re-ran on a clean origin/main checkout: the same 6 files fail there, so they are pre-existing on this machine and unrelated to this change.

Honest boundary: I verified the detection and dialog logic at the unit level plus typecheck and lint. I did not build the NSIS installer artifact or drive a packaged desktop end to end; the classifier tests encode the exact filesystem layouts the two install flows produce.

Checklist

Code

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A (behavior documented in code comments; no docs page describes the manual dialog)
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — the changed branch is Windows-only (POSIX takes the in-app update path before it), and the classifier deliberately uses win32 path semantics
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

See the command output in "How to Test" above.

Written by Stan Shih (stantheman0128) with Claude Code assisting on implementation and tests.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/desktop Electron desktop app (apps/desktop/*) platform/windows Native Windows-specific behavior or breakage sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 17, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

Looks Good

  • Fixes incorrect messaging: desktop installer was telling users they installed from command line even when they used the installer
  • Clean fix updating the conditional text
  • No security concerns

Reviewed by Hermes Agent

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for tracing the installer layouts and keeping the change local to the desktop update seam.

Problems

  • The new installKind tests cover the updates.apply() result path, but not the separately changed progress path. Current main subscribes through apps/desktop/electron/preload.ts:256-261 and applies events in apps/desktop/src/store/updates.ts:616-637; please add a manual-progress event test that verifies installKind: 'installer' reaches $updateApply.

Suggested changes

  • Keep the existing classifier tests, and add the event-path test above so both Electron-to-renderer transport paths are covered.

Current main still unconditionally calls this a CLI install in apps/desktop/electron/main.ts:2448-2479 and always renders the CLI copy in apps/desktop/src/app/updates-overlay.tsx:300, so the reported premise remains live. This is an automated hermes-sweeper review.

@teknium1 teknium1 added the sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform label Jul 18, 2026
@stantheman0128

Copy link
Copy Markdown
Contributor Author

Thanks for the catch on the progress-event path.

Added a startUpdatePoller test that feeds a stage: 'manual' progress payload with installKind: 'installer' through onProgress and asserts it lands on ``. Existing apply()-result and classifier tests are unchanged.

Evidence (from apps/desktop):

npm test -- src/store/updates.test.ts electron/update-install-kind.test.ts

Test Files  2 passed (2)
     Tests  35 passed (35)

@teknium1 teknium1 added the area/install-update Installer, updater, packaging, wheels, doctor label Jul 19, 2026
stantheman0128 and others added 5 commits July 23, 2026 15:30
…al-update fallback

The Windows manual fallback assumed a missing staged updater means a CLI
install. Installer-deployed desktops (NSIS/MSI shell outside the managed
checkout, or a Tauri Hermes-Setup run whose best-effort self-copy failed)
land in the same branch and get told they installed from the command
line (NousResearch#66095). Add a pure classifier so the fallback can tell them apart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…back

applyUpdates() now classifies the install before surfacing the manual
`hermes update` fallback and carries the result (installKind) on both
the apply result and the progress event, so the renderer can stop
claiming installer users installed from the command line (NousResearch#66095).
The Tauri installer breadcrumb probed is
HERMES_HOME/logs/bootstrap-installer.log, written unconditionally by
Hermes-Setup even when its best-effort updater self-copy failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tops

The manual dialog told every user without a staged updater 'You
installed Hermes from the command line' — false for official installer
users (NousResearch#66095: NSIS/MSI shells never get hermes-setup.exe staged, and
the Tauri installer's self-copy is best-effort). Thread installKind
from the apply result / progress stream through the update store and
show a missing-updater explanation instead; the terminal command stays
the same because it is the working recovery path either way. New copy
localized for en/zh/zh-hant/ja.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The installKind interpolation pushed the rememberLog call in
applyUpdates() to 125 chars, past the repo printWidth of 120, so
`prettier --check electron/main.ts` failed. Output of
`npx prettier --write electron/main.ts`; whitespace only, no behavior
change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@stantheman0128
stantheman0128 force-pushed the fix/66095-windows-updater-detection branch from 7c586f8 to 48b4cec Compare July 23, 2026 07:34
@stantheman0128

Copy link
Copy Markdown
Contributor Author

Closing this P3 installer-copy PR so review attention can go to higher-impact Windows/desktop fixes we still have open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have platform/windows Native Windows-specific behavior or breakage sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: 官方安装包安装后点「更新」弹出从终端更新对话框,误判为命令行安装

4 participants