diff --git a/CHANGELOG.md b/CHANGELOG.md index e7f6ad6..52f4439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,6 @@ --- -## [v0.50.19] Fix UnicodeEncodeError when downloading files with non-ASCII filenames (PR #378) - -- **Workspace file downloads no longer crash for Unicode filenames** (`api/routes.py`): Clicking a PDF or other file with Chinese, Japanese, Arabic, or other non-ASCII characters in its name caused a `UnicodeEncodeError` because Python's HTTP server requires header values to be latin-1 encodable. A new `_content_disposition_value(disposition, filename)` helper centralises `Content-Disposition` generation: it strips CR/LF (injection guard), builds an ASCII fallback for the legacy `filename=` parameter (non-ASCII chars replaced with `_`), and preserves the full UTF-8 name in `filename*=UTF-8''...` per RFC 5987. Both `attachment` and `inline` responses use it. - - 2 new integration tests in `tests/test_sprint29.py` covering Chinese filenames for both download and inline responses, verifying the header is latin-1 encodable and `filename*=UTF-8''` is present; 924 tests total (up from 922) - ## [v0.50.21] Live reasoning, tool progress, and in-flight session recovery (PR #367) - **Durable inflight reload recovery** (`static/ui.js`, `static/messages.js`): `saveInflightState` / `loadInflightState` / `clearInflightState` backed by `localStorage` (`hermes-webui-inflight-state` key, per-session, 10-minute TTL). Snapshots are saved on every token, tool event, and tool completion, and cleared when the run ends/errors/cancels. On a full page reload with an active stream, `loadSession()` hydrates from the snapshot before calling `attachLiveStream(..., {reconnecting:true})` — partial messages, live tool cards, and reasoning text all survive the reload. @@ -40,6 +35,11 @@ - 25 new tests in `tests/test_issues_373_374_375.py`; 949 tests total (up from 924) +## [v0.50.19] Fix UnicodeEncodeError when downloading files with non-ASCII filenames (PR #378) + +- **Workspace file downloads no longer crash for Unicode filenames** (`api/routes.py`): Clicking a PDF or other file with Chinese, Japanese, Arabic, or other non-ASCII characters in its name caused a `UnicodeEncodeError` because Python's HTTP server requires header values to be latin-1 encodable. A new `_content_disposition_value(disposition, filename)` helper centralises `Content-Disposition` generation: it strips CR/LF (injection guard), builds an ASCII fallback for the legacy `filename=` parameter (non-ASCII chars replaced with `_`), and preserves the full UTF-8 name in `filename*=UTF-8''...` per RFC 5987. Both `attachment` and `inline` responses use it. + - 2 new integration tests in `tests/test_sprint29.py` covering Chinese filenames for both download and inline responses, verifying the header is latin-1 encodable and `filename*=UTF-8''` is present; 924 tests total (up from 922) + ## [v0.50.18] Recover from invalid default workspace paths (PR #366) - **WebUI no longer breaks when the configured default workspace is unavailable** (`api/config.py`): The workspace resolution path was refactored into three composable functions — `_workspace_candidates()`, `_ensure_workspace_dir()`, and `resolve_default_workspace()`. When the configured workspace (from env var, settings file, or passed path) cannot be created or accessed, the server falls back through an ordered priority list: `HERMES_WEBUI_DEFAULT_WORKSPACE` env var → `~/workspace` (if exists) → `~/work` (if exists) → `~/workspace` (create it) → `STATE_DIR/workspace`. diff --git a/README.md b/README.md index d92c792..c70e424 100644 --- a/README.md +++ b/README.md @@ -470,25 +470,25 @@ api/ models.py Session model + CRUD + CLI bridge (~377 lines) onboarding.py First-run onboarding wizard, OAuth provider support (~507 lines) profiles.py Profile state management, hermes_cli wrapper (~411 lines) - routes.py All GET + POST route handlers (~2200 lines) + routes.py All GET + POST route handlers (~2250 lines) state_sync.py /insights sync — message_count to state.db (~113 lines) - streaming.py SSE engine, run_agent, cancel support (~560 lines) + streaming.py SSE engine, run_agent, cancel support (~660 lines) updates.py Self-update check and release notes (~257 lines) upload.py Multipart parser, file upload handler (~82 lines) workspace.py File ops, workspace helpers, git detection (~288 lines) static/ index.html HTML template (~600 lines) style.css All CSS incl. mobile responsive, themes (~1050 lines) - ui.js DOM helpers, renderMd, tool cards, context indicator (~1900 lines) + ui.js DOM helpers, renderMd, tool cards, context indicator (~1740 lines) workspace.js File preview, file ops, git badge (~286 lines) - sessions.js Session CRUD, collapsible groups, search, reload recovery (~840 lines) - messages.js send(), SSE handlers, rAF throttle, live streaming (~700 lines) + sessions.js Session CRUD, collapsible groups, search, reload recovery (~800 lines) + messages.js send(), SSE handlers, live streaming, session recovery (~655 lines) panels.js Cron, skills, memory, profiles, settings (~1438 lines) commands.js Slash command autocomplete (~267 lines) boot.js Mobile nav, voice input, boot IIFE (~524 lines) tests/ conftest.py Isolated test server (port 8788) - 51 test files 802 test functions + 61 test files 961 test functions Dockerfile python:3.12-slim container image docker-compose.yml Compose with named volume and optional auth .github/workflows/ CI: multi-arch Docker build + GitHub Release on tag