Commit Graph

2832 Commits

Author SHA1 Message Date
Dustin dbebbeddfc fix(start.ps1): handle WOW64 ProgramFiles redirection in candidate discovery
Surfaced by smoke-testing this PR on a fresh foundry-side checkout.
PowerShell sometimes runs as a 32-bit (WOW64) process on 64-bit
Windows — e.g., from certain shell-chain configurations (Git Bash →
pwsh through specific launchers, or some 32-bit IDE-spawned shells).
In that mode `$env:ProgramFiles` is redirected to
`C:\Program Files (x86)` by Windows, so the existing two-entry loop:

    foreach ($root in @($env:LOCALAPPDATA, ${env:ProgramFiles}, ${env:ProgramFiles(x86)}))

produced TWO identical `C:\Program Files (x86)\hermes\hermes-agent`
candidates AND silently missed the real `C:\Program Files\hermes\hermes-agent`
where MSI-installed hermes-agent actually lives.

Two changes:

1. Add `${env:ProgramW6432}` to the loop. ProgramW6432 is the canonical
   override that Windows guarantees points at the 64-bit Program Files
   regardless of process bitness. On a native 64-bit process, it
   equals `$env:ProgramFiles` (so we may pick up a duplicate, handled
   below). On a WOW64 process, it's the only way to reach
   `C:\Program Files`.

2. Add `$candidates = $candidates | Select-Object -Unique` after the
   list is built. Collapses any same-path collisions regardless of
   which env-var combination caused them — defensive against future
   env-var weirdness too (constrained sandboxes, custom Windows builds).

Verified end-to-end:
- BEFORE the fix, smoke test on a WOW64 pwsh 7.5.4 showed candidates 3 + 4
  both = `C:\Program Files (x86)\hermes\hermes-agent`. Real `C:\Program Files`
  never checked.
- AFTER the fix, same shell shows 5 distinct candidates: USERPROFILE,
  LOCALAPPDATA, ProgramW6432 (`C:\Program Files`), ProgramFiles(x86), sibling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 16:20:33 -05:00
Dustin 6f42353812 fix(start.ps1): address Copilot review on #2805 — PathType+null-guard+changelog
Three Copilot-found issues from the PR review:

1. `start.ps1:94` and `start.ps1:107` used `Test-Path (Join-Path ... 'hermes_cli')` without `-PathType Container`. A file (not a directory) named `hermes_cli` at any candidate root would pass the check, even though every downstream use of `$AgentDir` treats it as a directory. Both sites now use `-PathType Container`.

2. `start.ps1:99-104` built `$candidates` as a 5-entry literal array, two of which (`${env:ProgramFiles}` and `${env:ProgramFiles(x86)}`) can be null/empty on 32-bit Windows or in constrained environments. `Join-Path` throws on a null Path. Switched to incremental list construction with an `if ($root)` guard for the three system-wide candidates; `%USERPROFILE%` is always set on standard Windows so it stays unguarded, and the dev-checkout sibling is path-derived (not env-based) so it's also unguarded.

3. `CHANGELOG.md:9` entry implied `start.ps1` was being extended in this PR. Because #2805 stacks on #2783, the full diff Copilot reviews shows `start.ps1` as newly added — making the original phrasing ambiguous. Rewrote the entry to be stack-position-independent: lists the discovery paths added without claiming the file is new or existing, mentions the `-PathType Container` validation and the conditional-build hardening.

Did NOT address Copilot's two WSL2-related comments (`start.ps1:16` header,
`README.md:140`) in this commit — those lines are from #2783's scope, not
#2805's. Will surface as a separate small docs-fix PR per the maintainer's
"keep diffs focused" guidance.

Verification:
- `[System.Management.Automation.Language.Parser]::ParseFile` returns no
  syntax errors against the updated start.ps1
- Both `Test-Path -PathType Container` sites match the same validation
  contract the candidate loop already used at the override-validation site
- Conditional foreach is verified to produce a 4-entry list on a standard
  64-bit Windows machine (USERPROFILE + LOCALAPPDATA + Program Files +
  Program Files (x86)) and degrades gracefully if any of the three
  system-wide roots is unset

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 16:06:42 -05:00
Dustin 6822cbbbb5 feat(start.ps1): expand hermes-agent candidate paths for Windows installers
Maintainer follow-up on PR #2783: the auto-discovery list only checked
`%USERPROFILE%\.hermes\hermes-agent` and `../hermes-agent`, but the
official Windows installer puts hermes-agent under
`%LOCALAPPDATA%\hermes\hermes-agent`, and MSI installs commonly land in
`Program Files`. Users hitting `start.ps1` from a fresh clone of an
installer-deployed agent currently have to set `HERMES_WEBUI_AGENT_DIR`
manually — which is the exact friction the PR was trying to remove.

Adds three new candidate paths to the discovery list:

- `%LOCALAPPDATA%\hermes\hermes-agent`   (official Windows installer)
- `%PROGRAMFILES%\hermes\hermes-agent`   (MSI to Program Files)
- `%PROGRAMFILES(X86)%\hermes\hermes-agent`  (MSI to x86 path)

Order matters: existing `%USERPROFILE%\.hermes\hermes-agent` stays
first (user-local installs win), then the three new system-wide paths,
then the sibling-of-RepoRoot `../hermes-agent` developer-checkout case
stays last. Same `Test-Path (Join-Path \$c 'hermes_cli')` validation
applies to every candidate.

Also restructures the not-found error message to enumerate every
searched path via `\$candidates -join ', '` — when discovery fails the
user now sees the exact list checked, so it's obvious where to drop
the agent or which `HERMES_WEBUI_AGENT_DIR` value to set.

Stacked on top of #2783. Once #2783 lands, this rebases cleanly onto
master.
2026-05-23 15:36:21 -05:00
Dustin bba516060f fix(start.ps1): validate HERMES_WEBUI_AGENT_DIR on disk before use
Surfaced by the maintainer's requested fresh-checkout smoke test on
PR #2783. The original `if (-not $AgentDir)` guard correctly handled
the unset-env-var case (falls through to candidate auto-discovery),
but did NOT validate the env var when it was explicitly set. A
stale or typo'd HERMES_WEBUI_AGENT_DIR pointing at a missing folder
would silently progress into `& $Python $serverPath`, leading to a
confusing exit 9009 from the Microsoft Store python3 stub (or a
missing-imports crash on a real python).

Now: when the env var is set we `Test-Path (Join-Path $AgentDir
'hermes_cli')` first. Missing -> Write-Error + exit 1 with a clear
message telling the user to either unset (to use auto-discovery) or
fix the path. Same validation the candidate-discovery loop already
applies to its own paths — just extended to the explicit-override
case.

Verified on a fresh `gh repo clone Koraji95-coder/hermes-webui`
checkout of this branch:

  PS> $env:HERMES_WEBUI_AGENT_DIR = 'C:\does\not\exist'
  PS> .\start.ps1 -Port 38913
  Write-Error: ...HERMES_WEBUI_AGENT_DIR is set to ...but no
  hermes_cli/ folder exists there. Unset the variable to fall back
  to auto-discovery, or fix the path.
  PS> $LASTEXITCODE
  1
2026-05-23 10:27:17 -05:00
Dustin 40b86d52f5 feat(windows): address Copilot review comments on #2783
Three fixes from copilot-pull-request-reviewer[bot]:

- start.ps1 .env loader: switch the "already-set env var" guard from a
  truthy check to an explicit $null check. Empty-string env vars are
  falsey in PowerShell, so the old guard would mis-skip and overwrite
  an intentionally-empty pre-set var from the .env file.

- start.ps1 hermes-agent-not-found error: switch from single-quoted to
  double-quoted (interpolated) message so $env:USERPROFILE and the
  sibling-dir path render as real paths instead of literal strings.
  Pre-resolve both candidate paths into local vars for clarity.

- README.md community-guide paragraph: restructure the dense one-liner
  into a bulleted list (memory delta with "varies by config" caveat,
  what works, known limitations) AND clarify the WSL2 relationship:
  WSL2 is needed once for first-time venv creation; after that,
  start.ps1 runs natively with no WSL2 in the daily loop.
2026-05-23 01:33:53 -05:00
Dustin 4b1a382df4 feat: native Windows community-guide link + start.ps1 launcher (#1952)
Combined PR for #1952 per maintainer's option (a) suggestion:

- README.md: paragraph below the existing "Native Windows is not supported"
  warning linking @markwang2658's community-maintained no-Docker / no-WSL2
  setup, including the memory delta (~330 MB native vs ~1080 MB with
  WSL2+Docker) cited in the issue thread.
- start.ps1 (new, 142 lines): PowerShell launcher that bypasses
  bootstrap.py's platform refusal and invokes server.py directly. Mirrors
  start.sh's discovery (load .env, find Python, locate agent dir, set
  env defaults).
- CHANGELOG.md: ### Added entry for start.ps1, ### Documentation entry
  for the README link.

No bootstrap.py change (deferred to a separate larger PR). See PR body
for Thinking Path / What Changed / Why It Matters / Verification /
Risks / Model Used.
2026-05-23 01:27:26 -05:00
nesquena-hermes e091e65d56 Merge pull request #2774 from nesquena/release/stage-pr2773
Release v0.51.118 (Release CP / stage-pr2773 / 1-PR hotfix — v0.51.117 brick fix)
v0.51.118
2026-05-22 16:25:41 -07:00
nesquena-hermes c9dfa33e39 Stamp CHANGELOG for v0.51.118 (Release CP / stage-pr2773 / 1-PR hotfix) 2026-05-22 23:22:27 +00:00
nesquena-hermes 3adc59874d Stage pr2773: PR #2773 — fix(chat): rename _inflightStateLimits() to fix v0.51.117 collision (closes #2771) 2026-05-22 23:21:33 +00:00
nesquena-hermes d8b82e274a docs: stamp PR #2773 in CHANGELOG entry 2026-05-22 23:17:47 +00:00
nesquena-hermes 12becd1f4b fix(chat): rename _inflightStateLimits() to _getInflightStateLimits() to fix v0.51.117 collision
Closes #2771.

v0.51.117 (PR #2766) introduced a top-level function _inflightStateLimits()
in static/ui.js that collided with the window._inflightStateLimits config
object set in static/boot.js. Because top-level function declarations in
classic (non-module) scripts attach to window, boot.js's assignment
overwrote the function reference, and every later _inflightStateLimits()
call threw TypeError. _compactInflightState() runs on every send(), so
no new chat session could be created — v0.51.117 is effectively unusable.

Reported by @jahilldev, with multiple users (@isma3iloiso, @theDanielJLewis,
@JHVenn) confirming the bug or reverting to v0.51.116.

Fix: rename the function to _getInflightStateLimits() — the window-attached
config key stays under its original name (unchanged for any downstream
code that reads it). Updates all 4 call sites in static/ui.js.

Tests:

  - Update tests/test_inflight_storage_quota.py — the existing test
    asserted 'function _inflightStateLimits()' in UI_JS as a positive
    presence check, which certified the bug. Now asserts the renamed
    function name is present AND the old colliding name is absent AND
    no stale call sites remain.
  - Add tests/test_window_function_collision.py — generalized regression
    that scans every static JS file for top-level function declarations
    whose name also appears as the target of 'window.X = {...}' or
    'window.X = <number>'. This is the exact shape that broke #2715
    (_pinnedSessionsLimit in v0.51.106) and #2771. Test fails with a
    precise diagnostic naming the file and symbol if the bug class
    returns. Confirmed test FAILS on current master (unfixed) and PASSES
    on this branch.

Verified end-to-end against the live browser before commit:
  - typeof window._inflightStateLimits === 'object' (config preserved)
  - typeof window._getInflightStateLimits === 'function'
  - _getInflightStateLimits() returns the limits object
  - saveInflightState() persists to localStorage without throwing

Full pytest suite: 6308 passed, 6 skipped, 3 xpassed, 8 subtests passed.
Opus advisor: SHIP.
2026-05-22 23:17:00 +00:00
nesquena-hermes f930260157 Merge pull request #2770 from nesquena/release/stage-pr2766
Release CO: v0.51.117 (stage-pr2766 — 1-PR — in-flight recovery storage quota-safe)
v0.51.117
2026-05-22 12:56:45 -07:00
nesquena-hermes aa0c7b7144 Stamp CHANGELOG for v0.51.117 (Release CO / stage-pr2766 / 1-PR) 2026-05-22 19:53:05 +00:00
george-andraws b2477974c5 fix: make in-flight recovery storage quota-safe 2026-05-22 19:49:20 +00:00
nesquena-hermes a9acafb918 Merge pull request #2769 from nesquena/release/stage-pr2676
Release CN: v0.51.116 (stage-pr2676 — 1-PR — per-skill enable/disable toggle in Skills panel, CLI-parity, Telegram-approved)
v0.51.116
2026-05-22 12:47:44 -07:00
nesquena-hermes e42e3e59b2 Stamp CHANGELOG for v0.51.116 (Release CN / stage-pr2676 / 1-PR) 2026-05-22 19:43:27 +00:00
lucasrc 35adc3a473 feat: add per-skill enable/disable toggle in Skills panel
Original PR: #2676 by @lucasrc

Adds POST /api/skills/toggle endpoint that flips skills.disabled in
config.yaml, and a UI toggle in the Skills panel that shows all skills
(including disabled ones) with a per-skill on/off control.

- Backend: new endpoint validates skill exists in filesystem before
  toggling. Read-modify-write wrapped in _cfg_lock for thread safety.
  Writes through to platform_disabled.webui when present.
- Frontend: each skill-item now has a toggle switch; disabled skills
  appear muted but still listed (previously they were filtered out).
- i18n: new toggle keys translated across all 9 non-English locales.
- Tests: round-trip test for disabled list normalization + toggle
  endpoint behavior.

Squash-merged from contributor's branch (19 commits + 1 merge commit)
onto current master via the cherry-pick-stale-contributor-prs procedure.
2026-05-22 19:43:00 +00:00
nesquena-hermes d833e11fda Merge pull request #2765 from nesquena/release/stage-pr2731
Release CM: v0.51.115 (stage-pr2731 — 1-PR — clarify prompt collapse/expand with chevron-icon polish, Telegram-approved)
v0.51.115
2026-05-22 11:21:51 -07:00
nesquena-hermes 56b2f58259 Stamp CHANGELOG for v0.51.115 (Release CM / stage-pr2731 / 1-PR) 2026-05-22 18:15:39 +00:00
nesquena-hermes 057ae7da53 Polish: chevron icon toggle + fix collapsed-card edge clip
- Replace text 'Collapse'/'Expand' button labels with Lucide chevron SVG
  icons (chevron-down expanded → click to collapse, chevron-up collapsed
  → click to expand). Matches the iconographic design language of the
  rest of the chrome (composer buttons, sidebar controls).
  ARIA label + title attributes carry the same semantics for assistive
  tech, so no accessibility regression vs. the text labels.

- Fix collapsed-card edge clipping at viewport bottom. Original
  .clarify-card { bottom: -24px } was sized for the expanded card
  (300-420px tall); adding a 72px collapsed variant pushed the header
  below the parent's visible region. Override bottom to 8px and reduce
  inner padding for the collapsed state so the entire header sits cleanly
  inside the viewport at both desktop and mobile sizes (verified card
  fits with ~115px margin desktop / ~125px margin mobile).

Per Nathan's 2026-05-22 UX feedback on the screenshot package.
2026-05-22 18:14:48 +00:00
Michael Lam 581da3da2b feat: make clarify prompt collapsible 2026-05-22 17:45:40 +00:00
nesquena-hermes e08eecefb1 Merge pull request #2764 from nesquena/release/stage-407
Release CL: v0.51.114 (stage-407 — 1-PR — update-check recovery from remote re-tags)
v0.51.114
2026-05-22 10:38:18 -07:00
nesquena-hermes 60f146afe6 Stamp CHANGELOG for v0.51.114 (Release CL / stage-407 / 1-PR) 2026-05-22 17:32:26 +00:00
nesquena-hermes 15afabf849 docs: stamp PR #2758 in CHANGELOG entry 2026-05-22 17:25:54 +00:00
nesquena-hermes 0703a07654 fix(updates): pass --force to git fetch --tags to recover from remote re-tags
Without --force, git fetch origin --tags refuses to overwrite divergent
local tags and returns 'would clobber existing tag', jamming the entire
WebUI update path indefinitely. The WebUI is a release-tracking consumer
that never pushes tags, so it should always defer to whatever the remote
says a release tag points to. Add --force to all three fetch-tag call
sites:

  - _check_repo (the 'Check now' button + periodic check)
  - apply_force_update (force-reset to remote HEAD)
  - apply_update (stash + pull --ff-only)

Tests:

  - Updated 3 existing tests in test_updates.py whose fake_git mocks
    asserted the exact ['fetch', 'origin', '--tags'] args list.
  - Updated 1 existing test in test_update_banner_fixes.py that asserted
    the same shape for apply_update.
  - Added 4 new regression tests:
      - test_check_repo_fetches_tags_with_force
      - test_apply_force_update_fetches_tags_with_force
      - test_apply_update_fetches_tags_with_force
      - test_check_repo_recovers_from_remote_retag (end-to-end,
        proves the bare --tags fetch shape is no longer used)

Closes #2756.
2026-05-22 17:25:54 +00:00
nesquena-hermes 92d144ba00 Merge pull request #2763 from nesquena/release/stage-406
Release CK: v0.51.113 (stage-406 — 1-PR — composer model picker lag fix + hard-refresh recovery)
v0.51.113
2026-05-22 10:18:17 -07:00
nesquena-hermes aaa06c1574 Stamp CHANGELOG for v0.51.113 (Release CK / stage-406 / 1-PR) 2026-05-22 17:13:44 +00:00
Frank Song 53f294dc8d Fix composer model picker opening lag 2026-05-22 16:58:55 +00:00
nesquena-hermes 73fe8f24c9 Merge pull request #2760 from nesquena/release/stage-405
Release CJ: v0.51.112 (stage-405 — 1-PR — session model authoritative across restore)
v0.51.112
2026-05-22 09:57:40 -07:00
nesquena-hermes d56cd6a312 Stamp CHANGELOG for v0.51.112 (Release CJ / stage-405 / 1-PR) 2026-05-22 16:54:23 +00:00
ai-ag2026 ef9fe1dfdb fix(chat): keep model fallback guard before session option repair 2026-05-22 16:50:17 +00:00
ai-ag2026 ebcf0dabb5 fix(chat): keep restored session model visible on hard refresh 2026-05-22 16:50:17 +00:00
ai-ag2026 765e5aa091 fix(chat): hydrate restored session model on boot 2026-05-22 16:50:17 +00:00
ai-ag2026 6bcc9689aa fix(chat): keep new session model authoritative 2026-05-22 16:50:17 +00:00
ai-ag2026 af1ee81f06 fix(chat): resolve session model before activating 2026-05-22 16:50:17 +00:00
nesquena-hermes a323f49f14 Merge pull request #2759 from nesquena/release/stage-404
Release CI: v0.51.111 (stage-404 — 1-PR — keep state.db replays out of sidecar tail)
v0.51.111
2026-05-22 09:49:28 -07:00
nesquena-hermes 9f4c7adbb1 Stamp CHANGELOG for v0.51.111 (Release CI / stage-404 / 1-PR) 2026-05-22 16:46:12 +00:00
ai-ag2026 dd07334d6c fix(session): keep state db replays out of sidecar tail 2026-05-22 16:25:10 +00:00
nesquena-hermes 0de3eccdc3 Merge pull request #2757 from nesquena/release/stage-403
Release CH: v0.51.110 (stage-403 — 2-PR batch — default personality from config + sort configured providers to top)
v0.51.110
2026-05-22 09:24:28 -07:00
nesquena-hermes 4da2a8e21a Stamp CHANGELOG for v0.51.110 (Release CH / stage-403 / 2-PR batch) 2026-05-22 16:20:41 +00:00
fxd-jason 84ef8a63a6 fix: remove xai from has_key test (CI env has no XAI_API_KEY) 2026-05-22 16:13:46 +00:00
fxd-jason 7e556614f9 test: add sort order tests for providers and model picker 2026-05-22 16:13:46 +00:00
fxd-jason 56575bd393 feat: sort configured/custom providers to top in model picker and settings 2026-05-22 16:13:46 +00:00
s010mn 4153a47d0f feat: new_session() reads display.personality from config as default
When display.personality is set in config.yaml (e.g. personality: taleb),
new sessions now inherit it automatically instead of starting with
personality=None and requiring an explicit /personality command.

This makes the selected personality sticky across new conversations rather
than requiring per-session activation.

Behavior:
- display.personality values 'none', 'default', 'neutral', '' are treated
  as no personality (personality=None), matching TUI gateway semantics.
- Config read is wrapped in try/except — if it fails, personality falls
  back to None (no crash, no regression).
- Case-insensitive: 'Taleb' normalizes to 'taleb'.

The /personality slash command still works for per-session overrides as
before; this change only affects the initial default.
2026-05-22 16:13:33 +00:00
nesquena-hermes 6498043b5e Merge pull request #2755 from nesquena/release/stage-402
Release CG: v0.51.109 (stage-402 — 2-PR batch — sidebar action menu click stability + chat panel sidebar resync after navigation)
v0.51.109
2026-05-22 09:07:30 -07:00
nesquena-hermes 0a1e22d0a2 Stamp CHANGELOG for v0.51.109 (Release CG / stage-402 / 2-PR batch) 2026-05-22 15:55:12 +00:00
nesquena-hermes cab60bcd3b Stage 402: PR #2736 2026-05-22 15:51:12 +00:00
nesquena-hermes 78233e91dc Stage 402: PR #2741
# Conflicts:
#	CHANGELOG.md
2026-05-22 15:51:09 +00:00
nesquena-hermes 05c63b5611 Merge pull request #2754 from nesquena/release/stage-401
Release CF: v0.51.108 (stage-401 — 4-PR batch — session-index dedup + update-check redaction + handoff-summary sqlite leak + RuntimeAdapter Slice 4d gate docs)
v0.51.108
2026-05-22 08:39:18 -07:00
nesquena-hermes 46661ede93 Stamp CHANGELOG for v0.51.108 (Release CF / stage-401 / 4-PR batch) 2026-05-22 15:29:02 +00:00