Restyle shared Sonner toasts (wrapping, bottom-chrome clearance with mobileOffset, custom delete-failure footer) and add a dev-only Dev Tools settings pane gated behind import.meta.env.DEV. Removes dead devToolsSearch locale keys, aligns toast description opacity/width with sibling toasts, and uses a distinct nav icon for Dev Tools.
* Show coding agent icons on mobile terminal tabs
Move agent title decoration and terminal title parsing utilities
from the desktop renderer to shared code for reuse on mobile.
* Extract agent title stripping and terminal agent resolution to shared
* Implement mobile agent identity resolution and title-cleaning helpers
* Render agent icons on mobile terminal tabs when an agent is active
* Strip leading status glyphs from tab titles when showing an icon
* Suppress PTY resize on resume for mobile-driven terminals
Avoid reasserting the PTY size on resume if desktop resizing is
suppressed. This prevents overriding the intentional drift from
desktop dimensions for parked or mobile-driven terminals.
GitHub rejects enabling auto-merge on a PR that is already mergeable
with a "Pull request is in clean status" error.
* Suppress "Enable auto-merge" option in the UI when direct merge
is available, while retaining "Disable auto-merge".
* Translate the GitHub "clean status" GraphQL error into an actionable
message recommending direct merge.
* Recommend Tailscale when the remote Orca runtime is unreachable
When a remote-runtime connection fails (RemoteRuntimeClientError "Could not
connect to the remote Orca runtime."), append an actionable Tailscale hint to
the user-facing error, branched on whether the endpoint is already on a tailnet:
- Non-Tailscale endpoint: recommend connecting both devices over Tailscale and
pairing with its Tailscale address, with a download link.
- Tailscale endpoint (*.ts.net or 100.64.0.0/10): point at the real causes —
server offline on the tailnet, or Funnel reverted to tailnet-only — and note
that already-paired devices reconnect without re-pairing.
Applied at the desktop transport chokepoint (status probe, in-use calls, and
subscriptions — connection failures reject, so the hint is applied to the thrown
error, not just ok:false responses) and at the web client's connect/timeout
sites. New pure shared helper mirrors withMacTailscaleDnsHint.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Address review: scope CGNAT hint to IPv4 literals, track re-paired endpoint
- isTailscaleEndpoint: gate the 100.64.0.0/10 check on a full IPv4 literal so
DNS names like 100.64.0.1.example.com no longer get tailnet-specific advice.
- callRuntimeEnvironment: capture the endpoint the queued closure actually used,
so a re-pair between enqueue and dispatch can't append the wrong hint.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Recognize Tailscale IPv6 endpoints and trailing-dot FQDNs in hint
The remote-runtime Tailscale hint classified IPv6 Tailscale nodes
(fd7a:115c:a1e0::/48) and trailing-dot FQDNs as non-Tailscale, so a
user already reaching their server over Tailscale by IPv6 literal was
wrongly told to 'connect both devices to Tailscale'. Pairing endpoints
can carry bracketed IPv6 literals (resolvePairingEndpoint), so this is
a reachable path. Normalize the extracted host (strip brackets and the
trailing FQDN dot) and add an IPv6 ULA-range check.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: s546126 <268420947+s546126@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
Register Helium (imput, bundle id net.imput.helium) so it is auto-detected
and importable from the picker on macOS like Chrome/Edge/Arc/Brave/Comet,
instead of only via the "From File..." JSON path. Reuses the existing macOS
Chromium decryption path unchanged.
Helium quirks (verified on a real install): its Keychain entry is service
"Helium Storage Key" / account "Helium" (not the usual "<Browser> Safe
Storage"), it stores data under its bundle id, and it keeps cookies at the
legacy <Profile>/Cookies path. Mac-only for now; Windows/Linux data dirs are
unverified so winRoot/linuxRoot are omitted and the source defaults off there.
Claude-Session: https://claude.ai/code/session_01SZzX6ktZaaCUg5PWnzniuC
* Support respawn-pane in Claude Agent Teams tmux shim
Claude Code's pane backend spawns each teammate in two steps: it
`split-window`s a holding pane running `cat`, then `respawn-pane -k`s
that pane with the real teammate command. Orca's tmux dispatcher had no
`respawn-pane` case, so every teammate spawn failed with
`tmux: unsupported command: respawn-pane` and the real command was
dropped — agent teams were completely broken in Orca on current Claude
Code (2.1.x).
Honor respawn-pane by closing the placeholder terminal and re-splitting
from the pane's original origin/direction with the real command, keeping
the fake pane id stable so later send-keys/kill-pane/list-panes still
resolve. Panes now remember how they were split for faithful recreation.
Pure pane geometry/format helpers move to a sibling module to keep the
dispatcher within the 300-line cap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* respawn-pane: create replacement before closing placeholder
Address review: closing the placeholder before the replacement split
succeeded could leave the fake pane id registered against a dead handle.
Split first; on cleanup failure, discard the new split and keep the
placeholder registered so send-keys/kill-pane/capture-pane still resolve.
Adds a regression test covering a failed respawn split.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* Add worktree labels for localhost ports
* Fix localhost label test fixtures
* Extend localhost worktree labels to agents
* Address localhost label review feedback
* Remove localhost label page injection; stream responses untouched
Drop the title/favicon HTML injection from the localhost label proxy.
The proxy now only relabels the hostname and pipes responses straight
through, so app CSP/cookies/bodies are preserved and large/streamed
responses are no longer buffered in memory.
- Normalize wildcard bind hosts (0.0.0.0 -> 127.0.0.1, :: -> ::1) before
using them as a proxy connect target.
- Delete the favicon SVG generator and dead repoIcon/badgeColor plumbing.
- Remove orphaned LocalhostLabelMock i18n keys.
Co-authored-by: Orca <help@stably.ai>
* Harden localhost label proxy from review
- IPC register: restrict proxy target to loopback or a matching scanned
workspace port (close open-proxy/SSRF surface from untrusted renderer).
- Proxy: guard against ERR_HTTP_HEADERS_SENT on mid-stream upstream error;
add error/cleanup listeners on client request/response and upgrade socket.
- labelLocalhostUrl: fall back to the raw URL when the proxy rejects a
target (e.g. https) instead of throwing.
- Port label route: include worktreePath so button-open and terminal/CLI
paths produce the same label.
- Terminal OSC link hover: discard stale async tooltip results via a hover
token, matching the WebLinks path.
Co-authored-by: Orca <help@stably.ai>
* Match default-port advertised hosts in localhost label target check
Co-authored-by: Orca <help@stably.ai>
* Consolidate duplicated localhost label helpers
- Move the loopback host set, loopback-URL parser, and wildcard
connect-host normalizer into shared/localhost-worktree-labels.ts; proxy,
runtime, terminal link routing, and the IPC guard now share one copy.
- Extract the port -> repo -> worktree -> project label-route lookup into
workspace-port-localhost-label-selector.ts (a hook plus an imperative
resolver), replacing the block triplicated across the ports surfaces.
Co-authored-by: Orca <help@stably.ai>
* Extract command-code prompt-status seed to its own module
Keeps launch-agent-in-new-tab.ts under the max-lines limit after the
localhost-hint additions, without a lint disable.
Co-authored-by: Orca <help@stably.ai>
* Remove agent-facing localhost mechanism
Orca does not mutate user prompts or inject prompt snippets, so drop the
localhost-open agent hint entirely:
- Remove appendLocalhostOpeningHint / includeLocalhostOpeningHint and the
hint constant from tui-agent-startup; agent prompts are no longer rewritten.
- Remove the ORCA_LOCALHOST_OPEN env var from local agent terminals (it was
only discoverable via the now-removed hint).
- Remove the orca localhost label|open CLI commands, their workspacePorts RPC
methods, and the runtime labelLocalhostUrl/openLocalhostUrl methods.
The feature is now purely structural: the loopback label proxy plus the
ports-panel and terminal-link 'Open in Browser' paths, which surface a
clickable labeled URL without touching agent prompts.
Co-authored-by: Orca <help@stably.ai>
* Make localhost worktree labels opt-in (default off)
Serving a dev app under a different host than localhost:<port> can break
apps that bind cookies/sessions to localhost, so the feature should not
change existing users' Open-in-Browser behavior on upgrade.
- Default localhostWorktreeLabelsEnabled to false.
- Flip the gates to enable only when explicitly true (=== true / !== true)
instead of treating undefined as enabled.
- Update the setting switch to checked only when explicitly enabled.
- Drop the now-unused runtime store settings field.
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): converge post-spawn PTY size reconcile to fix split-mount column desync
Follow-up to #6644/#6649. Those added a post-spawn PTY reconcile but capped
it at a FIXED 12 requestAnimationFrames whose counter advanced even on frames
where the pane was unmeasurable or the split layout had not yet equalized. When
a tab MOUNTS with a split layout already present (a new worktree opened with the
side split panel on), the real narrow split width settles AFTER frame 12, so the
reconcile gave up while xterm had reflowed narrow and the PTY stayed pinned at
the wide spawn width. The corrective xterm onResize is dropped during the hidden
mount window (isRendererPtyResizeAuthoritative() is false), so process.stdout.columns
stayed wide and interactive TUIs (Claude Code) rendered garbled until a manual resize.
Extract the reconcile into pty-size-reconcile.ts with an authoritative-gated
convergence loop instead of a fixed frame budget:
- While the pane is hidden (onResize dropped), the reconcile is the SOLE corrector:
it keeps polling and forwarding every grid change (its transport.resize bypasses
the visibility gate). Hidden frames never advance the settle counter.
- Once visible AND stable for SETTLE_FRAMES, it hands off to the live
onResize/ResizeObserver path, which reliably catches any later reflow.
- Hard cap (MAX_FRAMES) guarantees termination; mobile-fit/locked frames are
skipped; the reconcile handle is cancelled on dispose.
Harness: pty-size-reconcile.test.ts (14 tests) drives the loop with a deterministic
frame scheduler; the desync-repro tests fail against the old 12-frame logic and
pass on the fix. Adds an e2e "MOUNTS with a split layout present" test.
Caveat: headless Electron does not reproduce this layout-settle-after-rAF race
(the existing golden e2e passes even against the old buggy logic), which is why
#6644/#6649 merged with green e2e yet the bug persisted. The unit test is the
real regression harness; the e2e tests are integration smoke.
Made with [Orca](https://github.com/stablyai/orca)
Co-authored-by: Orca <help@stably.ai>
* fix(terminal): re-assert PTY size on visibility resume to heal stubborn column desync
Follow-up within the same fix: the user reported "sometimes even resizing
doesn't fix it." Root cause beyond the mount-timing race — the renderer forwards
resizes fire-and-forget and dedupes on the size it THINKS it sent, but never
learns the PTY's actual size. A resize dropped main-side (the pane was hidden,
a mobile take-back resize-suppression window, or a provider no-op) leaves xterm
and the PTY silently diverged; a later same-cols layout fires no onResize, so it
never self-corrects.
Expose the PTY's last-APPLIED size to the renderer and re-assert on show:
- New read-only IPC pty:getSize -> ptySizes.get(id) (the size written only when
a resize actually lands or at spawn — the authoritative "what the PTY believes
it is"). Wired through preload (window.api.pty.getSize) + api-types.
- On visibility resume (noteVisibilityResume), the pane re-fits, reads the PTY's
real size, and re-asserts via forwardPtyResize ONLY on genuine drift — so no
spurious SIGWINCH on an already-synced resume (which would jar alt-screen TUIs).
Routed through forwardPtyResize so the authoritative/mobile gates are
re-checked at send time; remote-runtime PTYs (separate viewport channel) are
skipped; overlapping resumes coalesce to one query.
Also register pty:getSize in the registerPtyHandlers removeHandler cleanup block
so re-registration (macOS re-activate / new window) doesn't throw on a duplicate
ipcMain.handle, and make the pty IPC test mock throw on duplicate channels like
real Electron so this class of omission is caught going forward.
Tests: 7 resume-reassert cases (drift / match / null / remote-skip /
mobile-fit-skip / hide-during-hop / overlap-coalesce), all non-vacuous. Full
terminal-pane + pty IPC suites green (1494 tests); typecheck (web+node) + oxlint
clean; e2e desync specs pass against a fresh build.
Made with [Orca](https://github.com/stablyai/orca)
Co-authored-by: Orca <help@stably.ai>
* Stub PTY getSize API and skip redundant Wayland GPU sandbox tests
- Implement PTY `getSize` stub in `web-preload-api.ts` to satisfy API
requirements for the web-preload environment.
- Skip the unfixed Wayland GPU sandbox negative control test if the
target base branch already contains the sandbox workaround.
---------
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* Surface GitHub check suites awaiting approval to unblock merge
- Query the check-suites API endpoint to find suites with an
"action_required" conclusion, which are often workflows awaiting
"Approve and run" and do not have any associated check runs.
- Map the "action_required" status distinctly instead of treating it as
a standard failure or omitting it entirely.
- Update the UI to render these suites with a warning icon, a dedicated
"Action required" label, and a localized hint explaining that manual
approval is required on GitHub.
- Count "action_required" checks as failed/blocking when deriving overall
PR and task statuses so the UI does not report all checks passing.
* Enhance visibility and handling of action-required PR check suites
* Include check suite IDs in pending approval check names and URLs to
allow navigating directly to the specific workflow run.
* Add an "action required" count badge to PR dialog and page checks tabs.
* Prioritize action-required checks in the checks preview summary.
* Use correct check run state for the action-required fallback hint in
the right sidebar details panel.
* Add translations for the new status across all supported locales.
Machine translation rendered the abbreviation "PR" (pull request) as "relaciones públicas" (public relations) across 32 Spanish UI strings — e.g. "Reabrir relaciones públicas" (Reopen PR), "Crear relaciones públicas" (Create PR), "Abrir cheques de relaciones públicas" (Open PR checks).
Adds the missing `es` rule to LOCALE_PHRASE_FIXES. Because "relaciones públicas" is a real Spanish phrase (unlike the CJK-only ko/zh patterns 홍보/公关), the rule guards on the actual `PR`/`PRs` token via a new optional `whenEnMatches` RegExp guard in applyPhraseFixes, so it never fires on unrelated English that merely contains a "pr" substring (approve, preview, press). `whenEnMatches` is backward compatible — existing `whenEnIncludes` rules are unchanged.
Regenerates the 32 affected es.json leaves. Adds a vitest spec covering the rewrites and a negative case proving the token guard ignores genuine "public relations" strings.
* Reload working-tree combined diff views on external file changes
Combined diff views (e.g. "Changes" and "All Changes" tabs) display the
working-tree diffs for all modified files but do not match any single
file path. As a result, the file system watcher previously did not
notify them when individual files were updated.
Check for active working-tree combined diff tabs once per event payload,
and trigger a reload notification on file changes so the diff sections
refresh automatically when files are modified externally.
* Reload combined diff view when matching single-file tab is dirty
When an external file change occurs and the matching open file is dirty,
reloading the individual file tab is skipped. However, if a combined
diff view (like the uncommitted Changes tab) is open, it still needs
to be refreshed to reflect the external changes.
Ensure we schedule a debounced external reload for the combined diff
consumer even when there are dirty matching files.
* Clear stale agent identity when a pane is reused (codex vs claude)
When a terminal pane is reused for a different agent, its launchAgent
goes stale. resolveTabAgentFromSignals ignored the terminal title while
launchAgent was set and ranked the stale launch ahead of the live title,
so the tab icon and notifications kept showing the previous agent
(e.g. codex when claude is now running).
Extract the title->agent mapping into terminal-title-agent-type.ts and
let a live, explicit title override a stale launchAgent once the pane has
shown activity. Apply the same guard to notification dispatch so a stored
snapshot from a different agent is not reused for the rich notification.
Also add the missing MiMo Code title mapping.
Fixes#6355
* test(terminal-pane): align completion fixture with live agent identity
The working->idle completion test paired a stored codex snapshot with a
live '* Claude done' title. After the stale-identity guard, an explicit
Claude title correctly drops a mismatched codex snapshot, so the rich
notification no longer carried codex's prompt/tool fields.
Make the fixture self-consistent (snapshot agentType: 'claude') so the
test still verifies the rich completion snapshot flows through on
working->idle, matching the corrected dispatch behavior. The discard
path is covered separately in use-notification-dispatch.test.ts.
Refs #6355
* Harden agent notification snapshot identity guard
---------
Co-authored-by: brennanb2025 <brennanb2025@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
* refactor(settings): unify network-address picker across mobile and server-share
The 'Share this Orca server' form (Settings → Runtime Environments) had the
same uneven dropdown + always-visible custom-text-field layout the mobile
pairing screen used to have.
Extract a generic AddressPicker + CustomAddressDialog (validator and copy
injected) and use it from both surfaces:
- Mobile keeps its IPv4 / Tailscale *.ts.net grammar.
- Server-share gets a plain dropdown (incl. 'This computer') plus an
'Add custom address…' row opening a dialog that accepts host, host:port,
or a ws(s):// URL (new parseServerShareAddress validator + tests).
Collapses the server form's separate selectedAddress/customAddress state
into one, dropping the side-by-side text field. Muted (non-red) validation
hint, all strings localized (en/es/ja/ko/zh).
Co-authored-by: Orca <help@stably.ai>
* fix(settings): bound the server-share connection-address dropdown width
Removing the side-by-side custom field left the picker as flex-1, which
stretched the trigger across the whole card for a short value like
'This computer (127.0.0.1)'. Give it min-w-[240px] max-w-full so it sizes to
content and only a long custom URL grows it (then truncates within the card).
Co-authored-by: Orca <help@stably.ai>
---------
Co-authored-by: Orca <help@stably.ai>
Fixes#2434. Orca unconditionally advertised xterm's Kitty enhanced
keyboard protocol (vtExtensions.kittyKeyboard) to every pane, including
local native Windows ConPTY terminals. Several local Windows CLIs (e.g.
the Antigravity agy CLI) read the advertisement but do not decode CSI-u,
so once enhanced reporting is on they ignore Enter/Up/Down and other
navigation keys.
Add a terminal-keyboard-protocol gate that withholds the advertisement
only for a genuine local Windows ConPTY pane (reusing the existing
isLocalNativeWindowsConpty predicate), while SSH and macOS/Linux panes
keep enhanced reporting.
Co-authored-by: brennanb2025 <brennanb2025@users.noreply.github.com>