Commit Graph

7219 Commits

Author SHA1 Message Date
Jinwoo Hong 01929fde40
fix(ssh): open external host images from terminal links (#10323)
* fix(ssh): open external host images from terminal links

* fix(ssh): keep external file ownership host-scoped

* fix(ssh): reject blank external file owners

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-24 12:05:38 -07:00
github-actions[bot] 3dfbb10775 Update README downloads badge 2026-07-24 18:47:45 +00:00
github-actions[bot] 17959a22b8 Update README downloads badge 2026-07-24 12:47:46 +00:00
Mark Xian 1bd36ce04b
fix(github): align PR file diff order (#10081) 2026-07-24 02:10:30 -07:00
Neil 1367094bbc
fix(terminal): flush URL hover tooltip to pane bottom-left corner (#10351)
Move link-tooltip chrome into terminal.css so offsets cannot drift via
inline styles, and square the bottom-left corner so the hover preview
sits flush against the pane edge (Ghostty-style).
2026-07-24 01:50:55 -07:00
Neil 981653f27d chore: remove openspec folder 2026-07-24 01:04:58 -07:00
Brennan Benson e651fe91c6
fix(mobile): heal terminal input after ambiguous image-send delivery (#10325)
An image send whose text+Enter RPC ended 'unknown' (ack loss / path
cutover) collapsed to accepted=true, so the terminal was never marked
stale. When the Enter truly never landed, the already-pasted image path
sat on the input line and glued onto the next plain-text message.

Propagate the send outcome through handleNativeChatSendWithOutcome and
mark the terminal input stale on any non-accepted outcome; the next send
heals with Ctrl+U (a no-op when the message did land). Chips still clear
on 'unknown' to avoid a double-send on retry.
2026-07-24 00:47:20 -07:00
Kaynan Sampaio de Camargo d50ea090cf
fix(terminal): reveal Markdown links at target lines (#9518)
* fix(terminal): reveal Markdown links at target lines

* fix(terminal): scope line reveals to opened tabs

---------

Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
2026-07-24 00:39:37 -07:00
Yoel d1ccfcff40
fix(settings): normalize and validate branch prefixes (#7772)
* Normalize branch prefixes and flag invalid ones in settings

A custom branch prefix ending in a slash (e.g. "team/") produced a
double-slashed branch name like "team//feature" that git rejects, and
the raw check-ref-format error gave no hint that the prefix caused it.

- Normalize the configured prefix (trim whitespace, strip leading/
  trailing and duplicate slashes) in the shared branch-name builder so
  the common trailing-slash case just works, for local and SSH worktrees.
- Validate the prefix on the worktree-create path (computeValidatedBranchName)
  so a genuinely invalid prefix fails fast with a clear
  "update it in Settings -> Git" message instead of an opaque git error.
- Add a live BranchPrefixFeedback under the Branch Prefix setting: previews
  the resulting branch name, warns on invalid characters, and notes when a
  prefix collapses to none.
- Keep the background first-work rename on the non-throwing builder since the
  prefix is already validated at create time.

* Keep caret in place when editing the branch prefix

The custom branch prefix input was directly controlled by settings, but
updateSettings persists through an async IPC round-trip, so the value
updated a tick late and React re-assigned it, snapping the caret to the
end on mid-string edits. Drive the input from a local draft and only
adopt genuine external settings changes so the caret stays put (and fast
typing survives slow SSH round-trips).

Co-authored-by: Cursor <cursoragent@cursor.com>

* Return ReactNode from BranchPrefixFeedback

JSX.Element needlessly excludes null/string/number returns; ReactNode
keeps the component's return type from over-constraining future changes.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 00:39:32 -07:00
Neil 662d23f9b3
fix(readme): point French star badge to repo root (#10335)
Co-authored-by: Orca <help@stably.ai>
2026-07-24 00:39:12 -07:00
Neil eea1577ddd
fix(dashboard): close closed-agent retention race (#9008) (#10334)
Co-authored-by: Orca <help@stably.ai>
2026-07-24 00:39:06 -07:00
Brennan Benson ec04827b37
test(session): guard against workspace-reopen tab fork-bomb (STA-1111) (#10057)
* test(session): guard against workspace-reopen tab fork-bomb (STA-1111)

Relates to STA-1111 (already fixed on main by #6945).

The runaway-tab-on-reopen bug was fixed by #6945 (activeOrQueuedResumeClaimsProviderSession dedup guard) hours before the ticket was filed. Verified: disabling that guard makes tab count climb 1->2->3->4 across reopens; restoring it holds at 1. This adds a revert-sensitive regression test covering the created-agent and sleeping-resume reopen paths so it cannot regress.

Test plan: 2 new tests pass; fail if the #6945 guard is removed.

* test(session): isolate automatic resume replay coverage

* test(session): assert resumed tab identity stays stable
2026-07-24 00:36:50 -07:00
Brennan Benson 1b5db4bc2a
fix(window): reflow on macOS occlusion-reveal so the bottom bar is not clipped (#10056)
* fix(window): reflow on macOS occlusion-reveal so the bottom bar is not clipped

Fixes STA-2383.

On macOS the window is background-throttled while hidden; on occlusion-uncover only 'focus' fires and its handler runs webContents.invalidate() (the setSize jiggle is skipped to avoid SIGWINCH-ing terminals). invalidate() repaints but does not reflow, so the app-shell h-dvh root keeps a stale dynamic-viewport height and the StatusBar is clipped below the viewport ('no bottom bar'); a manual resize restores it.

Fix: renderer relays a genuine hidden->visible reveal (visibilitychange) to main via new ui.notifyWindowRevealed IPC; main runs the same proven forceRepaint. Occlusion-gated (no per-Cmd+Tab SIGWINCH regression), darwin-scoped, sender-guarded, cleaned up on close.

Test plan: vitest createMainWindow + web-preload-api green. Recommend on-device macOS occlusion QA before merge.

* fix(window): preserve user resizes during reveal repaint
2026-07-24 00:36:18 -07:00
Wooseong Kim 559f04d297
fix(daemon): gate agent startup cwd after safe default fallback (#10035)
createPtySubprocess asserted assertSafeAgentStartupCwd on the raw
opts.cwd before applying opts.cwd || getDefaultCwd(). An omitted cwd
was treated as root-like and threw even though the post-fallback home
default is safe — while LocalPtyProvider already gates the effective
cwd after fallback.

Compute requestedCwd first, then gate. Update the daemon unit test to
assert omitted-cwd agent launch uses the safe default (#9578).
2026-07-24 00:29:23 -07:00
Kaynan Sampaio de Camargo 69d05b6e24
fix(mobile): resolve permission args when a new session launches an agent (#8469)
The New Workspace flow built a bare launch command client-side and sent it as
`startupCommand`, so the host ran it verbatim and never applied the default
launch args. The first Claude session therefore started in manual mode, while
opening another Claude via the "+" tab (which sends the agent id and lets the
host resolve args) started with `--dangerously-skip-permissions`.

Send `startupAgent` from every client-built create path (blank, reuse-branch,
and new-branch) so the host resolves the launch command, args, env, and
host-shell quoting through the same path the "+" new-tab and CLI use. The
work-item path already delegated via `startupDraft`. Custom `agentDefaultArgs`
are now honored on all paths.

Adds a shared `agentLaunchCreateFields` helper and removes the now-unused
client-side command map, which had also drifted from the canonical launch
commands for continue, hermes, command-code, kiro, and mistral-vibe.

Claude-Session: https://claude.ai/code/session_014iufZnQwPD2obYuvdahjaE

Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
2026-07-24 00:29:19 -07:00
scokeepa 6997bc40ab
fix(usage): guard web client against undefined usage scan state (#10073)
The claude/codex/openCode usage store slices read `scanState.enabled`
directly off `window.api.<provider>Usage.getScanState()`. In the web
client that usage IPC is not bridged, so the preload fallback proxy
resolves those calls to `undefined`, and enabling usage tracking from
Settings -> Stats & Usage throws
`TypeError: Cannot read properties of undefined (reading 'enabled')`
(reproduced live against `orca serve` v1.4.150; present on main too).

Guard the getScanState()/setEnabled() seams in all three slices so an
absent scan state degrades to a graceful no-op instead of crashing.
Desktop behavior is unchanged (a real ScanState is always truthy).

Adds a regression test that stubs the web-client fallback (every call
-> undefined) and asserts fetch*/enable* no-op without throwing for all
three providers.

Co-authored-by: ECO2G Migration <cmeia.ai02@cmeia.co.kr>
2026-07-24 00:28:52 -07:00
Wooseong Kim dc18ba9cda
fix(win): taskkill agent PTY descendant trees on stop (#10100)
* fix(win): taskkill agent PTY descendant trees on stop

Windows agent teardown previously degraded to shell-only kill because
descendant snapshot is POSIX-only. Orphaned claude/codex/MCP children
kept worktree cwd handles open and blocked worktree remove.

Use taskkill /T /F on the PTY root in killWithDescendantSweep (daemon +
local agent shutdown) so the ConPTY tree is cleared before teardown.

Fixes #10004

* fix(win): bound taskkill with timeout and windowsHide

Prevent a wedged taskkill from delaying killRoot, and hide the console
flash during agent PTY tree teardown (CodeRabbit on #10100).
2026-07-24 00:27:40 -07:00
Wooseong Kim 1f29a33b2a
fix(sidebar): do not sticky-pin Project header without mounted geometry (#10090)
During scrollToIndex/reveal, rangeStartIndex can advance before TanStack
mounts the candidate Project row. Returning that unmounted index made a
Project sticky paint over the Host card in multi-host views. Prefer a
previous mounted sticky (or none for the group tier) until geometry exists.

Closes #10088
2026-07-24 00:26:44 -07:00
JeongUk Park fc181a8496
fix(i18n): restore count separators in terminal theme picker for CJK locales (#9935)
The theme picker count row concatenates "Showing {count}" directly with
the " of {{value0}}" fragment. The ko/ja/zh translations dropped the
fragment's leading separator, so the shown and total counts fused
(e.g. Korean rendered "표시 중 3030 중" instead of "표시 중 30/30").

Restore a slash separator for the total-count fragment and the leading
space for the search-match fragment in ko/ja/zh, in both the runtime
catalogs and the key-override sources so catalog regeneration keeps the
repaired values. Add a regression test covering both fragments.

🤖 Generated with Claude Code
2026-07-24 00:26:39 -07:00
Taras Kornichuk e3cc08f185
fix(worktree): don't flag a disabled sparse checkout as sparse (#9922)
`git sparse-checkout disable` restores the full working tree and sets
core.sparseCheckout=false, but deliberately leaves <gitdir>/info/sparse-checkout
in place so the checkout can be re-enabled with the same patterns.
detectSparseCheckout treated the mere presence of that pattern file as "sparse",
so a fully-populated worktree kept showing the sparse badge and the misleading
"Partial checkout. Files outside these paths are not on disk." tooltip.

Gate the fast-path fs.stat behind a config read that confirms core.sparseCheckout
is actually enabled (shared repo config or per-worktree config.worktree, honoring
git's precedence). The config read runs only when a non-empty pattern file
exists, so it does not reintroduce the per-poll subprocess fan-out PR #1290
removed, and it reads git's config files directly (no subprocess).

Adds a real-git regression test (enable -> disable leaves file -> not sparse) and
unit tests for the git-config boolean parser.
2026-07-24 00:26:34 -07:00
Kevin Espiñeira a4f42ad427
fix(terminal): make Ctrl+V / Cmd+V paste work in the HTTP web client (#9900)
* fix(terminal): make Ctrl+V paste work in the HTTP web client

navigator.clipboard only exists in secure contexts, so the web client
served over plain HTTP (e.g. a LAN address) read an empty clipboard and
Ctrl+V silently did nothing: the keydown handler preventDefault-ed the
chord and suppressed the native paste event whose clipboardData is the
only clipboard access available there.

When the async clipboard reader is unavailable in the web client, let
the chord's native paste event fire and feed its clipboardData text
through the existing paste pipeline (size limits, bracketed-paste
handling and error toasts included).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTjQWLg4wy1CgmcZKmGAuN

* fix: address review finding (bug-bash takeover)

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-24 00:26:30 -07:00
Tingde Liu 1ace87c155
fix(wsl): route global CLI fallbacks to user-pinned terminalWindowsWslDistro (#9734) 2026-07-24 00:26:25 -07:00
Kaynan Sampaio de Camargo b5ae776c31
fix(terminal): clear stale search highlights (#9519)
Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
2026-07-24 00:26:21 -07:00
developerKYH a90ec540f2
fix(settings): persist the last IME syllable when leaving the display-name field mid-composition (#9517)
RepoSettingsDraftInput holds unconfirmed IME text in local draft state and only
persists on compositionend (so the async store echo cannot cancel the composition).
If the user types a Hangul syllable and immediately navigates back out of project
settings while it is still composing, no compositionend fires — the last syllable
stays in the draft and never reaches the store, so the project's display name loses
its final character. Users have to click back into the field or press Enter (both
force compositionend) to make it stick.

Flush the visible draft on blur and on unmount, guarded by lastPersistedRef so it is
a no-op when a keystroke or compositionend already persisted that value. The flush
closure is published from an effect (post-commit) so a discarded concurrent render
cannot leave the cleanup pointing at uncommitted draft state.

Adds blur / unmount / no-double-persist / no-op regression tests to the component's
existing suite.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 00:26:16 -07:00
Gideon cb19e79504
fix(ai-vault): resume Claude sessions from their start directory (#9499)
The AI Vault session scanner recorded a session's cwd by overwriting it with
every transcript record that carried one, so a session that changed working
directory mid-run ended up with its last-seen cwd. That value drives the resume
command (cd <cwd> && claude --resume <id>) and the history panel's grouping and
filtering.

For Claude this breaks resume: transcripts live under
~/.claude/projects/<slug-of-start-dir>/, and claude --resume <id> only searches
the project dir derived from the current cwd, so resuming from the drifted cwd
fails with "No conversation found". Capture the first-seen (start) cwd instead,
which transcripts write up front; this fixes resume, grouping, and filtering at
once. updateLatestLocation is only used by the Claude parser, so no other agent
is affected.

Fixes #9361
2026-07-24 00:26:11 -07:00
Rod Boev 26e48e4159
fix(relay): honor the remote OpenSSH login shell for Windows SSH terminals (#9455)
* fix(relay): honor the remote OpenSSH login shell for Windows SSH terminals (#9327)

* Prove OpenSSH DefaultShell fallback stays safe on bad registry reads
2026-07-24 00:26:07 -07:00
David Whatley 5a1ca24262
fix(status-bar): tolerate missing provider snapshots (#9408) 2026-07-24 00:26:02 -07:00
kazu-42 53222cc9c1
fix(terminal): wait for shell readiness on Codex account restart (#9365) 2026-07-24 00:25:58 -07:00
Avery Bloom cd28da13f4
fix(orchestration): treat ask as a long-poll so it survives the 30s socket idle wall (#9351)
orchestration.ask blocks server-side until a reply lands or its timeout
(default 600s) elapses, holding the RPC open — but isLongPollRequest never
classified it as a long-poll. So the keepalive that resets the 30s
RUNTIME_RPC_SOCKET_IDLE_TIMEOUT_MS was never armed, and any ask left
unanswered for 30s died with a misleading runtime_unavailable ("The Orca
runtime closed the connection"), regardless of --timeout-ms. The same
omission left the handler's abort signal unwired (it is only passed for
long-polls), so the client-disconnect release path guarded by
signal?.aborted was dead code.

Add orchestration.ask to isLongPollRequest so it gets the keepalive, the
abort signal, and long-poll admission. The client already extends its
per-call socket timeout for ask (handlers/orchestration.ts passes
timeoutMs + 5s at the call site), so only the server-side classification
was missing.
2026-07-24 00:25:53 -07:00
Yunqian Fan 143d2232bb
fix: reconcile a stale activeWorktreeId against live worktrees on hydration (#9344)
The web client persists its workspace session (activeWorktreeId,
lastVisitedAtByWorktreeId, ...) in localStorage and, unlike the main-process
Store, gets no load-time orphan GC. `pruneLastVisitedTimestamps` already drops
stale focus-recency entries on hydration, but the persisted `activeWorktreeId`
pointer is not reconciled — so a pointer to a worktree the server no longer
reports lingers (the main-process path clears it via removeWorkspaceSessionOwner
when a repo is removed; the web has no equivalent), and can surface a phantom /
duplicate workspace that survives reloads.

Extend the hydration reconcile to also clear `activeWorktreeId` once its repo is
hydrated and the worktree is confirmed gone, mirroring the existing per-repo
defer rule (a not-yet-hydrated repo, e.g. SSH pre-connect, keeps its pointer).

Co-authored-by: fanyunqian.1 <fanyunqian.1@bytedance.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 00:25:49 -07:00
Yunqian Fan c2371c0cd8
fix: don't hydrate a headless mobile session for a repo that no longer exists (#9343)
`hydrateHeadlessMobileSessionTabsFromWorkspaceSession` iterates
`workspaceSession.tabsByWorktree` with no repo gate. Those keys are
`${repoId}::${path}` and are not pruned when a repo disappears from this
client's view, so a stale key re-materializes a phantom "unknown"/duplicate
workspace with no live repo behind it, on boot, with no `session-created` event.

Skip entries whose parsed repoId is not in the live `repos`; leave unparseable
keys alone (conservative). Defensive complement to the delete-path (#9025) and
load-time (#9200) fixes — this closes the mobile/headless hydration path.

Co-authored-by: fanyunqian.1 <fanyunqian.1@bytedance.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 00:25:44 -07:00
Yunqian Fan d8499fae16
fix: don't mint worktreeMeta from a sidebar sort-order snapshot (#9342)
`worktrees:persistSortOrder` (ipc/worktrees.ts) and `persistManagedWorktreeSortOrder`
(orca-runtime.ts) call `store.setWorktreeMeta(id, { sortOrder })` for every id the
renderer sends. `setWorktreeMeta` has no repo-existence check, so a stale id the
client still lists — e.g. a removed repo's `${repoId}::${path}` that lingers in the
renderer's order — gets a brand-new `worktreeMeta` entry minted on every sidebar
snapshot, resurrecting an orphan/duplicate workspace on the next launch.

A sort-order snapshot must only reorder worktrees that already exist, never create
one. Guard both call sites with `getWorktreeMeta` so absent ids are skipped.

Co-authored-by: fanyunqian.1 <fanyunqian.1@bytedance.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 00:25:39 -07:00
Mark Xian dd642cb3e3
fix(rate-limits): refetch claude usage when the last live Claude PTY exits (#9325)
The managed token refresh is deferred while a live claude session owns
the credentials, but nothing reacted to the last live PTY exiting: the
deferred result is a terminal-classified error whose retry lane backs
off to the 15-minute cadence and is window-focus-gated, so the usage
panel stayed on "Waiting for Claude session" long after the blocker was
gone.

Notify on the live-PTY 1->0 transition (covering both markClaudePtyExited
and confirmSeededClaudeLivePtys releasing the last dead seeded id) and
force a claude-only refetch iff the current state is deferred.

Closes #9324
2026-07-24 00:25:35 -07:00
Mark Xian 48a258d502
fix(win): stop shipping duplicate broken orca.cmd shim in app.asar (#9123)
The Windows CLI shim is delivered via extraResources to
resources/bin/orca.cmd, beside the native resources/bin/orca.exe, and
resolves the launcher adjacent to itself (%SCRIPT_DIR%orca.exe) — which
works.

But nothing in `files` excluded resources/win32/, so its source copy was
also packed into app.asar and then extracted by asarUnpack:['resources/**']
to app.asar.unpacked/resources/win32/bin/orca.cmd. That duplicate has no
adjacent orca.exe, so invoking it fails with "Unable to locate the native
Orca CLI launcher", breaking orchestration skills that reach for the
unpacked shim.

Exclude the win32 shim source tree from app.asar so only the working
extraResources copy ships. Add a regression guard to the electron-builder
config test.

Closes #7351
2026-07-24 00:25:30 -07:00
Yunqian Fan 253ccd29f5
fix: prune workspace session state when a project is removed (#9024) (#9025)
* fix: prune workspace session state when a project is removed

removeProject → pruneWorktreeStateForRepo cleared worktreeMeta, lineage,
and workspace lineage, but left the removed repo's worktrees behind in
workspaceSession (lastVisitedAtByWorktreeId, sleepingAgentSessionsByPaneKey,
tab state, …) and in every workspaceSessionsByHostId partition.

Those dangling references caused the runtime to treat the deleted repo's
worktrees as recently-active on the next launch and re-materialize their
worktreeMeta. With no owning project left, the UI rendered them as an
orphaned "unknown" workspace that returned after every restart.

Reuse the existing removeWorkspaceSessionOwner cleanup (already used by
removeFolderWorkspace and deleteProjectGroup) against the legacy session
blob and each per-host partition, collecting owner keys before the
worktreeMeta delete loop so host classification still works.

Fixes #9024

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: scope session cleanup to the removed host in removeProjectForHost

The workspace-session cleanup applied every collected owner key to the legacy
(local) session blob AND every workspaceSessionsByHostId partition. Owner keys
are `${repoId}::${path}` and carry no host, so a host-scoped removal
(removeProjectForHost) of one host wrongly wiped a surviving host's session for
a shared repo id/path — discarding its lastVisitedAt, tabs, sleeping-agent
state, and active-worktree pointer.

Scope the session prune to the removed host: prune the legacy blob only when the
target host is local (or on a full removeProject where hostId is null), and
prune only the matching workspaceSessionsByHostId partition for a non-local
host; a full removal still clears every partition. Collect session owner keys by
`${repoId}::` prefix (not belongsToHost, which is worktreeMeta-host-classified)
so a partition-only key is still prunable.

Adds regression tests for a shared repo id + path across local and an SSH host,
covering removeProjectForHost on the SSH host (local session survives) and on
the local host (SSH session survives).

Addresses review feedback on #9024.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: cover third surviving host in removeProjectForHost session prune

Add a regression case where a shared repo id + path exists on local and two
SSH hosts. Removing one non-local host must prune only that host's session
partition, leaving both the legacy/local session and the other surviving SSH
host's partition intact. Locks in that the host-scoped cleanup never touches a
non-targeted third partition (per review feedback on #9024).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* perf: prune workspace session in a single clone+scan per partition

Project removal collected every owner key to prune, then called
removeWorkspaceSessionOwner once per owner AND per host partition. Each
call structuredClones and scans the entire session, so removal was
O(worktrees x hosts x session size) in full-session clones on the main
thread.

Add removeWorkspaceSessionOwners(session, ownerKeys) which clones once
and scans each collection once for the whole set, and route
pruneWorktreeStateForRepo through it. The per-owner O(1) field deletes
and the single-scan pane-key passes are factored into shared functions
so removeWorkspaceSessionOwner keeps identical behavior for its other
callers. No behavior change.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: PannenetsF <fanyunqian.1@bytedance.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-24 00:25:26 -07:00
Mark Xian eefded2a04
fix(terminal): stop native middle-click paste inserting twice on Linux (#8993)
* fix(terminal): stop middle-click primary paste inserting twice on X11

When "Middle-click Paste from Selection" is enabled, the integrated
terminal reads the X11 PRIMARY selection on mousedown and writes it to
the PTY itself. It calls preventDefault on the mousedown, but Chromium's
native X11 middle-click primary paste fires on mouse release regardless,
landing in xterm's helper textarea, which xterm then forwards to the PTY
a second time. The result is the selection pasted twice.

The global primary-selection hook already suppresses the follow-up native
paste, but only for editable DOM targets it owns via a pending-target
handle; it deliberately excludes xterm, so the terminal path had no
suppression at all.

Arm a short shared suppression window when the terminal handles a
middle-click, and have the global hook's capture-phase beforeinput/paste
suppressor honor it. This swallows the single native paste event so the
selection reaches the PTY exactly once. Ctrl+Shift+V and right-click
paste are unaffected: they use the CLIPBOARD and never emit a native
primary-paste event.

Closes #8860

* docs(terminal): clarify native middle-click paste suppression

* fix(terminal): scope primary-selection native-paste suppression to Linux xterm

Gate the armed native-paste suppression window to Linux (X11 primary-selection
path) and scope it to xterm's helper textarea so unrelated document pastes and
non-Linux platforms are never affected. Re-arm on auxclick for slow releases.

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-24 00:25:21 -07:00
morluto 9ced27eca8
fix(onboarding): skip Computer Use setup when macOS helper app is unavailable (#8951)
When the macOS Computer Use helper app is missing (e.g. a dev build that
never ran `pnpm build:computer-macos`), getComputerUsePermissionStatus
reports helperUnavailableReason alongside all permissions set to
not-granted. The onboarding runner only checked the permissions, so it
called openSetup, which throws a RuntimeClientError in the
computerUsePermissions:openSetup IPC handler and logs an alarming error
to the main process console.

Guard on helperUnavailableReason first: surface the reason as a warning
and skip openSetup, so onboarding degrades gracefully instead of
triggering an IPC handler error.
2026-07-24 00:25:17 -07:00
Kaynan Sampaio de Camargo deb2b50e71
fix(sidebar): revalidate setup-script prompt when the hook becomes effective (#8752) (#8893)
The "Add a setup script" card cached its inspection result and only re-ran
on activeRepo/settings/sidebarOpen/dismiss/retry changes. A shared orca.yaml
setup hook that became effective on disk — edited externally, or run during
worktree creation — left the stale prompt visible until a full sidebar reopen.

Extract the revalidation into useSetupScriptPromptRevalidation, which
re-inspects on window focus (external edits / terminal hook runs) and when a
worktree of the repo activates while the prompt still shows no effective setup.

Claude-Session: https://claude.ai/code/session_01C8RPZ1mhUCMWcojgD6jLaN

Co-authored-by: kaynan <kaynan.camargo@terceiro-sky.com.br>
2026-07-24 00:25:12 -07:00
Rod Boev 4e670d3e4c
fix(terminal): stop wheel replay when mouse reporting is disabled (#8616) 2026-07-24 00:25:07 -07:00
Rod Boev 739fce5287
fix(agent-status): replay remote Codex startup snapshots (#7873)
* fix(agent-status): replay remote Codex startup snapshots

* fix(agent-status): move unattributed-track comment next to its call

The '// Why: ... track the adoption/routing failure separately' comment
was left above the new replay branch after the track() call moved into
the non-replay branch. Move it next to track('agent_hook_unattributed')
so the rationale sits with the code it explains.

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-07-24 00:25:03 -07:00
Yu Sun 2cbcf03b0f
fix: qualify ssh fallback worktree paths (#7764) 2026-07-24 00:24:58 -07:00
Rod Boev 6d39e49480
fix(ssh): accept GitHub restricted-shell SSH probes (#6988) (#7659)
* fix(ssh): accept GitHub restricted-shell SSH probes (#6988)

* fix: match first stderr line for GitHub restricted-shell probe (bug-bash takeover)

Co-authored-by: Orca <help@stably.ai>

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Co-authored-by: Orca <help@stably.ai>
2026-07-24 00:24:53 -07:00
Matteo Musacchio c1d2c4be08
Fix PowerShell worktree terminal cwd (#7435) 2026-07-24 00:24:48 -07:00
github-actions[bot] cda97cec41 Update README downloads badge 2026-07-24 07:10:19 +00:00
Brennan Benson efe996a007
ci(release-cut): add explicit version override to the cut dispatch (#10329)
* ci(release-cut): add explicit version override to the cut dispatch

Kind-based computation derives the next version from the latest *published*
stable. When a shipped stable is deleted/rolled back, the release list
regresses to the prior stable, so a `kind` cut recomputes a number at or
below the deleted one — stranding every client that already installed it,
since electron-updater only moves forward. The existing package.json floor
only recovers this when the deleted version's bump commit is on the ref
being cut, which a hotfix cut from an older RC ref does not carry.

Add an optional `version` workflow_dispatch input that lets a human assert
the exact target (e.g. leapfrog a deleted 1.4.154 to 1.4.155), bypassing
kind-based computation. The updater-safety gate (must exceed the latest
published stable) and the existing tag-collision recovery still apply.
Empty by default, and forced empty for scheduled cuts, so normal automation
is unchanged.

* ci(release-cut): let explicit version override the package-floor recovery

Per review: the package.json floor block can recover_unpublished_tag and
exit 0 before the explicit-version branch runs, hijacking an explicit
request to recover a floor tag instead — the exact rollback scenario the
override targets. Skip floor-tag recovery when EXPLICIT_VERSION is set;
latest_stable is still raised to the floor for the safety gate, and the
requested tag's collision recovery runs later.
2026-07-24 00:09:07 -07:00
BingZ 2cf41ab864
fix(mobile): keep terminal caret visible without focus (#10101) 2026-07-23 23:55:35 -07:00
Wooseong Kim 4274dbc48a
fix(linear): union filter options across every selected team (#10042) 2026-07-23 23:51:54 -07:00
Fazal Kadivar 34caad787c
fix(browser): unstick Ctrl+Tab switcher when opened from a focused browser guest (#9966)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 23:48:07 -07:00
余辉 fa09d6fd8e
fix(tasks): hide repos without remote identity (#9898) 2026-07-23 23:46:01 -07:00
Rod Boev 108a2ad41b
fix(cli): relativize absolute --path for file open and file diff before the runtime RPC (#9429) (#9824) 2026-07-23 23:43:15 -07:00