When scrolling inside a host section, the host card now stays pinned at
the top (z-30) while project/status group headers hand off beneath it
(z-20, offset by the pinned card height). The host is the outer
hierarchy level, so it is the most persistent context — previously the
first repo header replaced it, losing 'which machine am I on' exactly
when it mattered. The pinned card keeps its collapse/menu/warning
affordances. Handoff rules: the next host card pushes the previous one
out at the viewport top; a group pins only once it reaches the slot
beneath the host card, and a previous host's group can never pin under
the next host. Without host sections the logic degrades to the original
single-tier behavior.
Co-authored-by: Orca <help@stably.ai>
Sidebar polish from review:
- The count badge sat in dead space between the label and the
hover-only chevron/menu; it now hugs the label like repo headers
- Rows under a host card get a left inset so projects and workspaces
visibly belong to the machine above them
- A host whose only visible row is a collapsed repo group counted 0
while the group badge said 9; host counts now fall back to header
counts for groups contributing no visible items
Co-authored-by: Orca <help@stably.ai>
Feedback: the bordered card with the server glyph made it clearer that
a host section is a separate machine, not just another group. Bring
that back while keeping the recent quieting: no status dot when
healthy (marks only for connecting/blocked/error/disconnected), no
'This computer' detail on the local host, and collapse/menu/count
behavior unchanged.
Co-authored-by: Orca <help@stably.ai>
Design feedback: the All-hosts view stacked redundant chrome (server
icon three times, status dots everywhere, a strip repeating what the
headers below said).
- The scope strip no longer renders in All-hosts view — host section
headers tell the story, and scope switching lives in the workspace
options menu. When scoped to one host it becomes a slim
'<host> only · ✕ All hosts' return banner
- Host headers are now quiet uppercase muted labels (no server icon),
with a transport suffix only for remote hosts and a status mark only
when a host needs attention (connecting/blocked/error/disconnected);
healthy hosts show nothing
- Collapse, hover chevron, count badge, and the host menu are unchanged
Co-authored-by: Orca <help@stably.ai>
The host scope strip is the single scoping control (the design doc
explicitly forbids a separate focused-host toggle), and decluttering is
now served by collapsing host sections. A second entry point with a
different verb invented a third concept where two suffice: the strip is
where work goes, the header is a group you can fold.
Co-authored-by: Orca <help@stably.ai>
Sidebar usability fixes for the multi-host grouping, from review feedback:
- A lone host section is noise: host headers now render only when at
least two hosts have visible workspaces, so a 6-host registry with
only local work shows today's plain sidebar
- Host sections collapse/expand like other sidebar groups (persisted
via the existing collapsed-group keys; chevron on hover; menu clicks
don't toggle)
- Host headers restyled from bordered cards to the group-label idiom so
the scope strip (a filter) and host headers (group labels) read as
different tiers
- Scope strip shows '{n} connected' instead of the raw saved-host count
Co-authored-by: Orca <help@stably.ai>
PR #4946 forced terminalGpuAcceleration to 'off' whenever a remote
runtime environment is active, as a conservative workaround alongside
the real fixes (CSS anchor-name encoding and rebuilding the WebGL
renderer after replay bytes parse). That left every remote-runtime
terminal on the slower DOM renderer even though the post-replay
rebuildPaneWebgl already covers the snapshot-after-attach race.
Remove the forced-off resolver so remote-runtime panes honor the user
GPU setting again. The snapshot path (onSnapshot -> processData with
replayingBufferedData -> onReplayData -> rebuildPaneWebgl after parse)
keeps the glyph atlas in sync, and attachWebgl re-checks all guards
(gpuRenderingEnabled, deferred attachment, context loss) on rebuild.
Co-authored-by: Orca <help@stably.ai>
* Make Add Project highlight a roving keyboard selection
The Add Project modal previously rendered Browse folder as a permanently
filled "primary" card with a static ⏎ chip. Turn that white fill + ⏎ chip
into a roving selection indicator driven by keyboard focus: Browse starts
selected (it is autofocused on open), and Tab or ↑/↓ move the highlight —
and the ⏎ chip — to whichever action is focused, so Enter's target is always
the highlighted row.
Also flatten the unselected Browse card's surface to bg-background so it
matches the secondary rows instead of showing the outline variant's lighter
tinted/shadowed surface.
ShortcutKeyCombo gains an optional keyCapClassName so the ⏎ chip can tint
itself for the filled surface.
Co-authored-by: Orca <help@stably.ai>
* Drop focus ring on selected Browse card so it stays borderless
The primary Browse card uses the Button component, whose base styles always
draw a focus-visible border + ring. Because Browse is autofocused-and-selected
on open, that ring rendered as a border on only the top card, unlike the
filled secondary rows. Suppress the ring on the selected state (the fill + ⏎
chip already indicate focus, since focus drives selection) and add a
transparent border to hold the box size steady across the outline↔default swap.
Co-authored-by: Orca <help@stably.ai>
* Fix add project action selection accessibility
Co-authored-by: Orca <help@stably.ai>
* Refine add project action outlines
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
- New runtime-status slice holds per-environment status (boot hydration,
settings-pane probes, host-header checks all write through it); stale
environments dropped on list reload
- buildSidebarHostOptions forwards live status to the host registry at
all call sites, so compat verdicts and blocked health render in the
scope strip, options menu, host headers, and browser pane
- New-workspace composer defaults to a repo on the focused host scope
(explicit draft/initial/active choices still win)
- SSH hosts with expired auth say "Authentication needed" in the host
header instead of icon-only
Co-authored-by: Orca <help@stably.ai>
Replace the variable chip Tooltips with HoverCards to allow scrolling
through long prompt previews (such as the base prompt template).
* Pass action-specific base prompt previews (commit, PR, branch name)
into the text generation dialogs to populate the variable chips.
* Style the hover cards to support vertical scrolling with a sleek
scrollbar and update theme colors to match design guidelines.
* Add unit tests for the variable chips and dialog form behavior.
When on full-page views (like Tasks or Landing) with an open sidebar
but no active worktree, mirror the split-column titlebar layout.
This positions the left titlebar controls directly above the sidebar,
avoiding a layout gap and ensuring consistent visual alignment.
* fix(windows): stop main-thread PowerShell storm on env-store reads
Two changes fix the v1.4.52+ Windows performance regression (#4901 regression
against #4840) where 49 powershell.exe processes were spawned in 27 seconds
during load, saturating the Electron main thread and causing black terminals
and runtimeEnvironments:call timeouts.
Root cause: `readEnvironmentStore` calls `hardenExistingSecureFile` on every
read. The env-store parent directory's mtime churns constantly (every secure
write updates it), so the mtime-keyed idempotency cache never matched →
`bestEffortRestrictWindowsPath` (powershell, ~1-1.5s synchronous) fired on
every call. After #4901, the remote-runtime tab-sync loop reads the store
~2×/s, turning sporadic mtime misses into a continuous main-thread storm.
Fix 1 – path-cached directory hardening: add `hardenedDirectoryPathsThisProcess
(Set<string>)` that caches directory hardening by PATH for the process lifetime.
A directory's required ACL does not change when its mtime changes; only file
hardening retains the metadata-keyed cache so post-rename inode changes are
detected correctly.
Fix 2 – async ACL application: replace `execFileSync(powershell.exe, ...)` with
`execFile` (fire-and-forget). PowerShell cold-start is ~1-1.5s; the function is
already named `bestEffortRestrictWindowsPath` so async/optimistic caching is
correct. `applySecurePathRestriction` returns `true` optimistically on win32 so
the cache entry is written before the background process completes.
Tests: new regression tests verify the directory is hardened exactly once even
when its mtime changes between calls, that unchanged files are not re-hardened,
and that ACL application goes through async execFile (not execFileSync).
* fix(windows): apply credential-file ACL synchronously on write path
Follow-up rigor on the env-store PowerShell ACL storm fix (#5006). The
read-path storm fix (path-cached async directory hardening + async file
re-harden) is retained, but switching ALL ACL application to async opened a
narrow Windows-only security window: because writeFileSync({mode}) is a no-op
on Windows, writeSecureFile returned with the credential file still carrying
the parent directory's inherited (broader) ACL for the ~1-1.5s PowerShell
cold-start, affecting the e2ee keypair, device registry, and runtime env auth
store.
Fix: apply the credential FILE's ACL synchronously (execFileSync) on the
infrequent write path, before the atomic rename publishes it, and cache the
path as hardened only on confirmed success so a failed apply retries. Keep the
DIRECTORY hardening async + path-cached for the process lifetime (that is what
killed the #4901/#5006 main-thread storm). The read path's existing-file
re-harden stays async + metadata-cached (fires at most once per file, no storm).
Also:
- Document the dir-path cache process-lifetime known limitation (deleted+
recreated dir not re-hardened until restart).
- Remove the redundant double dir-cache write in writeSecureFile.
- Add docs/windows-secure-file-acl-hardening.md describing the sync-file/
async-dir model and a manual Windows e2e test plan (the cross-platform
Playwright harness runs on Linux and cannot reach the PowerShell path).
Tests (src/shared/secure-file.test.ts, 13 passing): credential file hardened
synchronously while dir stays async (no async file-ACL window); failed sync
file-ACL apply is not cached and retries; dir hardened exactly once across many
writes despite mtime churn; no PowerShell spawned on non-win32.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: keep POSIX secure directory hardening metadata-aware
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* feat: add windows ssh relay base support
* feat: support windows ssh relay runtime services
* fix: default windows ssh pty cwd to user profile
* fix: support windows hosts over system ssh
* fix: preserve degraded windows relay native deps
* fix: gate windows shell args by relay platform
* fix: preserve windows relay fallback pipes
* test: align windows native deps relay fixture
* fix: build valid windows install lock command
* fix: address windows SSH relay review findings
Resolve correctness, efficiency, and reuse issues found reviewing the
Windows SSH native-host support:
- GC liveness on Windows now probes the actual named pipe (via node
net.connect against markers + deterministic candidates) instead of
substring-matching Win32_Process command lines, which could remove a
live relay dir. Reports ALIVE conservatively only when there is no
liveness signal at all (no markers and no seed pipes).
- Resolve the remote node path once per deploy and thread it through
install/repair/launch instead of re-resolving 3-7x.
- Replace the 200ms node -e poll loop with a single long-lived remote
wait process during Windows relay startup.
- Skip the no-op executable command on Windows in uploadRelay.
- Make the Windows fallback pipe name deterministic and recoverable
(drop the global counter), with an extra reconnect attempt.
- Normalize the prepended node bin dir to backslashes on Windows PATH.
- Batch the system-SSH Windows directory upload into a single streamed
JSON package instead of one ssh process per file.
- Extract relay endpoint/marker helpers into ssh-relay-endpoints.ts and
consolidate the PowerShell EncodedCommand encoding into the shared
powershell-command-encoding module.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Support cancellation and timeouts in Windows port scanning
- Propagate the request AbortSignal and a 5-second timeout to both
PowerShell and netstat child processes during Windows port scanning.
- Avoid spawning the netstat fallback process if the port scan has
already been aborted.
- Wrap the .NET OSArchitecture check in a try/catch block during SSH
Windows platform detection to robustly fall back to environment
variables if needed.
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
- Use the active runtime environment RPC for fetching, paging, and
counting work items when available, falling back to local IPC.
- Scope in-flight work item request keys to specific environment targets
to avoid incorrect deduplication during runtime transitions.
- Discard and skip writing work item responses to cache if the active
runtime environment changed while the request was in flight.
Keep the worktree details hover card visible while the review actions
dropdown is open. This change prevents the hover card from unmounting
when interacting with the portaled dropdown items, and adds support
for unlinking GitLab MRs with appropriate terminology.
* Add remote SSH file download
Implement the remote file download flow described in docs/remote-file-download.md, including main/preload IPC wiring, SSH provider support, file explorer UI actions, and tests.
* Add open action to download toast
* rm design doc
* Detect active agents from title/launch hints before hooks report
* Fix active agent detection in split-pane layouts with lone background ti
* Probe runtime for manually started agents during note-send detection
- Query runtime via `terminal.isRunningAgent` to detect active agents
before titles or status hooks have reported them.
- Extract active-agent-target resolution utilities and state selectors
to a dedicated `active-agent-note-target.ts` file.