Register a window-level keydown listener while the SSH disconnected
dialog is open so Enter triggers Reconnect regardless of which element
holds focus. Dialog-scoped handlers don't fire when focus is inside
xterm/monaco, which aggressively reclaim focus.
Co-authored-by: Orca <help@stably.ai>
* wip
* refactor(sidebar): drop agent identity icon + expand chevron from inline rows
In the per-card inline agent list, the user already knows which worktree
they're looking at and clicking a row jumps directly to the agent — the
repeated identity glyph (Claude/Gemini/…) and a separate expand chevron
are redundant. Add hideIdentityIcon/hideExpand props to DashboardAgentRow
(default false) and set both on the inline list only; full dashboard is
unchanged.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* feat: close settings on Escape key press
* fix(settings): skip Escape-to-close when focus is in editable field
Why: Escape in an input/textarea/select or contenteditable region usually
means 'cancel this edit', not 'close Settings'. Closing the entire page
would discard in-progress typing. Defer to the field's own handler; a
subsequent Escape with focus on the body will close the page.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
Allows the user to reposition the sidekick overlay by pressing and dragging. Position is clamped to the viewport (including on resize) and persisted to localStorage. Uses pointer capture so drag state can't get stuck if the pointer is released outside the window.
Co-authored-by: Orca <help@stably.ai>
Renames the experimental pet overlay to "sidekick" with themed character
names (Claude the Mage, OpenCode the Rogue, Gremlin the Trickster).
Covers IPC channels, preload API, persisted UI state, settings flag,
on-disk userData path, components, and types.
Deletes the standalone pet-overlay design mock.
Co-authored-by: Orca <help@stably.ai>
* feat: add experimental pet overlay
Adds an opt-in 3D pet overlay pinned to the bottom-right. Gated behind
an experimental flag so three.js + GLB models stay out of the renderer
bundle for users who never enable the feature. Ships with four bundled
models plus user-uploaded custom GLBs via a pet:import IPC; a status-bar
segment provides model picker + hide toggle.
See docs/design/pet-overlay.md for the full design.
Co-authored-by: Orca <help@stably.ai>
* refactor(pet): replace 3D GLB models with 2D webp images
Co-authored-by: Orca <help@stably.ai>
* chore(pet): compress pet webp images and remove unused assets
Reduce resources/claude.webp, gremlin.webp, opencode.webp sizes; drop
the obsolete pet-overlay design doc and compress-pet-glb script now
that the GLB pipeline has been replaced by 2D webp images.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
* fix(tabs): align tab row bottom with sidebar header
The center column's top band was 6px drag strip + 34px tab row = 40px,
while the sibling `titlebar-left` above the sidebar is 42px. The tab row
sat 2px high, making the seam between the two columns visibly off.
Bump the drag strip from 6px to 8px so the top band totals 42px and the
tab row's bottom border lines up with the sidebar header.
Co-authored-by: Orca <help@stably.ai>
* fix(tabs): shrink tab row to 32px, pad drag strip to 10px
Keep the total top-band at 42px (matching the sidebar's titlebar-left)
while making the tabs themselves 2px shorter, so the tab chrome feels a
touch more compact without breaking alignment with the sidebar header.
Co-authored-by: Orca <help@stably.ai>
* fix(tabs): drop doubled border on leftmost split pane
The TabGroupSplitLayout wrapper paints a full-height `border-l` at the
sidebar seam, and every split pane paints its own `border-l`. On the
leftmost pane those stacked at the same x, reading as a ~2px bar just
below the drag strip where the wrapper's 1px line continues alone above.
Mirror the right-edge handling: skip the pane's `border-l` when it
touches the left edge, leaving the single wrapper border to draw the
seam — same visual weight as the right edge.
Co-authored-by: Orca <help@stably.ai>
* docs(tabs): refresh stale wrapper border-l comment
Why: `border-l` on the wrapper comment still described the pre-fix
overlap behavior. After `touchesLeftEdge`, the leftmost pane drops
its own `border-l`, so the seam is exactly 1px — the old comment
contradicted the code.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
- BrowserTab: Globe icon uses text-blue-500 on both active and inactive tabs
for a distinct, recognizable anchor in the tab strip.
- shell-icons: GenericTerminalIcon now renders a pitch-black tile with a
thick stroked >_ (chevron at 3.2px, underscore at 2.6px, taller chevron)
so mac/linux/default terminal tabs match the colored-badge treatment of
the PowerShell/CMD/WSL icons instead of a flat lucide chevron.
- SortableTab: all terminal tabs use ShellIcon. On Windows, tabs without a
per-tab shellOverride fall back to the user's configured default
Windows shell so the tab-strip icon reflects what's actually running.
Co-authored-by: Orca <help@stably.ai>
getConnectionId returns undefined during store hydration, which was
misclassified as remote by `!== null` check. Changed to `typeof === 'string'`
so unhydrated state falls through to client-OS quoting, consistent with
terminal-drop-handler.ts behavior.
Co-authored-by: Orca <help@stably.ai>
Switch the reveal scroll from align:'center' to align:'auto' so clicking
a worktree only scrolls the sidebar when its card is not already visible.
Centering on every click made the list feel jumpy during normal navigation.
Co-authored-by: Orca <help@stably.ai>