Commit Graph

2993 Commits

Author SHA1 Message Date
Frank Song d2e4dfabb4 fix: localize external notes drawer copy 2026-05-25 08:51:44 +08:00
nesquena-hermes 4132085e0c Merge pull request #2889 from nesquena/release/stage-batch14
Release/stage-batch14
v0.51.132
2026-05-24 17:39:33 -07:00
nesquena-hermes a1e5f89ce8 Stamp CHANGELOG for v0.51.132 (Release DD / stage-batch14)
4-PR low-risk batch:
- #2685 LumenYoung: replayed-context dedup fix + live tool prompt cap
- #2739 ai-ag2026: interrupted-response classification + SSE diagnostics
  (rate-limited 30/60s, 4KB body cap, payload sanitized)
- #2824 gavinssr: shutdown server affordance — relocated to Settings
- #2859 AJV20: passkey/WebAuthn sign-in (opt-in default-off behind
  HERMES_WEBUI_PASSKEY / webui_passkey_enabled feature flag)

Opus Advisor verdict: SHIP-WITH-SHOULD-FIXES applied.
Zero MUST-FIX. 4/5 SHOULD-FIX patched inline. 1 deferred to follow-up
(live tool metering cumulative cap).
2026-05-25 00:27:30 +00:00
nesquena-hermes 1c2d574882 Stage-batch14: Opus advisor SHOULD-FIX patches (UX + defense-in-depth)
Inline fixes for 4 of 5 Opus SHOULD-FIX items before tag:

1. /api/auth/status now gates passkeys_enabled / passwordless_enabled on
   _passkey_feature_flag_enabled() — when flag is off, status reports
   no credentials even if passkeys.json has legacy entries. New
   passkey_feature_flag field added to the response for the frontend.

2. Settings → System Passkeys block (passkeysSettingsBlock) now starts
   display:none and loadPasskeys() reveals it only when the server
   confirms passkey_feature_flag === true AND /api/auth/passkeys
   doesn't return {disabled: true}. Stops the broken-affordance trap
   where users would see Add passkey → click → 404.

3. /api/settings/save now refuses to set passwordless mode when the
   passkey feature flag is off. Closes the auth-bypass path Opus flagged:
   user goes passwordless while flag on → admin unsets flag → restart
   serves the WebUI fully unauthenticated.

4. CHANGELOG entries added for PR #2685 (replayed-context dedup +
   per-turn metering cap) and PR #2824 (Stop server affordance,
   relocated to Settings) — both PRs had functional changes but no
   release-notes entries. Also enriched the rate-limit detail on the
   #2739 entry (30 events / 60s / 4KB body cap).

Deferred to follow-up issue (#5 in Opus review):
- Live tool metering cumulative cap across many tool calls — non-trivial
  refactor of _bump_live_prompt_estimate, will be a separate PR
2026-05-25 00:26:40 +00:00
nesquena-hermes 8c170b50ac Stage-batch14: i18n parity for new shutdown keys
Adds the 7 shutdown-related i18n keys to all 10 non-en/tr locales
(it, ja, ru, es, de, zh, zh-Hant, pt, ko, fr) with proper translations.

Resolves test_*_locale.py::test_*_locale_covers_english_keys failures
that were caught by full sequential pytest. Locale parity is enforced
because untranslated keys would surface in non-en deployments as
English fallback text in the Stop Server affordance.

Italian + Portuguese translations use \' to escape apostrophes inside
the single-quoted JS string literals.
2026-05-25 00:22:15 +00:00
nesquena-hermes 19c6e5d5f2 Stage-batch14: update passkey test for HERMES_WEBUI_PASSKEY feature flag
test_passwordless_mode_keeps_auth_enabled_with_passkeys now sets
HERMES_WEBUI_PASSKEY=1 via monkeypatch since are_passkeys_enabled()
gates on the feature flag.

Adds 2 new tests:
- test_passkey_feature_flag_off_disables_passkeys_even_with_credentials
- test_passkey_feature_flag_via_config
2026-05-25 00:17:11 +00:00
nesquena-hermes 46ed70bfde Stage-batch14: add HERMES_WEBUI_PASSKEY feature flag for #2859 passkey support
Per the stage-batch14 ship plan, passkey/WebAuthn support is shipped
opt-in default-off behind an explicit feature flag so deployments can
disable the entire surface (UI + endpoints + credential storage) without
needing to delete code.

Enable via either:
  - HERMES_WEBUI_PASSKEY=1 environment variable, OR
  - webui_passkey_enabled: true in config.yaml

With the flag off:
  - are_passkeys_enabled() returns False even if credentials exist
  - is_auth_enabled() falls back to password-only checking
  - /login renders password-only (no passkey button)
  - All 6 /api/auth/passkey/* endpoints return 404 with a clear message
  - Settings → System → Passkeys section is hidden

Mirrors the #2527 notes-drawer flag shape (env-or-config, truthy parse).
Auth is high-stakes; opt-in lets us land the code while keeping default
deployments on the well-tested password-only path.

Touches: api/auth.py (new _passkey_feature_flag_enabled helper, gated
are_passkeys_enabled), api/routes.py (6 endpoint guards).
2026-05-25 00:16:12 +00:00
AJV20 1b48643f63 feat: support passkey-only auth 2026-05-25 00:14:38 +00:00
AJV20 7c257ae8f9 fix: avoid prompt in passkey registration 2026-05-25 00:14:38 +00:00
AJV20 c60ff543b5 feat: add passkey sign-in 2026-05-25 00:14:38 +00:00
nesquena-hermes 15c5f4cf05 Stage-batch14: relocate #2824 shutdown from title bar to Settings → System
Per project deep-UX standards (default-hidden for niche destructive
actions). The title bar is shared real estate where always-visible
chrome competes with the title text and reload button — adding a
prominent destructive button there fails the 'kid clicks it' test even
with a confirmation modal. Moved to Settings → System where the user
who actively wants to stop the server can still find it, while everyone
else doesn't have to look at it.

Changes:
- Removed app-titlebar-shutdown button from <header> in index.html
- Removed dead .app-titlebar-shutdown CSS rule
- Added Settings → System → Stop server affordance (label + description + button)
- shutdownServer() and _showServerStopped() now use i18n keys
- Added 8 new locale keys to en + tr blocks (settings_label_shutdown,
  settings_desc_shutdown, settings_btn_shutdown, settings_shutdown_confirm_*,
  settings_shutdown_stopped_message). Other 9 locales fall back to English
  via the existing locale fallthrough — follow-up issue tracked separately.

Preserves all of gavinssr's backend work (/api/shutdown route after CSRF
gate, BroadcastChannel for multi-tab signaling, app dialog with danger
styling) — only the placement is changed.
2026-05-25 00:13:47 +00:00
gavinssr 0ab3ad3bb2 fix: place shutdown route after CSRF gate
Move POST /api/shutdown routing after the CSRF check so drive-by
cross-origin requests cannot bring down a dev server with auth off.
Also replace os._exit(0) with os.kill(os.getpid(), signal.SIGINT)
so atexit handlers and pending session writes run during shutdown.
2026-05-25 00:10:52 +00:00
gavinssr c361089658 fix: use app dialog instead of confirm, danger 2026-05-25 00:10:52 +00:00
gavinssr 39121650d4 feat: add shutdown button to WebUI title bar
Add a power button (⏻) in the title bar that gracefully stops the
WebUI server process from the browser.

- api/routes.py: POST /api/shutdown endpoint with threaded os._exit(0)
- static/boot.js: shutdownServer() with confirm prompt, BroadcastChannel
  cross-tab notification, and _showServerStopped() placeholder UI
- static/index.html: shutdown button HTML in title bar (after reload btn)
- static/style.css: .app-titlebar-shutdown styles, hover turns red
2026-05-25 00:10:52 +00:00
nesquena-hermes fe6558efac Stage-batch14: drop pr-artifacts/ scratchpad from #2685 cherry-picks
The contributor used pr-artifacts/ as a working scratchpad during PR
development. The real test count and failure-mode docs are already
covered by inline test comments and CHANGELOG entries; this directory
adds nothing for upstream readers.
2026-05-25 00:10:39 +00:00
Lumen Yang d0992730a9 fix: preserve repeated state rows in replay delta 2026-05-25 00:10:27 +00:00
Lumen Yang 32658978a9 docs: refresh context replay test count 2026-05-25 00:10:27 +00:00
Lumen Yang 5934c2fe8a fix: address context replay review feedback 2026-05-25 00:10:27 +00:00
Lumen Yang 3740df5302 docs: add context replay PR body 2026-05-25 00:10:27 +00:00
Lumen Yang c616c8e788 fix: cap live tool prompt estimates 2026-05-25 00:10:27 +00:00
Lumen Yang 50c69713cc fix: reconcile state db delta after context 2026-05-25 00:10:27 +00:00
Lumen Yang 15cde132f3 fix: dedupe replayed context summaries 2026-05-25 00:10:27 +00:00
nesquena-hermes 74b3ca9920 Merge pull request #2739 from ai-ag2026/fix/interrupted-response-cause-diagnostics
fix(chat): classify interrupted responses and log SSE diagnostics
2026-05-25 00:09:52 +00:00
ai-ag2026 8a2f11c770 fix(chat): log sanitized client sse diagnostics
(cherry picked from commit 749ca6e18c5e307fbf7e7fb5fffce97249545017)
2026-05-25 02:06:42 +02:00
ai-ag2026 2f1ca959f1 fix(chat): classify interrupted response causes
(cherry picked from commit 5c1e802cd6ee8565da74c7ffe57e6407fe21bf02)
2026-05-25 02:06:42 +02:00
ai-ag2026 efe3d7c296 fix(chat): avoid false restart wording for interrupted responses
(cherry picked from commit ef8fd879682aeb729a7b7afa1e7c46478ca5ebb6)
2026-05-25 02:06:42 +02:00
nesquena-hermes e50d6ccc8c Merge pull request #2884 from nesquena/release/stage-batch13
Release/stage-batch13
v0.51.131
2026-05-24 16:43:13 -07:00
nesquena-hermes d012436cb4 Stamp CHANGELOG for v0.51.131 (Release DC / stage-batch13 / 6-PR notes-drawer + context-parity + PWA-swipe + locale polish)
Opus Advisor verdict: SHIP-AS-IS. Zero MUST-FIX, three SHOULD-FIX
filed as follow-up issues:
- Notes drawer: 10 non-en locales ship English fallback (default-off so user impact = 0)
- _joplin_api_get URL-token defense-in-depth (move to Authorization header)
- prefill_messages setattr cache-reuse safety on older agent builds

6,503 pytest passed (sequential mode — xdist not supported by test infra).
2026-05-24 23:42:37 +00:00
nesquena-hermes e5533ea0e4 Merge pull request #2547 from AJV20/fix/webui-context-parity
fix(chat): align WebUI context with messaging sessions
2026-05-24 23:12:27 +00:00
nesquena-hermes 767a9cd06d Merge pull request #2527 from AJV20/feat/webui-notes-sources
feat(memory): show third-party notes sources
2026-05-24 23:11:54 +00:00
nesquena-hermes 376fb78906 Stage-batch13: CHANGELOG for #2873 launcher env
PR was fork-PR-style with no CHANGELOG entry; added an entry describing
the launcher-env-preserve behavior change.
2026-05-24 23:09:48 +00:00
nesquena-hermes d42253bca3 Merge pull request #2873 from Charanis/codex/webui-launcher-env-pr
[1/7] Preserve WebUI launcher environment
2026-05-24 23:09:28 +00:00
nesquena-hermes 1ec0bbc9e0 Stage-batch13: PR #2882 polish — fix zh-TW indent + CHANGELOG entry
The cherry-pick of #2882 brought in an accidental two-space indent on a
zh-TW key. Restored the existing two-space indentation level so the
zh-CN clarification stays the only behavioural change.
2026-05-24 23:09:23 +00:00
john 0279f1b6df Apply zh-CN session-time label clarifications from #2882 (ycj)
PR #2882 was based on stale master (66de2367, pre-stage-batch7); naive
merge would delete 5,627 lines of subsequent work. Extracted the actual
zh-CN diff and applied it on top of fresh stage.

Co-authored-by: john <yuanchangjun@gmail.com>
2026-05-24 23:08:58 +00:00
nesquena-hermes 6f94a44745 Merge pull request #2868 from AJV20/feat/pwa-sidebar-swipe
feat: add PWA sidebar edge swipe
2026-05-24 23:08:30 +00:00
nesquena-hermes 2d803afa3d Merge pull request #2865 from AJV20/fix/session-personality-default
fix: avoid stamping display personality on sessions (#2845)
2026-05-24 23:08:04 +00:00
AJV20 7c460ef7b1 fix(i18n): add Turkish notes-source strings 2026-05-24 17:54:14 -04:00
AJV20 d7b98d87cd Merge remote-tracking branch 'origin/master' into maint/pr-2547
# Conflicts:
#	CHANGELOG.md
2026-05-24 17:48:09 -04:00
AJV20 24979c8af1 Merge remote-tracking branch 'origin/master' into maint/pr-2527
# Conflicts:
#	CHANGELOG.md
2026-05-24 17:48:09 -04:00
AJV20 cf92aa5cc1 Merge remote-tracking branch 'origin/master' into maint/pr-2868
# Conflicts:
#	CHANGELOG.md
2026-05-24 17:48:07 -04:00
AJV20 6e2991f45a Merge remote-tracking branch 'origin/master' into maint/pr-2865
# Conflicts:
#	CHANGELOG.md
2026-05-24 17:48:06 -04:00
Charanis f0b0854773 fix: preserve webui launcher environment
(cherry picked from commit 2297ab4db8)
2026-05-24 21:49:21 +02:00
nesquena-hermes 5977567035 Merge pull request #2869 from nesquena/release/stage-batch12
Release DB — v0.51.130 (stage-batch12, 3-PR profile-isolation + boot-precedence + workspace Artifacts tab)
v0.51.130
2026-05-24 12:43:25 -07:00
hermes-agent 7796f74ca3 Stage 406: Opus MUST-FIX — parity-fix sync_session_usage profile= at api/routes.py:9007
Opus pre-release advisor caught a #2762 parity gap. api/streaming.py:5078
(_run_agent_streaming worker, background thread) correctly passes
profile= to sync_session_usage post-#2827. But the SECOND production
call site at api/routes.py:9007 (_handle_chat_sync, HTTP thread) does
not. Safe TODAY (HTTP thread sets TLS correctly), but it's a
defense-in-depth gap: anyone wrapping that handler in a worker pool
later silently regresses the fix. Closes the parity gap so the
threat-model invariant holds regardless of future threading changes.
2026-05-24 19:39:28 +00:00
hermes-agent cb6780e170 Stage 406: fix conflict-resolution bug — restore sessionModelState definition in _hydrateBootModelDropdown
My earlier conflict resolution between #2716 master and #2726 PR
dropped the 'const sessionModelState=...' assignment that the
.then() callback body uses on 6 different lines (1596, 1600, 1601,
1607, 1608, 1610). Without it boot.js would ReferenceError on every
boot. Caught by tests/test_new_chat_default_model_frontend.py::test_boot_model_hydration_prefers_active_session_over_persisted_model
which I'd missed in the initial touched-tests gate. Adds the
assignment back at the top of the .then() callback — semantically
matches the original #2716 master shape (S.session.model → wrap in
{model,model_provider} object, else null).
2026-05-24 19:21:43 +00:00
hermes-agent c9bc21f394 Stage 406: in-stage test fixes + CHANGELOG for v0.51.130
- Patch tests/test_issue2762_state_sync_profile_kwarg.py::_read_session
  helper to query the real state.db schema (sessions.id PRIMARY KEY,
  not sessions.session_id). Was always broken — the test never matched
  any actual schema. Fix: SELECT id AS session_id + WHERE id = ?
- Patch tests/test_session_metadata_fast_path.py::test_failed_boot_model_catalog_prime_is_retryable
  to accept both populateModelDropdown() and populateModelDropdown({preferProfileDefaultOnFreshBoot:true})
  signatures (sibling-collision with #2726).
- Patch tests/test_model_default_boot_precedence.py::test_boot_model_dropdown_explicitly_requests_profile_default_precedence
  to accept either the original allowBootSavedModelOverride variable
  name OR the post-#2716-cherry-pick stateToApply equivalent
  (!window._defaultModel?savedState:null gate).
- Stamp CHANGELOG for v0.51.130 (Release DB).
2026-05-24 19:17:59 +00:00
AJV20 b0f7a7bdff feat: add PWA sidebar edge swipe 2026-05-24 15:14:28 -04:00
AJV20 7af7370be6 Merge remote-tracking branch 'origin/master' into fix/session-personality-default
# Conflicts:
#	CHANGELOG.md
2026-05-24 15:05:29 -04:00
hermes-agent 7a84c81dda Stage 406: PR #2673 — Add scoped workspace Artifacts tab by @AJV20 (closes #2655) 2026-05-24 18:58:59 +00:00
hermes-agent c4ee97f41f Stage 406: PR #2726 — fix(model): keep boot default precedence non-destructive by @starship-s 2026-05-24 18:58:49 +00:00