Commit Graph
11496 Commits
Author SHA1 Message Date
Neil 15213c15e6 Send hidden terminal query replies without batching (#8213) 2026-07-11 00:05:54 -07:00
Neil cf04845f5b fix(mobile): keep TypeScript 6 for Expo Metro bundling (#8243) mobile-ios-v0.0.26 mobile-android-v0.0.26 2026-07-11 00:04:03 -07:00
github-actions[bot] 350ed02f41 Update README downloads badge 2026-07-11 07:01:18 +00:00
Rod BoevandJinjing 04a040801b fix(terminal): detect PR links with ANSI resets (#8216)
* fix(terminal): detect PR links with ANSI resets (#8126)

* fix(terminal): safely normalize PR link styling

---------

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-07-10 23:41:20 -07:00
github-actions[bot] 588dba6354 release: v1.4.136-rc.0 v1.4.136-rc.0 2026-07-11 06:35:57 +00:00
Brennan BensonandBrennan Benson 31cff75a7b feat(agent-status): show Claude subagent child rows and gate premature done (#8211)
* feat(agent-status): show Claude subagent child rows and gate premature done

A Claude pane that spawned background subagents/teammates showed a green
done check the moment the lead's turn ended, even while a background
review loop was still running. Orca now tracks the pane's live children
from Claude hook events and:

- keeps the pane 'working' while at least one child is working (Stop is
  gated; Claude wakes the lead when a child finishes, so the pane
  resolves to done on the follow-up Stop with an empty roster)
- renders the children as indented child rows under the pane's sidebar
  row (name/type + working/idle dot), reusing the existing lineage UI

Tracking is lifecycle-primary: SubagentStart/SubagentStop/TeammateIdle
(newly registered hooks) plus child-origin tool events (they carry
agent_id) own the roster. Stop's background_tasks is folded only where
unambiguous — verified live on Claude Code 2.1.207 that teammates report
status "running" while idle-alive and their task ids never match
lifecycle agent_ids, so the list cannot decide teammate working-ness.

Child-origin events no longer overwrite the lead's tool/prompt caches
(a live AskUserQuestion card survives child churn); a child's own
PermissionRequest records waitingAgentId so only that child's progress
or death clears the wait. The interrupted flag survives the gated
window, inferred interrupts sync the lead record and refuse while a
child works, and hydration reseeds the roster after a restart.

* fix(agent-status): drop identity icon on subagent child rows

The child's agentType carries its NAME (e.g. "pr-reviewer"), which is not
an iconable agent and rendered the unknown "?" glyph. Nesting under the
parent row already conveys identity.

* fix(agent-status): restore displaced lead state and reconcile phantom subagents

Four review findings from the adversarial pass on the subagent child-row
feature:

- Stash the lead state a child-induced wait displaces
  (ClaudeLeadTurnState.stateBeforeWait) and restore it when the wait
  clears, instead of inventing 'working' — a lead that had already
  stopped left the pane spinning forever after the roster drained,
  since the done-gate only ever downgrades done → working.
- Tag snapshot-seeded and background_tasks-recreated roster entries
  (backgroundTasksAuthoritative) and demote them when a PRESENT
  background_tasks list omits their id. A phantom child seeded before a
  restart could otherwise gate the pane 'working' indefinitely in teams
  sessions, whose task list is never empty. Live activity clears the
  tag so lifecycle-tracked teammates keep their state.
- Match teammate ids with a hyphen-free suffix after `a<name>-` so
  TeammateIdle for "lane" cannot idle "lane-hooks"'s rows or clear its
  pending permission wait.
- Route turn-boundary events (Stop/StopFailure/UserPromptSubmit) that
  carry a KNOWN child agent_id through the child-driven re-emit instead
  of adopting them as lead state, and tie the prompt-cache new-turn
  reset to lead-origin events so child refreshes can't blank the
  prompt label.

---------

Co-authored-by: Brennan Benson <brennanbenson@Brennans-MacBook-Pro.local>
2026-07-10 23:34:49 -07:00
JinjingandOrca 2e48495273 Prevent mobile screen locking during voice dictation. (#7746)
* Prevent mobile screen locking during voice dictation

Integrate expo-keep-awake to prevent the mobile device from locking or
sleeping while a voice dictation session is active.

- Modularize useMobileDictation logic into separate helper files for
  keep-awake, audio chunking, session state, and desktop startup.
- Acquire keep-awake lock only after successfully establishing a
  desktop session to avoid locking on stale start attempts.
- Release the keep-awake lock on all completion, cancellation, error,
  and unmount paths.
- Add source invariant unit tests to verify keep-awake ownership and
  strict cleanup ordering.

* serialize keep-awake operations and avoid stale dictation start races

- Implement a global execution queue and tag tracking for keep-awake
  operations to prevent concurrent races and stale deactivations.
- Track failed native deactivations and retry them when a replacement
  hook owner mounts or starts a new dictation session.
- Ensure stale or canceled desktop dictation starts do not reset the
  UI state or propagate outdated start/keep-awake failures.
- Reuse the audio chunk queue wiring in useMobileDictation to avoid
  allocating new closure objects on the high-frequency microphone path.
- Add comprehensive unit tests for the keep-awake and desktop start hooks.

* Commit native recording during dictation session startup

Commit native recording in the same continuation as the final session
stale check. This prevents a queued cancellation from resurrecting the
microphone recording after cleanup has already run. If microphone
initialization fails or throws, acquired resources (like keep-awake
locks and the remote desktop session) are properly rolled back.

* Make keep-awake acquisition best-effort with a bounded startup timeout

- Recording start no longer blocks (or fails) on keep-awake acquisition:
  a hung or failing native call is capped at a short budget and logged
  instead of delaying or aborting dictation.
- Add native-call timeouts, orphan-tag tracking, and reacquire/drain
  logic in mobile-dictation-keep-awake.ts so Activity recreation on
  Android and stale tags no longer wedge the keep-awake queue.
- Add useMobileDictationForegroundKeepAwake to refresh the wake tag on
  Android foreground and retry failed refreshes/deactivations.
- Hold the wake tag through chunk drain and the finish RPC so a screen
  lock can't suspend the app before the transcript arrives, and keep
  cleanup running even if native recording shutdown throws.
- Loosen expo-keep-awake to a caret range to unblock the patch pulling
  in these native fixes.

* Fix cancellation races in mobile dictation keep-awake handling

- Run wake-lock release and dictation cancel concurrently on stale
  starts so a hung acquisition no longer delays the native cancel
- Guard foreground reacquire retries with a run token so a stale
  retry chain can't deactivate a wake lock reacquired by a newer
  AppState transition

* Update source invariant test for concurrent stale-start cleanup

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-10 23:31:56 -07:00
JinjingandOrca 931e402e93 Fix tui-idle detection for cursor-agent lanes with dismissed trust dialog (#8220)
* Fix tui-idle detection for Cursor Agent lanes with dismissed trust dialo

Cursor Agent's persistent TUI never emits an idle OSC title, so a
dismissed trust dialog stayed in scrollback and kept the wait blocked
even once Cursor reached its idle "→" prompt. Detect Cursor's active
prompt (busy or idle) to clear a stale trust hit, and detect its idle
state specifically (prompt present, no braille spinner) to satisfy
tui-idle, so busy lanes keep polling instead of returning a stale
blocked result.

* Add test coverage for Cursor Agent trust-dialog banner detection

Verify lastIndexOf picks the later ready banner over an earlier
"Cursor Agent" mention in the trust dialog body, for both the
idle-resolution and busy-detection cases.

* chore(i18n): sync localization catalog for aiVaultSessionLogOpen keys

Pre-existing gap from #8205 (ai-vault view log) that fails `pnpm lint`'s
localization-catalog check on origin/main; unrelated to the tui-idle fix but
committed here to unblock CI lint on this branch.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-10 23:25:46 -07:00
Rod BoevandJinjing b677b2a209 fix(github): recover oversized issue creation (#8217)
* fix(github): recover oversized issue creation (#7704)

* fix(github): preserve partial issue creation

---------

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
2026-07-10 23:16:13 -07:00
Jinjing 66cad529a2 Improve chinese translation 2 (#8219)
* Improve zh/ja/ko/es translations for missing and untranslated i18n strin

- Translates several previously English-only entries (locked workspace, host removal, subagent labels, org/profile switcher dialogs) that were left untranslated in each locale file
- Fixes zh/ja/ko/es JSON EOF newline formatting

* Improve zh/ja/ko/es translation quality and terminology consistency

- Fix mistranslated/untranslated strings (English leftovers in es/ja,
  incorrect "role"→"forbidden" wording in ko)
- Standardize terminology: 子代理→子智能体, 中立→中性 (zh); 하위
  에이전트→서브에이전트 (ko); align count-phrase word order with
  natural ko/ko phrasing (e.g. "N개 X" → "X N개")
2026-07-10 23:06:56 -07:00
Jinjing 026516f323 the-sandbox-flag-is-2 (#8236)
* Fix mobile source control drawer overflow and branch-compare state loss

- Render BottomDrawer in a native Modal so it covers the full viewport
  even when mounted inside a ScrollView.
- Move the conflict/Abort row onto its own line so it never overflows
  the branch card, and enlarge the Abort hit target.
- Show the committed-on-branch footer even when the changed-files
  SectionList has no sections, since RN skips ListFooterComponent for
  empty sections.
- Stop branch-compare state from collapsing to idle/error on transient
  base-ref resolution failures when a ready result should be preserved.

* Add mobile source control drawer reload screenshot

Attaches an evidence screenshot for the mobile source control drawer overflow / branch-compare state loss fix.

* Remove stray temp screenshot file

Accidentally committed debug artifact from mobile source control drawer work; not needed in the repo.
2026-07-10 23:04:38 -07:00
Jinwoo HongandOrca 5b1fcb0ff0 Fix task workspace handoff after switching workspaces (#8226)
Co-authored-by: Orca <help@stably.ai>
2026-07-10 22:56:33 -07:00
JinjingandOrca 6a176b89fc fix(source-control): keep push enabled for same-repo linked review with real upstream (#8202)
* fix(source-control): keep push enabled for same-repo linked review with real upstream

Push/Force Push (and Pull/Sync/Publish) were wrongly disabled when a branch
had a genuine git upstream but an open linked PR whose push target had not
yet hydrated. `hasUsableHostedReviewPushTarget` hard-returned false for any
resolvable review link without a hydrated `pushTarget`, so
`resolveHostedReviewActionUpstreamStatus` synthesized `hasUpstream:false`
and the whole remote menu treated the branch as unpublished.

A same-repo review's head IS the checked-out branch, so a real upstream
already tracking that branch is that head and is safe to use before the
resolver hydrates a target. Treat that upstream as usable; keep blocking the
fork-head/cross-repo case (upstream tracks a differently-named head) and the
no-upstream case until the resolver proves the real target. Provider-agnostic
(GitHub PR / GitLab MR) and covers the SSH linked-review path.

Adds regression tests to source-control-hosted-review-push-target.test.ts and
a composed pipeline test in source-control-dropdown-items.test.ts.

* docs(source-control): trim verbose comments on linked-review push-target fix

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

* refactor(source-control): use canonical gitRefTargetsBranchName for linked-review upstream match

Replace the hand-rolled upstreamTracksBranch leaf-split with the shared
gitRefTargetsBranchName primitive, which trims and rejects malformed
remote-qualified refs. The remote stays unknown until the resolver hydrates
the push target, so this remains a branch-leaf match; the strict remote+branch
check takes over once the target is known.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-10 22:45:32 -07:00
NeilandOrca 4f7fe78921 perf(mobile): stop polling live worktree names (#8051)
* perf(mobile): replace worktree name polling with events

* fix(worktrees): push rename invalidation to remote clients

worktrees:updateMeta deliberately skips the renderer notifier (PR #209),
but paired mobile clients no longer poll for titles, so a manual rename
would never reach them. Emit the remote-only worktreesChanged client
event (with resolved-cache invalidation), gated on displayName so
per-click isUnread writes stay event-free.

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

* test(worktrees): add missing runtimeStub type member for typecheck

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

* fix(worktrees): derive rename event repoId with the shared non-throwing parser

getRepoIdFromWorktreeId matches the mobile client's event filter exactly
and cannot throw after the meta write already persisted.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-10 22:44:59 -07:00
OrcaWin c869891b37 test(e2e): defer large repo cleanup until shutdown (#8228) 2026-07-10 22:43:12 -07:00
Siddiqui QamarandJinwoo Hong e3f0b99f4a fix: detect noisy Windows ARM64 SSH platforms (#7965)
* fix: detect noisy Windows ARM64 SSH platforms

- Scan remote platform probe output line-by-line for supported OS/arch markers.

- Handle PowerShell/OpenSSH first-use CLIXML or banner noise before Windows ARM64.

- Add regression coverage for noisy Windows ARM64 detection.

* fix: harden SSH platform probe markers

---------

Co-authored-by: Jinwoo Hong <73622457+Jinwoo-H@users.noreply.github.com>
2026-07-10 22:31:53 -07:00
Neil 4df9457530 Fix delayed terminal color-scheme replies leaking into fish (#8206)
* fix(terminal): send mode 2031 replies immediately

* docs(terminal): name mode 2031 color replies accurately
2026-07-10 21:24:27 -07:00
Jinjing c5044042ea Ai vault view log live tail (#8205)
* Add read-only View Log tabs so AI Vault agent sessions open inside Orca'

- Adds a `readOnly` flag on OpenFile that hard-blocks edits, autosave, dirty
  state, rename, and drafts, and persists/restores it safely across sessions
- Wires AI Vault's View Log/Open Log actions to open logs as permanent
  read-only local tabs instead of shelling out to the OS, gated to
  local, single-file, non-synthetic session paths
- Registers a dedicated `jsonl` Monaco language (JSON-style coloring without
  whole-document JSON validation) and forces read-only tabs to render as raw
  source, bypassing markdown/mermaid/csv/notebook viewers

* Add live-tail streaming for local AI Vault View Log tabs

- Extend the fs:readFile snapshot path with byte-stable file identity so a
  read-only tab can resume appending exactly where the snapshot left off.
- Add a ranged local log tail reader plus IPC (read/start/stop watch) that
  streams only newly appended bytes, detects truncation/rotation, and
  cleans up watchers on tab close or renderer destruction.
- Add a renderer-side UTF-8/line-boundary decoder and useLocalLogTail hook
  that appends completed lines into the existing Monaco model, falling
  back to a full reload on reset/rotation, keeping snapshot behavior
  unchanged when liveTail is not opted in.
- Thread the new `liveTail` flag through OpenFile/PersistedOpenFile,
  workspace session persistence/restore, and the AI Vault "View Log" open
  path so live tail survives restarts and stays read-only-safe.

* Remove stale planning brief for the live-tail feature

The AI-VAULT-VIEW-LOG-LIVE-TAIL.md pick-up brief is no longer needed now that the live-tail streaming work has landed (c7fdef7b1).
2026-07-10 21:22:18 -07:00
Neil 20c9e09cca test(renderer): restore terminal-create fixture parity (#8208) 2026-07-10 21:18:56 -07:00
Neil 6b7732d511 perf: skip terminal wait scans for ordinary output (#8169)
* perf: skip terminal wait scans for ordinary output

* test: record terminal wait performance gate

* docs: clarify terminal wait allocation proof
2026-07-10 21:10:29 -07:00
Neil 84d375ae06 perf: avoid rescanning idle serve-sim PTY output (#8166)
* perf: avoid scanning idle serve-sim PTY output

* test: record serve-sim PTY performance gate

* fix(renderer): dedupe connection context import
2026-07-10 21:04:59 -07:00
b902f19b0d fix(terminal): send CSI-u Shift+Enter to Droid on Windows (#7620) (#7668)
* fix(terminal): send CSI-u Shift+Enter to kitty TUIs (droid) on Windows (#7620)

On Windows, Shift+Enter was always sent as the Alt+Enter byte ESC+CR (added in
#2418 for Codex, which reads win32-input-mode and ignores CSI-u). droid speaks
the kitty keyboard protocol, parses CSI-u directly, and treats ESC+CR as a plain
Enter — so Shift+Enter SUBMITTED the message instead of inserting a newline.
droid works in other terminals (Windows Terminal, Warp) because those honor
win32-input-mode / kitty; Orca (xterm.js) withholds kitty from local Windows
ConPTY panes and emits neither.

Make the Windows Shift+Enter byte pane-aware: latch whether a pane's program
advertised the kitty keyboard protocol (query CSI ? u, push CSI > .. u, or set
CSI = .. u) and send CSI-u (\x1b[13;2u) to those panes, keeping the
Codex-compatible ESC+CR for win32-input-mode-only TUIs. Non-Windows is unchanged
(always CSI-u).

Verified end-to-end against the real droid and Codex CLIs through the actual
production functions: droid now newlines, Codex still newlines.

* fix(terminal): route Windows Shift+Enter safely for Droid

---------

Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-07-10 21:00:31 -07:00
Neil 2a01b41638 perf(main): make worktree path dedupe linear (#8177) 2026-07-10 20:52:24 -07:00
Neil 435de94102 perf(main): avoid hosted-review IPC fanout (#8171) 2026-07-10 20:52:22 -07:00
Neil 943fc781bb perf(runtime): reuse unchanged PTY path history (#8163) 2026-07-10 20:52:17 -07:00
Neil 90afbc3cf3 perf(status-bar): avoid resource badge rebuilds on title churn (#8152) 2026-07-10 20:52:15 -07:00
Neil 141b9b7de2 perf(renderer): gate agent completion coordinator sync (#8149) 2026-07-10 20:52:13 -07:00
Neil a4fb828b3c perf(renderer): scope folder review cache projections (#8136)
* perf(renderer): scope folder review cache projections

* fix(renderer): keep checks selector notifications constant-time
2026-07-10 20:51:59 -07:00
Neil 3afea9e9f2 perf(renderer): scope Markdown worktree path subscriptions (#8111) 2026-07-10 20:51:56 -07:00
Neil e0207cb360 perf(renderer): scope editor draft subscriptions by panel (#8105)
* perf(renderer): scope editor draft subscriptions by panel

* fix(renderer): keep conflict overview drafts live
2026-07-10 20:51:54 -07:00
Neil d617bda234 perf(renderer): scope active review cache subscriptions (#8097) 2026-07-10 20:51:51 -07:00
Neil 8b1054de19 perf(renderer): index runtime owner lookups (#8089) 2026-07-10 20:51:49 -07:00
Neil e5be88342d perf(renderer): reuse connection context indexes (#8085)
* perf(renderer): reuse connection context indexes

* perf(renderer): reuse connection indexes in tab bars

* perf(renderer): reuse worktree index for diff comments

* perf(renderer): index remaining diff comment selectors
2026-07-10 20:51:47 -07:00
Neil e085a84df8 perf(renderer): keep pre-handler PTY buffering linear (#8082) 2026-07-10 20:51:44 -07:00
Neil 65b7d9a532 perf(renderer): compact ignored Cursor title effects (#8080) 2026-07-10 20:51:31 -07:00
Neil 106009a90c perf(renderer): index terminal unified tab reads (#8076) 2026-07-10 20:51:28 -07:00
Neil 09196ba086 perf(renderer): scope floating workspace collections (#8071) 2026-07-10 20:51:26 -07:00
Neil 74e68afbb2 perf(renderer): share terminal agent type index (#8066) 2026-07-10 20:51:23 -07:00
Neil 818e182a0c perf(renderer): gate worktree list review caches (#8061) 2026-07-10 20:51:20 -07:00
Neil b681a2c54a perf(renderer): scope agent send-target control updates (#8055) 2026-07-10 20:51:18 -07:00
Neil fadb3f3730 perf(renderer): scope sidebar agent freshness by worktree (#8052) 2026-07-10 20:51:15 -07:00
Jinjing 5e100914d3 fix(mobile): recover terminal WebView/WebGL/viewport/theme state after iOS resume (#8196)
* fix(mobile): recover terminal state after iOS resume

* Refactor terminal record merge to extract snapshot-reconciliation helper

Split the inline merge logic in mergeTerminalRecordsByCurrentOrder into a
named mergeTerminalSnapshotWithKnownRecord function for clarity, preserving
the existing behavior of keeping the last known theme when a snapshot omits it.
2026-07-10 20:22:16 -07:00
NeilandOrca e825df8218 perf(memory): skip unrelated boot worktree scans (#8204)
* perf(memory): scope boot worktree scans to live sessions

* fix(memory): refresh daemon hydration snapshots

* fix(memory): rescan repos referenced only by the re-read snapshot

Repo selection previously came solely from the first daemon listing, so a
session that only became visible on the post-enumeration re-read (e.g. a
briefly unreachable adapter) could never be registered for the life of the
process. Loop enumeration until the latest daemon snapshot references no
unresolved repos, so selection and registration always share a snapshot.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-07-10 20:10:08 -07:00
2cfb028163 fix: Cap automationRuns retention to stop unbounded state file growth (#8119)
* Cap automationRuns retention to stop unbounded state file growth

`automationRuns` was the only unbounded durable collection in
`orca-data.json`, and the whole blob is re-serialized and rewritten on
every save. On a machine running four `* * * * *` automations it had
grown to 11,184 rows / 21 MB of a 28.5 MB file — all of them
`skipped_precheck` no-ops — so each synchronous `flush()` blocked the
Electron main thread for 190-210 ms and macOS filed 24 `disk writes`
diagnostic reports against Orca (12-30 MB/s sustained, 549 GB/session).

Prune to the newest 100 runs per automation, on load and on append. This
mirrors the retention that `pruneLocalTerminalScrollbackBuffers` and
`pruneWorkspaceSessionBrowserHistory` already apply to their
collections; `automationRuns` was simply missed.

The load-path prune marks state dirty, so an oversized file heals on
first load. Without that flag the shrink lives only in memory: the sole
load-time save trigger is `normalized.changed || loadNeedsSave ||
adaptedProjectGroups`, and `normalized` covers pane identity only. A
user who took the documented workaround (`automations edit --disabled`)
fires no runs, so nothing would ever rewrite the file.

Measured against the affected 28.5 MB file: flush() 190 ms -> 9 ms,
bytes written per save 28.5 MB -> 1.3 MB.

Pruning breaks the old `runNumber` derivation, which counted retained
runs, so every run after the cap would have been titled "run 101".
Carry the ordinal on the run itself and derive the next number from the
highest survivor. Legacy rows are numbered from the highest number their
automation already carries, not from their append position: a downgrade
to a pre-`runNumber` build appends unnumbered runs after pruned
survivors numbered 101+, and a position would reissue one of those,
giving two runs the same title.

Fixes #8118

* Never evict in-flight automation runs from retention

A dispatched run's completion can land hours later (renderer round-trip or
headless completion promise); pruning it makes updateAutomationRun throw
'Automation run not found.'. Only final-status runs are evictable now, with
the final-status predicate shared between retention and the service.

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

* Skip the usage write when retention evicted the run mid-collection

markDispatchResult finalizes a run, awaits usage collection, then writes
usage by id. The run is final during that await, so a concurrent
create-time prune can evict it and the write threw 'Automation run not
found.' — in the headless path that cascaded into an unhandled rejection.

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

* Pin backfill-before-prune ordering with true legacy fixture rows

The heal-on-load fixture rows carried runNumber, so swapping backfill and
prune passed every test while renumbering real legacy survivors 1..100 and
re-minting colliding titles. Seed unnumbered rows and assert healed ordinals.

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-10 20:02:45 -07:00
Neil 66437d19c3 perf(hook-commands): skip unrelated store flushes (#8181) 2026-07-10 19:56:03 -07:00
Neil 5eda948a7a perf(agent-startup): skip unrelated store flushes (#8179) 2026-07-10 19:56:00 -07:00
Neil 0eafb0e626 perf(ai-vault): index visible session pane lookups (#8173)
* perf(ai-vault): index visible session pane lookups

* perf(ai-vault): build pane index lazily
2026-07-10 19:55:57 -07:00
Neil c7777e44a6 Reduce terminal redraw CPU on active TUIs (#8178) 2026-07-10 19:50:44 -07:00
Jinjing a916a93df3 Make explicit desktop take-back always release the mobile presence lock (#8200)
Previously a failed resize during reclaimTerminalForDesktop left the
override/lock in place (#7588 semantics), but for an explicit "take
back all terminals" gesture that could strand banners on background
panes whose resize can't converge. Now the take-back unconditionally
releases the driver and clears any held fit-override via a new
releaseDesktopTakeBack helper, while auto-restore and phone-initiated
paths keep the original keep-lock-on-failure behavior.

Also extract the local mapWithConcurrency helper out of
workspace-cleanup.ts into a shared, tested src/shared/map-with-concurrency.ts
and use it to bound concurrent desktop-fit reclaims in
terminal-fit-restore.ts.
2026-07-10 19:41:27 -07:00
Jinjing 5a8078e755 Improve search box on mobile (#8187)
* Redesign mobile search field as a shared, raised component

- Extract MobileSearchField from duplicated Search icon + TextInput + clear
  button markup in worktree list and tasks screens into a reusable component
- Give the field a raised bgRaised shell with focus/disabled states so it
  reads as a tappable control instead of blending into panel chrome
- Fix delayed autoFocus via InteractionManager + timeout so the keyboard
  reliably appears after the search bar opens
- Preserve per-screen clear behavior (preset/query fallback for GitHub,
  project-view filter) via configurable showClear/onClear props

* Simplify GitHub project search state checks and fix stuck clear button

- Extract `isGithubProjectSearch` to dedupe repeated `provider === 'github' && githubMode === 'project'` checks
- Fix showClear so an explicit empty applied override doesn't leave the clear button visible forever
2026-07-10 19:40:40 -07:00