* Add mobile diff review
* Wrap mobile review notes prompt
* Fix mobile review unreviewed navigation
* Clear review completion when a refreshed diff invalidates a reviewed file
mergeMobileDiffReviewState invalidates a file's reviewed flag when its
diff identity changes, but left completedAt set — inconsistent with
markUnreviewed. Drop completedAt on invalidation and add a regression
test.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): emit zsh shell-ready marker even when a user zle-line-init hook fails
Orca's zsh wrapper registered its OSC-777 shell-ready marker via
`add-zle-hook-widget line-init`. zsh's azhw dispatcher aborts the whole
hook chain when an earlier hook returns non-zero, and oh-my-zsh's vi-mode
installs a raw `zle-line-init` that exits 1 when VI_MODE_SET_CURSOR is
unset. The marker never fired, so every queued startup command sat on the
daemon's 15s pre-ready timeout — agent quick-launches looked like they
just opened a bare terminal.
Own `zle-line-init` directly: emit the marker first, then chain to any
previously-installed widget (called as a plain function so $WIDGET stays
`zle-line-init` for downstream azhw dispatchers). The registration is
idempotent — a re-source keeps the originally captured widget instead of
clobbering the chain. Applied to both the daemon and local-PTY wrappers
via a shared template helper.
* test(shell-ready): skip global zsh rcs so CI compinit can't block the marker tests
The real-zsh node-pty tests spawned 'zsh -l'/'zsh -i', which on CI runners
sources /etc/zsh/* whose global compinit hits insecure (group-writable) fpath
dirs and blocks on an interactive 'insecure directories [y/n]?' prompt before
zle-line-init fires. The marker never appeared and the tests timed out. Spawn
with -o noglobalrcs so only our ZDOTDIR wrapper/fixtures load; the marker
contract is unaffected.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Add keyboard shortcuts to launch agent tabs
Cmd+T opens a plain terminal tab, but launching an agent in a new tab was
mouse-only (tab bar + menu). This adds:
- tab.newAgent ("New agent tab"): launches the default agent in a new tab
in the active workspace. Default chord Cmd+Alt+T on macOS; unassigned on
Windows/Linux (AltGr / desktop-terminal chord conflicts), bindable in
Settings. Resolves the agent via the configured default when detected
and enabled, otherwise the shared auto-pick order; a 'blank' default
falls through to auto-pick since an explicit agent chord wants an agent.
- tab.newAgent.<id>: one bindable action per TUI agent so each enabled
agent can sit on its own chord. All ship unassigned. Settings →
Shortcuts shows them in a new "Agents" group, hiding disabled agents;
a per-agent chord launches its agent even when detection hasn't
confirmed the binary (explicit request fails visibly in the tab).
Launches go through launchAgentInNewTab (same path as the tab-bar quick
launch) with launch_source 'shortcut'. Agent display names move to a
shared module so the keybinding registry can title the generated actions
without importing renderer code. groupDefinitions moves out of
ShortcutsPane.tsx to keep it under the max-lines lint cap.
* Fix recording Option-composed shortcuts on macOS
On macOS, Option changes the produced character (Cmd+Alt+C reports
key 'ç'), so the shortcut recorder rejected Alt combos with 'Press a
key, not only a modifier'. Capture now falls back to the physical key
code when Alt is held, matching the existing matcher behavior.
* fix: ignore disabled agent shortcuts in conflict checks
Co-authored-by: Orca <help@stably.ai>
* fix: align mac option shortcut capture with matching
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* Fix markdown preview links opening in system browser instead of Orca
In the markdown preview, a plain (or Cmd/Ctrl) click on an http/https link
called window.api.shell.openUrl() directly, which always routes to
shell.openExternal (the OS default browser). It bypassed openHttpLink, so a
plain click could never open in the Orca built-in browser, regressing the
behavior from #987. The Cmd/Ctrl+Shift escape hatch was already correct.
Route both http click paths through openHttpLink via a new
resolveMarkdownPreviewHttpOpenOptions helper that centralizes the
cross-platform modifier decision (Cmd on Mac, Ctrl on Linux/Windows):
- plain / Cmd-click -> { worktreeId } -> Orca browser (per openLinksInApp),
falling back to the system browser when the setting is off, no worktree is
known, or a remote runtime is active.
- Cmd/Ctrl+Shift-click -> { forceSystemBrowser: true } -> system browser.
The remote/SSH case is handled inside openHttpLink (http stays on the client
system browser; file:// blocking is unchanged).
Adds a happy-dom interaction test that renders the real component and fires
real modifier clicks, plus full modifier-matrix coverage for the helper.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* review: share markdown preview link modifier logic
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
This allows simple clicks on the repository header to still reach the
inner collapse handler on pointerup. Additionally, body cursor and
user-select styles are only applied when actual dragging begins,
rather than when the session is armed.
- Pulls the Settings option out of the Help dropdown menu and renders it as a standalone button directly in the sidebar.
- Integrates the `useShortcutKeys` hook and `ShortcutKeyCombo` component to display the settings keyboard shortcut in the button's tooltip.
- Updates associated tests to verify the new button's placement, ARIA attributes, and tooltip content.
* fix(serve): persist active mobile-session tab so PTY output doesn't snap focus
In `orca serve` (headless host + remote/web client), running a command in a
terminal snapped the active tab back to the last-created tab. The renderer
reconcile forces the client's active tab to the host's reported active
(activeTabId / activeTabType / per-tab isActive), but `activateMobileSessionTab`
only called `focusTerminal` — a no-op for serve tabs no renderer has adopted —
and never persisted the chosen tab into the host's in-memory snapshot. So every
`onPtyData` -> `touchMobileSessionSnapshotsForPty` republish re-emitted the stale
"active = last tab" and the client snapped back on each command.
Persist the activation into the headless snapshot (activeTabId, activeTabType,
exclusive per-tab isActive, rebuilt tabGroups) after the focus dispatch, gated on
`!getAvailableAuthoritativeWindow() && isHeadlessMobileSessionPublication(...)` —
the same guard the hydrate path uses, so renderer-owned snapshots (including
`:headless-merge:`) stay authoritative. No-op when the tab is already active;
adds nothing to the `onPtyData` hot path.
Adds 3 regression tests covering: chosen tab survives a PTY republish, no version
bump on redundant activation, and no server-side persist when a renderer is
authoritative.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(serve): exclude :headless-merge: snapshots from headless active-tab persist
After a renderer detaches there is no authoritative window, so the
!getAvailableAuthoritativeWindow() guard alone let merged (:headless-merge:)
snapshots through this path. A merged snapshot still carries renderer-owned
tabs/groups, so a server-side active-tab rewrite could collapse that mixed
group state. Exclude merged epochs from the persist gate; only pure
`headless:` / `headless-hydrated:` publications are persisted server-side.
Adds a regression test: renderer-detach + `:headless-merge:` snapshot ->
the headless persist is suppressed (no snapshot mutation / event).
Addresses the CodeRabbit review on #5131.
* review: clarify headless active-tab persistence guard
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Correct a minor grammatical issue in the English notice by adding
"the". Additionally, localize FolderWorkspaceComposerDialog and
ProjectOrderManualDefaultNotice in Spanish, Japanese, Korean, and
Chinese to replace the English fallback strings.
* Optimize CI checks caching and polling backoff behavior
- Prevent backing off the polling interval when no checks are reported
yet, keeping polling at the baseline rate to detect newly started jobs.
- Reduce empty checks cache TTL to 10 seconds to allow faster recovery
from a "no checks" state while preserving the 60-second TTL for active jobs.
- Avoid bypassing the GitHub CLI cache on tab entry, reserving forced
fetches only for explicit manual user refreshes.
- Update "No checks configured" copy to "No checks reported yet" to avoid
misleading users before their CI pipelines have started running.
- Ensure manual checks refreshes do not inherit in-flight automatic requests
which might be backed by cached CLI data.
- Lookup head-specific cache keys during PR refresh events to prevent
incorrectly deriving neutral check statuses.
* Clarify polling reset comment in ChecksPanel
Update the comment to accurately refer to the entry refresh rather
than a forced fetch establishing a fresh baseline.
* Constrain right sidebar primary button widths to prevent layout jumps
Introduce min-width constraints, truncation, and content-width layouts
for primary actions in the right sidebar and PR dialogs. This prevents
buttons from shifting layout dramatically when labels morph dynamically
as git and review state changes.
* Fix right sidebar split action overflow
Introduce min-width constraints, truncation, and content-width layouts
for primary actions in the right sidebar and PR dialogs. This prevents
buttons from shifting layout dramatically when labels morph dynamically
as git and review state changes.