Commit Graph
8404 Commits
Author SHA1 Message Date
Neil c578f4e4e2 fix(e2e): restore the helpers the macOS key-remap spec imports (#13758)
#13314 landed terminal-macos-system-key-remap.spec.ts but its final commit,
"chore: drop non-mergeable IME e2e scratch files", deleted the three modules it
imports. The spec survived; terminal-ime-pane-arena, terminal-ime-cdp-composition
and terminal-ime-platform-policy did not.

Playwright resolves every spec before running any of them, so the unresolved
import is fatal for the whole run, not just that file: `playwright test --list`
on main reports "Total: 0 tests in 0 files". All ten scheduled E2E shards have
been failing at collection since, and the macOS system-key-remap coverage the PR
was for has never run once.

No typecheck project includes tests/, which is why this stayed invisible outside
the E2E lane.

Restored from the commit before the drop. pane-arena and platform-policy come
back verbatim; cdp-composition keeps only the four entry points this spec uses,
since the rest served specs that were not merged. Its doc comment is retargeted
accordingly — the composition-session drivers are the part that went.

Collection is back to 528 tests in 222 files and all six remap tests pass.
2026-08-11 00:10:40 -07:00
NeilandOrca 200b3e53ae perf(renderer): keep the repos array identity across no-op refetches (#13744)
* perf(renderer): keep the repos array identity across no-op refetches

reconcileFetchedRepos deliberately returns the previous array when a refetch
changes nothing, so identity-keyed memos can skip work. Two later steps in the
same chain copied unconditionally and threw that identity away:

- reconcileReadoptedSshRepoRows spread the input on its no-prune path, which is
  the common case.
- applyManualRepoOrder allocated a fresh array even when the saved order moved
  nothing.

Both now return the input when they change nothing, so state.repos stays
referentially stable through fetchRepos, fetchRuntimeEnvironmentRepos,
fetchReposForAllHosts, and hydratePersistedUI.

Return type stays Repo[] with the same cast reconcileFetchedRepos already uses;
all four call sites only read the result.

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

* refactor(renderer): make the store repos array readonly at the type level

Preserving the repos array identity means handing callers the same array that
is live store state, which previously relied on `as Repo[]` casts to launder
readonly inputs back into a mutable field. A cast is a footgun: the next person
to add a .push or .sort corrupts store state with no type error.

Widen RepoSlice['repos'] to readonly Repo[] and propagate honestly. Consumers
that only read take readonly Repo[]; genuine local accumulators are annotated
Repo[] and built from copies.

Removes all four pre-existing `as Repo[]` casts in the reconcile chain
(repo-identity-reconcile, superseded-ssh-repo-rows, manual-repo-order x2) —
this lands with fewer casts than main has today.

Type-only change; no runtime behavior differs.

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

* fix(renderer): compare nested repo fields so reconciliation actually fires

Preserving the repos array identity was inert. reconcileFetchedRepos compares
repo fields with !==, but every repo the renderer receives carries nested
records that are new objects on every fetch:

- main's hydrateRepo unconditionally rebuilds hookSettings for every repo,
  even a pristine one (persistence.ts:5109)
- IPC structured-clone (and the JSON hop for SSH/runtime hosts) reclones
  gitRemoteIdentity, upstream, repoIcon, and the path arrays

So every repo compared unequal, `identical` went false on every refresh, and
the array was rebuilt regardless of the copies removed in the parent commit.

Compare nested plain records structurally instead. They are small sanitized
values; anything non-plain falls back to reference equality.

The end-to-end test previously passed for a fixture-only reason: its repo had
five scalar fields and the mock returned the same object both calls, the one
shape production never produces. It now uses a production-shaped repo and
fails without this change.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-11 00:08:19 -07:00
BingZandOrcaWin bdebe53568 fix(settings): paste bash-native skill setup under WSL PTY (#13710)
* fix(settings): paste bash-native skill setup under WSL PTY

WSL worktree setup terminals force wsl.exe even when shellOverride is
powershell.exe. Auto-pasting the PowerShell `& { wsl.exe ... }` wrapper
into bash fails with a leading-& syntax error (#13305). Rewrite that
wrapper to a bash login-shell script for setup-terminal paste only;
clipboard copy still keeps the PS host wrapper for manual use outside Orca.

* fix(settings): align skill paste with resolved PTY shell

* fix(onboarding): keep shell preparation out of render

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-11 00:07:49 -07:00
Brennan Benson 3ed4dc484f fix(native-chat): scope persisted options to chat launches (#13675)
* fix(native-chat): defer to Codex model picker defaults

* fix(native-chat): settle Codex picker ownership

* fix(native-chat): record typed options after submit

* fix(native-chat): verify typed option submission

* perf(native-chat): skip option probe for chat sends

* perf(native-chat): scope verified sends to Codex

* fix(native-chat): require standalone picker command

* fix(native-chat): scope launch options to chat view

* fix(native-chat): align smart folder launch mode
2026-08-10 23:51:18 -07:00
Brennan Benson 915ee50cc2 fix(ui): rename Caffeinate Auto mode to Agent (#13751)
* fix(ui): rename caffeinate auto mode to agent

* fix(ui): center caffeinate radio indicator

* fix(ui): center caffeinate indicator within option
2026-08-10 23:50:41 -07:00
Brennan Benson 4dcb410982 docs: remove restored shell validation report (#13759) 2026-08-10 23:49:38 -07:00
Brennan Benson 7250fde148 fix(codex): repair hook trust before restored shells reconnect (#13745)
* fix(codex): reconcile hooks for restored shells

* docs: move restored shell validation report

* perf(codex): gate retained pane inventory
2026-08-10 23:47:32 -07:00
Neil 0345d71214 refactor(renderer): split oversized TabBar module (#13739) 2026-08-10 23:43:10 -07:00
Brennan Benson 063022f62d fix(native-chat): open composer pickers upward (#13754) 2026-08-10 23:42:46 -07:00
Neil fdaafc93dd refactor(renderer): split SettingsFormControls below max-lines limit (#13747) 2026-08-10 23:37:40 -07:00
Jinjing c1e75477f3 Fix static analysis page stuck in loading state (#13674)
* Fix static analysis page stuck in loading state

- Bound check-details requests with 30s timeout, matching remote RPC budget
- Track request IDs to discard stale responses when context changes
- Propagate githubRepository through store and components for proper routing
- Add retry button for failed check-details loads
- Improve accessibility with ARIA labels for loading and error states

* Fix static analysis page stuck in loading state

When an open check-details tab's repository is removed, the loading
state would continue indefinitely because the fetch was still being
triggered. Prevent the fetch call in this scenario to unblock the UI.
Also migrates translation keys to obfuscated identifiers.

* Fix static analysis page stuck in loading state

Add deadline-based timeouts and request ID tracking to prevent stale responses
from freezing the checks panel. Include abort signal propagation throughout the
request chain and provide retry UI for failed check details loads.

* fix(checks): prevent loading state from getting stuck on retry

- Consolidate mount checks into a helper function
- Details now clear when a new request begins
- Add i18n strings for retry status
2026-08-10 23:11:45 -07:00
Neil 03f471d328 perf(runtime): coalesce project lineage refreshes (#13638) 2026-08-10 22:58:44 -07:00
1e22befe17 fix(sidebar): close the workspace rename editor opened by the shortcut (#13729)
* fix(sidebar): close the workspace rename editor opened by the shortcut

The workspace.rename shortcut opened the editor with setEditing, while
every other transition went through setEditingMode, which also mirrors the
flag into editingRef and guards on it. After a shortcut-opened edit the ref
still read false, so Escape, commit, and blur all returned early and the
editor stayed on screen until the card unmounted. The borderless sidebar
editor gives no sign it is still live, so the row looked like a finished
rename.

The editing element also took its React key from the display name and the
unread flag. Neither is an edit, but both moved the key, so React remounted
the input and the ref callback re-ran focus and select over a half-typed
name. That half was never shortcut-specific: the double-click and hovercard
editors lost typed text the same way.

Remove editingRef so the editing state is the only source of truth, route
both entry points through a single openRenameEditor, and keep the key on
the rendered title where remounting is how truncation gets measured again.

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

* fix(sidebar): guard rename editor transitions

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinwoo-H <Jinwoo-H@users.noreply.github.com>
2026-08-10 22:53:58 -07:00
Neil ee7e743813 perf(orchestration): skip redundant federation acknowledgments (#13671) 2026-08-10 22:51:33 -07:00
NeilandOrca 23c803a1a6 perf(renderer): scope batched open-file reconciliation by worktree (#13748)
Every snapshot in a batch scanned the whole openFiles array three times and did
a linear find per editor tab, so a reconnect paid for open files those snapshots
never touched. Bucket open files by worktree for the duration of a batch, skip
the global rebuild when a snapshot has nothing to drop or mirror, and retarget
the index at the array each snapshot produced.

Per-snapshot semantics are unchanged: openFiles still flows through each patch,
so the equality bail is still evaluated per snapshot against the current array.
An earlier draft deferred that bail to the end of the batch, which let the batch
keep pre-batch file objects that sequential reconciliation rebuilds; the two
regression tests here pin both cases.

1,200 workspaces, 3,000 unrelated open files: no workspace with editors
99.7ms -> 3.1ms, 5% with editors 105.3ms -> 7.7ms. Where every workspace has
editors the array genuinely changes each snapshot, so the rebuild remains
(113.9ms -> 84.2ms).

Co-authored-by: Orca <help@stably.ai>
2026-08-10 22:21:06 -07:00
NeilandOrca 1928ca501e perf(renderer): unmount closed setup guide content (#13546)
* perf(renderer): unmount closed setup guide content

* fix(renderer): keep setup-guide progress live through the close linger

Dropping shouldRefreshCoreState on close disabled skill discovery and
computer-use permission state while the dialog was still fading out, so
'Agent capabilities' visibly un-completed mid-animation. Mirrors the
paletteStatusInputsActive guard from the worktree palette.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-10 22:04:56 -07:00
Brennan Benson 93e08115d0 fix(native-chat): type Codex slash commands (#13685)
* fix(native-chat): type Codex slash commands

* fix(native-chat): keep Codex skill sends pasted
2026-08-10 22:02:46 -07:00
NeilandOrca 9f8c22c7f9 perf(renderer): unmount closed workspace cleanup content (#13567)
* perf(renderer): unmount closed workspace cleanup content

* fix(workspace-cleanup): restore unconditional delete-state clear on batch error

The session extraction swapped the batch-level onError handler from an
unconditional clearWorktreeDeleteState to the conditional queued-only
helper. When the batch driver dies, nothing settles those rows later, so
a hung 'deleting' row stayed stuck in the sidebar and was permanently
excluded from retry by filterWorkspaceCleanupRemovalCandidates.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-10 21:59:04 -07:00
NeilandOrca aa50d8cee3 fix(ssh): release the relay-loss watcher before teardown mux writes (#13737)
* fix(ssh): release the relay-loss watcher before teardown mux writes

Cancelling the in-flight port scan emits rpc.cancel on the control lane.
If that lane is saturated, enqueue admission fails and the writer calls
fail() -> mux.dispose('connection_lost'), which fires the relay-loss
watcher during our own teardown and schedules a redundant relay redeploy.

teardownProviders already released the watcher first, but stopPortScanning
runs ahead of it and is what emits the frame. Hoist the release into a
named method and call it before stopPortScanning on all four teardown
paths.

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

* fix(ssh): hoist the watcher release above abort on every teardown path

Review follow-up. Two nits from the readiness pass:

- The "stop scanning before teardownProviders" comment had drifted onto
  releaseRelayLossWatcher(); move it back above the stopPortScanning()
  call it describes.
- Release the watcher ahead of abortController.abort() too. That signal
  reaches no mux request today, so this is not a live hole, but plumbing
  it into one would have silently reopened the bug on three paths. Making
  the release first keeps the invariant structural rather than incidental.

detachSshPtyConsumerRecovery stays first on the two detach paths, per the
existing synchronous-half-first rule.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-10 21:50:18 -07:00
Jinwoo Hong 25f7870c58 feat(github): support stacked pull requests (#13730) 2026-08-10 21:49:30 -07:00
NeilandOrca b44df2e9f1 perf(renderer): index GitHub resume lookups (#13698)
* perf(renderer): index GitHub resume lookups

* perf(renderer): skip the resume cache sweep publication when nothing changed

Every eviction helper already returns its input reference untouched when it
evicts nothing, so the opening sweep in refreshAllGitHub can compare identities
and return the previous state. Window resume then stops waking every store
subscriber on a no-op sweep.

Folds in the remaining unique optimization from #13711, which this PR
supersedes on the lookup-indexing side.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-10 21:42:27 -07:00
Neil 680a9d9bc5 perf(renderer): unmount closed Quick Open content (#13618) 2026-08-10 21:38:31 -07:00
Neil 2e5f067c2e perf(renderer): unmount closed Workspace Board content (#13619) 2026-08-10 21:33:50 -07:00
NeilandOrca 34c721fc2c perf(renderer): preserve unchanged remote mirror resources (#13683)
* perf(renderer): preserve unchanged remote mirror resources

* test(renderer): restore layout-value coverage and record the workspaceId dependency

Notes why browser page identity reuse is safe: browserPageEqual must keep
comparing workspaceId, since the removed-workspace page-list cleanup gates on
it. Also re-asserts the effective active leaf that the patch-only assertion
stopped covering.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-10 21:20:46 -07:00
OrcaWinandOrcaWin 9deb72f9ed fix(git): support Windows-linked worktrees in WSL projects (#13483)
* fix(git): support Windows-linked worktrees in WSL projects

* fix(git): harden WSL linked worktree routing

* fix(test): defer WSL routing filesystem access

* test(git): type WSL routing probe mock

* fix(git): retry transient WSL route probes safely

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-10 21:19:01 -07:00
Neil 2734bccd68 refactor(stats): share usage tracking pane shell (#13472) 2026-08-10 21:13:04 -07:00
Neil 4bb7e7d050 refactor(feature-wall): remove retired onboarding preview (#13489) 2026-08-10 21:07:41 -07:00
NeilandOrca a65e0c5c97 perf(renderer): keep remote snapshot batches linear (#13676)
* perf(renderer): keep remote snapshot batches linear

* test(renderer): cover the prefix-colliding sibling worktree

The sibling-mapping test used a worktree id that shares no prefix with WT,
so it passed against the prefix-scan it was meant to pin. Use an id prefixed
by WT's and drain the new mapping index in the leak counters.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-10 20:55:40 -07:00
Neil 0acf04a985 perf(ssh): cancel abandoned remote port scans (#13548) 2026-08-10 20:49:21 -07:00
Neil 5538584c74 perf(git): overlap status with conflict detection (#13529) 2026-08-10 20:48:00 -07:00
Neil e33863b2a9 refactor(onboarding): remove retired repository step (#13484) 2026-08-10 20:42:43 -07:00
Neil a944905451 refactor(onboarding): remove retired repository controller (#13492) 2026-08-10 20:42:12 -07:00
Neil 9796f7dc5f refactor(mobile): use shared GitHub Project sorting (#13459) 2026-08-10 20:41:34 -07:00
Neil a321ac3c8f refactor(mobile): use shared source-control decisions (#13453) 2026-08-10 20:41:31 -07:00
Neil e671c64dea refactor(utf8): centralize byte and chunk boundaries (#13445) 2026-08-10 20:41:01 -07:00
Neil af47fa10ac refactor(comments): share PR comment core (#13457) 2026-08-10 20:40:57 -07:00
Neil 6964f75cd0 refactor(renderer): share metadata list request lifecycle (#13524) 2026-08-10 20:40:26 -07:00
Neil 8c53e9e1b6 Share usage recent-session table (#13467) 2026-08-10 20:40:23 -07:00
Neil ef19809778 refactor(renderer): share usage provider slice lifecycle (#13527) 2026-08-10 20:39:51 -07:00
Neil fc9fd7208d refactor usage provider IPC plumbing (#13543) 2026-08-10 20:39:18 -07:00
Jinwoo Hong 665e0ead83 Fix repo-scoped Quick Commands across remote hosts (#13727) 2026-08-10 20:38:40 -07:00
Neil 65e2b5b598 refactor(usage): share provider store lifecycle (#13558) 2026-08-10 20:38:31 -07:00
Neil 556f469b0b refactor(mobile): remove orphaned PR composer (#13450) 2026-08-10 20:25:54 -07:00
Neil 75c6efd48b Remove obsolete pairing connection attempt (#13460) 2026-08-10 20:25:51 -07:00
Neil f9f8d7a8bf refactor(relay): remove obsolete status parser (#13475) 2026-08-10 20:25:48 -07:00
Neil bb6f0c1cb5 refactor(renderer): remove superseded GitHub background create (#13479) 2026-08-10 20:25:45 -07:00
Neil 34f46398d7 refactor(daemon): remove superseded PTY provider (#13477) 2026-08-10 20:25:43 -07:00
Neil f805189bff refactor(automations): remove unused Hermes output limits (#13497) 2026-08-10 20:25:39 -07:00
Neil 3203b0c405 refactor(onboarding): remove retired tour outcome tracker (#13498) 2026-08-10 20:25:36 -07:00
Neil 573eace89f refactor(persistence): remove unwired state bounds (#13499) 2026-08-10 20:25:33 -07:00