Backend:
- Downloading a file from the local host through the transfer engine always
failed: the download branch had no LOCAL_HOST_ID case, so it opened SFTP
against 127.0.0.1:0 (reproduced: "SSH 连接失败: 地址无效 (os error 10049)").
The file browser's own download button goes through that path, so it was
broken in the UI too. The local branch now reuses stream_upload_to_host,
which already had one, keeping the temp-file/resume/SHA-256 guarantees.
- remove_item only refused the literal "/", so a Windows drive root listed by
the file browser ("此电脑" returns "C:/") could be deleted recursively. New
is_root_like() also covers drive roots, "." and "..", shared with
compress_item, plus unit tests.
- dir_cache grew without bound; capped at 256 entries, oldest evicted first.
- ExecTaskManager capped task count but not buffered bytes: 60 running tasks
could hold 120 MiB. Added a 32 MiB budget that evicts finished tasks only.
- Web sessions were only ever inserted, never expired, and every auth-settings
save minted another one. Now a token->issued map with a 30-day TTL, pruned on
every issue.
Frontend:
- A failed pane creation left the stage spinning "正在连接" forever (no retry,
and the standalone window has no tab bar to escape through). The failure is
now kept on the tab and rendered as an error with a retry button.
- The transfer-queue poller only cleared its 350 ms interval on success, so a
401 or a backend restart left it polling ~3 req/s indefinitely.
- The MCP call detail fetch had no sequence guard, so clicking two rows quickly
showed the wrong call's args and result.
- Only three call sites handled 401. Since the session table lives in memory,
every daemon restart invalidates all sessions, so with auth enabled this is
routine rather than an edge case. All protected requests now go through
apiFetch and return to the login screen.
- check-update read data.message, which the backend never returns (it returns
error), so failures only ever showed a bare "检查更新失败".
Docs: corrected the Claude Code setup commands (missing --transport http, and
x-vps-switch-key is not a header the server reads), fixed the Setup.exe PATH
claim, added measured memory numbers for both platforms, and added a
build-from-source section -- a clean clone cannot compile, since frontend/dist
is ignored while RustEmbed treats its absence as a hard error.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>