The previous initial-scroll behavior fired one scrollToBottom() at
+200ms after the session load and cleared the pending flag. When
markdown, syntax highlighting, or images finished rendering after
that window, scrollHeight grew but nothing re-anchored the viewport.
The chat tab appeared "scrolled way up" with the latest assistant
message off-screen until the user manually scrolled or sent a new
message.
This replaces the setTimeout with a requestAnimationFrame loop that
re-scrolls every frame while scrollHeight is still growing, capped
at ~1s (60 frames) or 3 consecutive stable frames. The loop cancels
cleanly on session change via the existing pendingInitialScrollRef
flag, and the cleanup function cancels any in-flight rAF on unmount.
No behavior change for sessions whose content layout is already stable
at the first frame.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously the regex ^\/(\S*)$ only matched when the entire text before
the cursor was a bare /command. Typing a slash mid-sentence (e.g.
"please run /he") produced no suggestions.
Changed pattern to (?:^|\s)(\/\S*)$ which matches / at the start of
input or after any whitespace. Also compute slashPos from match.index
instead of hardcoding 0, so insertCommandIntoInput replaces the correct
slice of the input when the command is mid-sentence.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Plugin servers are started with a deliberately minimal env (PATH, HOME,
NODE_ENV, PLUGIN_NAME). On Windows that drops system variables that child
processes need to bootstrap. The one that bit me: without APPDATA, CPython
cannot find the per-user site-packages, so a plugin that shells out to a
pip install --user CLI launches the tool but it dies with ModuleNotFoundError.
SystemRoot, PATHEXT and TEMP cause similar failures for other tools.
On win32, pass through a small allowlist of non-secret system variables
(SystemRoot, windir, SystemDrive, USERPROFILE, APPDATA, LOCALAPPDATA, TEMP,
TMP, PATHEXT) when they are set. No change off Windows, and no host secrets
are exposed.
Replace bare background operator with nohup+disown so the cloudcli
server process survives after the sbx exec session terminates.
Also redirects stdout/stderr to /tmp/cloudcli-ui.log for debugging
via `cloudcli sandbox logs`.
Fixes#791
Co-authored-by: NoahHahm <noah@naverz-corp.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Haile <118998054+blackmammoth@users.noreply.github.com>
Users need a visible upload path from the explorer itself, not only drag and
drop behavior with no progress feedback. Routing picker and drop uploads
through one XHR-backed hook keeps progress, validation, refresh, and success
counts consistent for every upload source.
The 200MB limit is mirrored in the client, multer, and nginx template so large
uploads fail predictably instead of being blocked by whichever layer sees the
request first. The server also returns explicit requested and uploaded counts
so partial or multi-file batches can render accurate status text.
Claude stores some tool failures as errored tool_result rows. The UI either
attached those rows to hidden tool output or dropped them when no matching tool
call was rendered, which made validation failures disappear from chat history.
Render unattached errored tool results, unwrap Claude tool_use_error content,
and keep tool errors visible even for tools whose successful output is hidden.
Also remove the permission-grant recovery controls from rendered error history
so denied tool use stays a plain error message.
Users deploying behind a reverse proxy need a config they can adapt.
The template documents each proxy block and centralizes upstream/subpath values.
It also notes that Nginx location matchers still require literal subpath edits.
* perf(file-tree): parallelize directory traversal and widen default ignore list
The project file-tree endpoint walked children sequentially with
`await fsPromises.stat()` inside a for-loop plus a separate
`fsPromises.access()` probe before recursing. On high-latency
filesystems (NFS/SMB) every one of those round-trips was serialized,
so a 120k-file SMB-mounted project took ~2 minutes to load.
This change:
* Runs stat() and recursive getFileTree() calls in parallel via
`Promise.all` — pipelines round-trips and lets subtree traversals
overlap.
* Drops the redundant access() probe; any EACCES now surfaces from
readdir's own try/catch in the recursive call, saving one RTT per
directory.
* Extracts the hardcoded skip list into an IGNORED_DIRS Set and
extends it to cover common Python / Rust / JVM / IDE build
artefacts (.next, __pycache__, .pytest_cache, .tox, .venv,
target, .gradle, .idea, coverage, etc).
No API shape change; existing consumers get the same tree structure,
only much faster on large or remote-mounted projects.
* fix(file-tree): bound filesystem traversal concurrency
Prevent large file-tree scans from launching unbounded stat and readdir work.
Keep the parallel traversal benefit on high-latency mounts with a bounded queue.
Ignore skipped names only for directories so same-named files stay visible.
* fix(file-tree): inspect entries with lstat
Use lstat for file-tree metadata so symlink entries are identified without following targets.
---------
Co-authored-by: leonkong via Claude <leonkong.claude@users.noreply.github.com>
Claude's model catalog changes quickly enough that a shared three-day cache can
leave users selecting stale defaults or missing newly available model aliases.
Route Claude model lookups through the provider every time so the UI and slash
commands reflect the current provider result instead of an old disk snapshot.
Keep the static fallback catalog aligned with the latest Claude defaults so the
provider still has a sensible response when live discovery is unavailable.
Add dir="auto" to chat message content and composer textarea so
Persian and Arabic text automatically renders right-to-left
while English and other LTR text remains unaffected.
Co-authored-by: Haile <118998054+blackmammoth@users.noreply.github.com>
The WebSocket gateway never sent ping frames, so any reverse proxy with
an idle timeout (Cloudflare Tunnel ~100s, AWS ALB 60s, nginx 60s, etc.)
would silently tear down /shell, /ws and /plugin-ws/* connections after
the idle window. The UI reconnects automatically but users see a
"Connecting to shell" toast every 1–3 minutes during normal use and any
in-flight PTY/chat traffic can race the reconnect.
Schedule a 30s ws.ping() per connection at the gateway level, cleared on
close/error. ping/pong counts as protocol activity for all proxies that
implement WebSocket correctly, so this single change covers every
deployment topology without per-proxy tuning.
Fixes#769
Co-authored-by: Haile <118998054+blackmammoth@users.noreply.github.com>
Plugin WebSocket connections (e.g. the official Terminal plugin) hang
in `npm run dev` because Vite proxies /api, /ws, and /shell but not
/plugin-ws/*. Production is unaffected because the same Express server
serves both the frontend and the WS gateway.
Co-authored-by: Haile <118998054+blackmammoth@users.noreply.github.com>
The effect cleanup sets unmountedRef.current = true to prevent reconnects after
the provider unmounts. Without an inverse reset at the start of the effect,
re-running the effect (e.g. when the auth token rotates) leaves the ref true,
and connect() short-circuits at its unmounted guard. The socket then stays
permanently disconnected for the lifetime of the provider.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Haile <118998054+blackmammoth@users.noreply.github.com>
* fix(security)(components): unsanitized svg content injected via `dangerouslys
The plugin icon renderer fetches SVG text from `/api/plugins/.../assets/...` and injects it directly into the DOM using `dangerouslySetInnerHTML` after only checking that the payload starts with `<svg`. This does not remove malicious attributes/elements (e.g., event handlers, scriptable SVG payloads), enabling DOM-based XSS if a plugin asset is malicious or compromised.
Affected files: PluginIcon.tsx
Signed-off-by: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com>
* fix: sanitize plugin svg icons
---------
Signed-off-by: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com>
Co-authored-by: tuanaiseo <tuanaiseo@gmail.com>
Co-authored-by: Simos Mikelatos <simosmik@gmail.com>