Commit Graph
8328 Commits
Author SHA1 Message Date
Neil 96c2cebfa6 refactor(mobile): extract terminal settings styles (#13706) 2026-08-10 17:52:45 -07:00
Jinjing 20848169e0 Improve automations page UI: full-page detail and table redesign (#13292)
* improve automations page ui

* Improve automations page UI: fix menu interactions, extract components,

- Extract status cell to reusable component
- Fix portaled context menu clicks re-selecting rows
- Use explicit selection IDs instead of resolved objects for reliable detail state
- Close detail when selection is lost during refresh or deletion
- Improve escape key navigation through nested detail views
- Use native input for search field to avoid unwanted shadow elevation
- Add i18n keys for table and button labels

* fix: merge duplicate type imports in AutomationListLocalRows test

Static analysis fails under --deny-warnings when the same module is
imported twice; combine the Automation and external types into one import.

* Fix row keyboard activation to not intercept nested controls

Row handlers for Enter/Space were preventing the actions menu button from
opening when activated via keyboard. Extract a reusable check that only
treats these keys as row activation when they originate on the row itself,
not on child controls. Also consolidate the search input to use the shared
Input component for consistency.

* fix: use stable keys for automations page skeleton rows

React Doctor no-array-index-as-key failed static analysis on the
loading skeleton map. Give each static row an id for the React key.

* Reorganize i18n keys for automation components

Move translation keys to their proper component namespaces (rowActions to AutomationListLocalRows, normalize loading key), update all locale files.

* fix: move automations detail selection refs out of render

React Doctor fails CI when refs are mutated during render. Sync
selectedExternalKey and isDetailOpen into refs in effects instead.

* style: soften automation search field focus state

- Reduce focus ring opacity to 70% for a subtler focus indicator
- Set focus-visible:ring-0 to eliminate elevation effect
- Add dark:bg-background for consistent dark mode appearance
2026-08-10 17:37:49 -07:00
Neil 090678a32b [Perf-SS] Keep reattach live queues linear during replay (#13478) 2026-08-10 17:33:46 -07:00
github-actions[bot] 1c1107fc9b Update README downloads badge 2026-08-11 00:33:35 +00:00
Neil 119b1e1c53 fix(release): reject non-release publications (#13591)
* fix(release): quarantine unauthorized publications

* fix(release): remove unauthorized publication tags

* fix(release): require canonical version tags

* refactor(release): narrow policy to one workflow

* fix(release): reassert latest stable release
2026-08-10 17:27:56 -07:00
Neil 2ade803522 [Perf-SS] Remove redundant native Ripgrep probes (#13462) 2026-08-10 17:25:26 -07:00
Jinjing 3d8c8c3d4c docs: update Android APK to 0.0.42 (#13700) 2026-08-10 17:12:53 -07:00
Brennan Benson 2ee43bfc0d fix(agent-hooks): refresh existing Orca launchers when agent CLIs are unavailable (#13378)
* fix(agent-hooks): refresh existing shared hook scripts when the CLI is no longer detected

A CLI that falls off PATH (moved npm prefix, relocated shim) keeps its user-wide
config invoking Orca's launcher script under ~/.orca/agent-hooks, but the
presence gate skips install() with no removal — freezing the script at whatever
Orca generated last. Anyone in that state kept the pre-#11568 more.com-leaking
.cmd forever, because no launcher script is ever deleted and Windows startup
deliberately skips shell PATH hydration.

Reconcile before gating: every existing shared launcher/statusline script is
rewritten to the current template on each install pass. Creating scripts stays
behind the presence gate — an existing file is proof of a prior install; a
missing one means the gate did its job. Amp and Hermes are deliberately absent:
they write provider-native plugin code with its own install lifecycle, not
shared launchers.

- refreshManagedScriptIfPresent() in installer-utils (no-op unless the file exists)
- refreshManagedScripts() on the 11 launcher-writing services (openclaude via
  the shared Claude class)
- reconcile pass in installManagedAgentHooks before presence detection,
  filtered by the agents option, best-effort per agent
- coverage gate: a launcher written to ~/.orca/agent-hooks without a matching
  refresher entry fails the suite, in both directions

* perf(agent-hooks): refresh launchers off the main thread

* test(agent-hooks): keep refresh mode assertion POSIX-only
2026-08-10 16:34:15 -07:00
Brennan Benson a70291a918 perf(orchestration): index mutation receipt capacity (#13647) 2026-08-10 16:17:52 -07:00
bokjkandBrennan Benson 1b02cedfff fix(tabs): keep widths stable during title updates (#11476)
* fix(tabs): keep widths stable during title updates

* review(tabs): reduce the width rule to the definite width and harden its tests

Why: once the tab container has a definite width the shrink-wrapped strip never
has free space, so flex-grow and max-w-[280px] were unreachable and only
duplicated the 180/220 numbers across two properties. Measured widths, strip
scrollWidth and clientWidth are identical to the flex-based version across four
window widths, five tab counts and short/long titles.

Tests: pin the width classes literally so the guarantee cannot be edited away
via the constant, and guard the e2e check against passing vacuously on a
saturated strip.

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 16:11:19 -07:00
Brennan Benson 6b9852af2b perf(terminal): remove output-driven WebGL atlas resets (#13657)
* perf(terminal): stop clearing glyph atlas on output

* test(terminal): gate output atlas reset removal

* test(terminal): harden atlas recovery gates
2026-08-10 16:10:47 -07:00
Brennan Benson de1b119141 fix(mobile): stop labeling accepted messages queued (#13658) 2026-08-10 16:09:17 -07:00
Brennan Benson 03e740fa50 Fix notification clicks with Agent Dashboard pop-out (#13680)
* fix(notifications): route clicks to main window

* fix(notifications): reveal hidden main window on click
2026-08-10 16:05:48 -07:00
Brennan Benson 8da362919e perf(runtime): batch legacy worker recovery persistence (#13649)
* perf(runtime): batch legacy recovery persistence

* fix(runtime): preserve concurrent recovery state

* fix(runtime): require durable recovery retry
2026-08-10 15:58:17 -07:00
Brennan Benson d50adec2d2 feat(ai-vault): isolate scanning from terminal workloads (#13411)
* feat(ai-vault): isolate scanning in service processes

* fix(ai-vault): retire idle service processes

* fix(ai-vault): discard unverified cache processes

* fix(ai-vault): clear relay sidecar cancel watchdog on acknowledgement

A cancelled relay call is settled before its 2s cancel watchdog is armed, so the acknowledgement path bailed out of settle() before clearing the timer. The watchdog then faulted a healthy sidecar two seconds after every aborted scan, killing whatever request had since become active.

* fix(ai-vault): clear the pending restart before scheduling another

recordFault overwrote this.timer, stranding a restart that dispose() could no longer cancel.

* refactor(ai-vault): drop the orphaned first-prompt IPC wrapper

session-first-user-prompt-handler.ts now owns this entry point and routes through the service; the copy left in the read module had no callers.

* fix(ai-vault): retry a faulted cold start before surfacing it

A slow first start surfaced a raw 'did not become ready' error to the caller even though the supervisor was already respawning. Requeue an unsent call once onto the scheduled respawn instead.

Also stop arming the cancellation watchdog for a call the child never received: no acknowledgement is coming, so it killed a healthy service and stalled the lane.

Invalidation bookkeeping and ready-waiter construction move to the state module to stay under the max-lines cap.

* fix(ai-vault): give relay title reads their own lane

Before this branch the relay read title files directly, concurrently with scans. Routing both through one sidecar lane put title resolution behind a list scan that may run up to 130s, so SSH tab titles could lag minutes behind.

Split cache and interactive lanes in both the relay client and the sidecar entry, mirroring the desktop service.

Also: clear the ready deadline on fault, so a sidecar that dies before ready cannot fault its healthy replacement five seconds later; retry an unsent call once across a respawn; and skip the cancellation watchdog for a call the sidecar never received.

Restart/circuit bookkeeping moves to its own module, mirroring the desktop policy, to stay under the max-lines cap.

* fix(ai-vault): degrade relay title resolution on sidecar failure

listSessions already returns a host issue when the sidecar is unavailable; titles propagated the raw RPC error instead. Return no titles so callers fall back to preview text, and keep cancellation propagating.

* fix(ai-vault): scrub the service child environment

The children are forked with a 384 MiB heap cap and no loader, but both
spawn sites handed them the full parent environment, so an exported
NODE_OPTIONS silently raised the cap or --require'd code into them.

Allowlist both, following the plugin worker. The desktop child keeps the
eleven agent-root overrides it resolves its own roots from; the relay
sidecar takes remoteHome and hostPlatform from its init message and so
needs none of them. Both children share one priority module while they
share this one.

* fix(ai-vault): soft-disable relay vault when the service is missing

A missing service threw out of the constructor, so a Vault wiring bug
would abort relay startup and take every PTY on the host with it. The
unsupported-platform branch three lines above already treats a Vault
failure as a soft disable; do the same here.

Threading the service through the two handlers instead of a field also
retires the definite-assignment assertion the throw was propping up.

* fix(ai-vault): drain consumed cache invalidations

invalidatedPaths was re-applied in every request's finally and never
drained, so once N paths had been invalidated every later request paid N
evictions for the life of the process; the 4096 cap only bounded how bad
that got.

The re-apply exists to cover a read that overlapped the invalidation, so
drain once nothing is executing. Clearing unconditionally would drop the
re-apply for a request still running on the other lane.

* fix(ai-vault): keep a busy child through slow invalidation acks

invalidate() reused the 5s ready budget as its acknowledgement deadline
and killed the child on expiry, so a delete issued during a large scan
could kill a healthy process mid-scan and burn a slot toward the restart
circuit.

Fault only when nothing is executing. Fork IPC ordering already puts the
invalidation ahead of any later request, so a busy child owes no ack
here, and the 130s/15s request deadlines still catch a wedged one.

The start-retry predicate moves to the state module to stay under the
line cap, matching the shape the relay client already uses.

* fix(ai-vault): report a failed local scan as a host issue

A local-scope scan let its error escape to the renderer, which paints it
over the session list. Service supervision now produces those errors, so
"AI Vault service restart circuit is open." replaced the list.

Route local scope through the degradation the all-hosts leg and every SSH
leg already use, so it lands as a retryable host issue row instead. Same
result shape either way, so no IPC or wire contract changes.

* test(ai-vault): cover the relay restart circuit transitions

The relay policy shipped without tests. Pin both circuit edges, the
aging-out case, the forced-refresh reopen the relay has and the desktop
does not, and the backoff schedule.

* fix(ai-vault): keep the OpenCode roots in the service child env

The scrubbed allowlist dropped XDG_DATA_HOME and OPENCODE_DB, which the child
reads to locate the OpenCode store and database. The pre-PR worker thread
inherited them, so a user who sets either lost every OpenCode session.

* test(ai-vault): anchor the service spawn env assertion
2026-08-10 15:52:59 -07:00
Brennan Benson fb80f91921 Clear stale terminal selection during pane recovery (#13677)
* fix(terminal): forward copy to TUI selections

* fix(terminal): narrow recovery selection cleanup
2026-08-10 15:52:25 -07:00
Brennan Benson 84bd306949 perf: Stop unchanged worktree refresh churn (#13662)
* fix: stop unchanged worktree refresh churn

* fix: preserve smart sort telemetry recomputations

* fix: preserve duplicate worktree host identities

* perf: skip reconciled catalog traversal

* test: strengthen worktree refresh regressions
2026-08-10 15:44:05 -07:00
makoto-developerandBrennan Benson 0b5c5d6e74 fix(i18n): restore identifiers and commands machine translation localized in ko/zh/es (#13124)
* fix(i18n): restore identifiers and commands machine translation localized

39 values in ko, zh and es are code rather than copy — shell commands, CSS
class strings, git-style identifiers, sample filenames and hostnames — and had
been machine-translated. pnpm install read pnpm 설치, text-foreground read
文本前景, pr-view read PR视图, and localhost:3000 read 本地主机:3000.

pnpm install is the font-mono placeholder of the setup-script input, and
gh auth login / glab auth login are the commands the integration panes tell the
user to run, so the translated forms are shown to users as text to type.

Catalog-only. Running repair-locale-catalog.mjs over these locales fixes the
same values but rewrites several hundred unrelated ones, because the catalogs
are stale against the current policy.

* fix(i18n): restore the zh code strings found by call-site context

@smwbev scanned by where a translate() renders — inside <code> or a font-mono
element — rather than by value shape, and found nine more in zh: upstream read
上游 in the base-ref picker, nbformat read nb格式, orca.yaml read Orca.yaml,
LIN-329 read 林-329, GH #1799 lost its space, and orca · zsh read Orca·zsh.

The matching NEVER_TRANSLATE_VALUES entries landed with #12934.

* test(i18n): guard restored technical literals

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 15:43:36 -07:00
闲人andBrennan Benson 72184b75fd fix(settings): widen font size input so values are fully visible (#11585)
* fix(settings): widen font size input so values are fully visible

The number input for terminal font size was too narrow (w-14) to display
two-digit values cleanly. Changed to w-24 to ensure 10-24px values fit.

* fix(settings): hide the native spin buttons clipping the font size value

The overlapping webkit spinner was what cut off the second digit, not the
box width. Adopt the number-input-clean idiom every other numeric settings
input already uses; the spinner also duplicated the -/+ steppers.

* fix(settings): keep font size stepper compact

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 15:32:50 -07:00
Brennan Benson b46ece212b perf: Stop orchestration interaction UI broadcast storms (#13651)
* fix(perf): stop feature interaction UI broadcast storms

* test(perf): verify feature bucket persistence
2026-08-10 15:24:45 -07:00
Brennan Benson fe0ab305c4 Avoid synchronous webview URL IPC during browser pane render (#13646)
* perf(browser): avoid synchronous URL IPC during render

* fix(browser): sync live URL after CDP navigation
2026-08-10 14:57:44 -07:00
ax-dfcorpandBrennan Benson 1fafbe65f5 fix(sidebar): dispatch workspace delete intent after menu close (#11646)
* fix(sidebar): keep delayed workspace delete target stable

* fix(sidebar): report a stale workspace list instead of a silent delete no-op

runWorktreeDelete fails closed when the clicked row is no longer in the store
(concurrent delete, state reset, or a runtime re-pair that drops live rows).
The guard is right, but it returned with no feedback, so Delete looked broken.

Report the miss with the stale-list toast runWorktreeBatchDelete already uses,
extracted to a shared module so both paths share one description string.

* fix(sidebar): dispatch delete intent after menu close

* fix(sidebar): validate batch delete identities

* fix(sidebar): preserve delete identity through confirmation

* test(sidebar): follow delete status boundary extraction

* fix(sidebar): bound delete status hydration

* test(sidebar): register current parallel delete targets

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 14:32:37 -07:00
Jinwoo HongandNeil ec7e3ea477 fix(terminal): prevent paired activity renderer starvation (#13508)
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-08-10 14:32:08 -07:00
Jinjing c0c893d171 fix(pty): bound cooked reply queue (#13422)
* fix(pty): bound cooked reply queue

* fix(pty): bound cooked reply queue

Implement bounded storage for cooked-echo-safe replies: 64 pending
replies and 4096 UTF-16 code units. Shed oldest replies on overflow,
never ordinary input. Add drain failure containment with generation
fencing to prevent stale operations from clearing fresh input after
clear() reuse.

* fix(pty): report pty id in drain failures

When the async drain yields, the owner may rebind to a different PTY
before the failure surfaces. Pass the failing pty id so the transport can
ignore stale failures from a rebound owner. Also tighten the pending
reply queue size bound to prevent half-written entries.
2026-08-10 12:17:21 -07:00
Neil 56b6d845e0 perf(relay): skip serialization without recipients (#13595) 2026-08-10 05:56:39 -07:00
Neil 158b575680 perf(orchestration): coalesce drift probes per dispatch tick (#13592)
* perf(orchestration): coalesce drift probes per dispatch tick

* fix(orchestration): preserve capacity after drift refusal
2026-08-10 05:56:01 -07:00
Neil 6206945c07 fix(native-chat): harden paginated history metadata (#13573) 2026-08-10 05:55:29 -07:00
Neil a63df91790 perf(renderer): gate remote session mirror scans (#13544) 2026-08-10 02:36:19 -07:00
Neil d15a554f62 perf(renderer): gate unread badge scans (#13554) 2026-08-10 02:34:54 -07:00
Neil 6cdd019367 docs(mobile): keep Android links on published release (#13565) 2026-08-10 02:22:35 -07:00
OrcaWinandOrcaWin fb3a3c5643 perf(native-chat): probe WSL transcript paths asynchronously (#13265)
* perf(native-chat): probe WSL transcript paths asynchronously

The WSL transcript resolvers probed `\wsl.localhost` UNC candidates with
existsSync. Those paths are served over 9P, so a stopped or unreachable distro
blocked the Electron main thread instead of falling through to the next
candidate.

- host-readable-transcript-path: the `pathExists` dep is now async, defaulting
  to fs/promises.access. The per-distro loop stays sequential — the ranked order
  exists so the owning distro wins, and probing every distro at once would fan
  9P calls out to ones the user deliberately left stopped.
- session-file-resolver: dropped the existsSync guard outright rather than
  converting it. walkSessionFiles already yields [] for a missing or unreadable
  root, so the guard was redundant as well as blocking.

* perf(native-chat): stop the resolve poll mkdir-ing the Codex runtime home

codexSessionsDirs() only needs the managed home's path to scan it, but called
getOrcaManagedCodexHomePath(), which mkdirSyncs. That put a synchronous fs call
back on the 500ms-5s resolve poll the surrounding async probe work just cleared,
and materialized the runtime home as a side effect of a read-only lookup.

Use the resolve-only variant the module already exposes for this case. A missing
root walks to no matches, so behavior is unchanged.

* perf(native-chat): gate WSL transcript fs access behind a shared queue

Serializes and dedupes WSL 9P filesystem probes (access/readdir) so a
stopped or slow distro can't exhaust the shared libuv threadpool or
block unrelated local filesystem work. Routes Codex session-tree scans
and path-existence checks through the new wsl-transcript-fs-gate,
while sharing in-flight scans across concurrent callers.

* perf(native-chat): prioritize exact WSL transcript probes over scans

- Add cancellation (AbortSignal) throughout session resolution and
  directory walking so an unsubscribed transcript watch stops
  in-flight WSL filesystem work instead of leaking it.
- Split the WSL fs task gate into exact vs scan priority lanes with
  per-route concurrency, so a live transcript access probe is never
  queued behind a directory scan on another distro/provider.
- Extract Codex WSL session path scanning into its own module that
  shares one root snapshot across concurrent session-id lookups and
  refreshes on a shared miss to see post-start file creation.
- Skip the async WSL probe entirely for local paths via existsSync.

* fix(native-chat): harden WSL transcript cancellation

* fix(native-chat): finish transcript cancellation

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-10 02:19:16 -07:00
Neil bbcf89e221 chore(mobile): prepare 0.0.43 releases (#13549) 2026-08-10 01:49:33 -07:00
Jinjing 418fbb3192 fix(mobile-ios): gate release on TestFlight distribution (#13419) 2026-08-10 01:47:36 -07:00
Neil eacb9a9fa4 perf(automations): keep output snapshot appends linear (#13469) 2026-08-10 01:36:08 -07:00
Brennan Benson 9060a88dde fix: contain unbroken dialog failure output (#13531) 2026-08-10 01:24:54 -07:00
Neil 131010277c [Perf-LH] Serialize relay JSON payloads once per publication (#13516)
* perf(relay): reuse serialized JSON payloads

* Defer bulk relay payload preparation until admission
2026-08-10 01:17:14 -07:00
d305e48547 fix(gitlab): guard against non-array API responses in MR/issue listing (#12911)
* fix(gitlab): guard against non-array API responses in MR/issue listing

fetchIssuesAsWorkItems and listMergeRequests parsed glab's JSON output
and called .map straight on it. When the GitLab API returns a JSON
object instead of an array (error body, unexpected shape) on a
successful exit, this crashed with a bare TypeError that got
misclassified as "Failed to load issues: JSON.parse(...).map is not
a function" instead of a useful message.

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

* fix(gitlab): cover listIssues and keep payloads out of error classification

The guard missed listIssues in issues.ts — the RPC-backed issue list that
produces the reported "Failed to load issues: JSON.parse(...).map is not a
function". Hoist the guard into glab-api-response.ts so both files share it.

The thrown message is fed to classifyGlabError, which substring-matches it.
A response payload is content, not a diagnostic: an MR titled "fix network
timeout" classified as network_error and the canned copy replaced the payload
the user needed. Report a GitLab error envelope by its own message, and mark
an opaque body so classification is skipped.

* test(gitlab): make the list-guard tests fail on the regressions they name

Two assertions were vacuous under mutation. The envelope test used a "403
Forbidden" message whose keyword matches earlier in the classifier chain than
its sibling payload, so leaking the payload into classification still passed;
it now uses a 404 envelope beside a "403 forbidden" sibling. No call-site test
carried a classifier keyword, so deleting the marker-error branch entirely
failed only one unit test; the MR API path now uses a keyword-bearing body.

Also give the non-list branch the same "Failed to load issues" prefix as every
other list error, cover the `{ error }` envelope field, and pin the thrown type.

* test(gitlab): pin the reported-payload bound

Removing the 300-char slice survived the whole suite, and the banner's
break-words now depends on it. Name the limit and assert both branches
truncate, plus the envelope falling through a blank message to `error`.

* test(gitlab): pin message-over-error envelope precedence

Swapping the lookup order passed the whole suite. Anchor the bound regex too
so it cannot match an incidental ": " near the end of a message.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 01:10:12 -07:00
hwantageandBrennan Benson 14dc499aa5 fix(ai-vault): preserve agent metadata header on session row expansion (#10920)
* fix(ai-vault): preserve agent metadata header on session row expansion

* chore(tests): remove redundant comment in AiVaultSessionRow test

* test(ai-vault): add happy-dom environment and window.api shim to AiVaultSessionRow tests

* test(ai-vault): assert the expanded session row via the rendered row

Replaces the parallel static-markup harness and second fixture with the
file's existing Testing Library row render, so both suites share one
session fixture and one prop list. Raw HTML substring matches are gone:
the identity assertions now run inside the metadata grid, because the
details-toggle button's aria-label repeats the agent name and made the
old check pass with the fix reverted.

Tags the grid with a data-testid like the row's other query anchors
rather than walking up from a text node, adds cleanup() — the suite has
no globals: true, so rows leaked across tests — and guards that the
worktree badge renders once when expanded. SessionWorktreeLine loses an
export the row no longer imports.

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 01:07:17 -07:00
ce3ec4d5ce fix(repo-icon): keep a renamed fork's own owner avatar (#12271)
* fix(repo-icon): keep a renamed fork's own owner avatar

Fork repos always took the upstream owner's avatar, so a renamed fork
showed its parent project's logo. Same-name forks (personal copies)
still prefer the upstream owner; renamed forks now keep their origin
owner across auto-detect, the startup backfill, and the settings
avatar refresh.

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

* fix(repo-icon): re-read repo state before backfill avatar write

The startup backfill computed icon updates from a pre-loop snapshot, so
an icon chosen in settings while the upstream/origin probes were pending
could be clobbered. Re-read the repo after the probes and only migrate
an icon that is still the auto-detected GitHub avatar.

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

* refactor(repo-icon): own the fork avatar rule in one shared selector

The renamed-fork rule was written out twice — once in the main-process
auto-detect and once in the renderer refresh — so the two copies could
drift. Move it next to `githubAvatarIcon` as `githubAvatarSlug`, which
collapses the renderer resolver to a single unbranched path.

Also stop swallowing a rejected origin probe: it cannot tell a renamed
fork from a same-name one, so degrading to the upstream owner would flip
a renamed fork's stored avatar back to the parent's. Letting it propagate
keeps the stored icon, matching how the non-fork path already behaved.

Adds coverage for the startup backfill, the third decision point the fix
claims, which had none.

* test(repo-icon): cover pending backfill icon change

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 01:06:32 -07:00
Brennan Benson 4e536a5232 Improve Agent Map hover and presence motion (#13407)
* feat(agent-map): improve hover and presence motion

* fix(agent-map): derive exiting popover state

* fix(agent-map): bound exit motion lifecycle

* perf(agent-map): avoid duplicate motion commits
2026-08-10 01:03:09 -07:00
Neil 75f5e2d964 perf(renderer): reuse prepared native chat messages (#13519) 2026-08-10 01:00:20 -07:00
Neil e78bf2b6ea [Perf-SS] Keep relay writer drains linear under deep backlogs (#13449)
* perf(relay): keep writer queue drains linear

* test(relay): cover replacement after consumed cursor
2026-08-10 00:59:51 -07:00
Brennan Benson 66aed16974 refactor(ui): consolidate toggle switches (#13432)
* refactor(ui): consolidate toggle switches

* fix(ui): label consolidated switches
2026-08-10 00:54:30 -07:00
Mark XianandBrennan Benson 80f23e31cb fix(file-explorer): open symlink files when stat fails (#11670)
* fix(file-explorer): open symlink files when stat fails

* fix(file-explorer): grant symlink targets path access on activation

Following a symlink out of the workspace was denied by the main-process
path allow-list, so both the stat and the file read failed. Activating the
row is explicit intent, so authorize the target the way terminal links and
Quick Open already do.

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 00:53:54 -07:00
Neil c5023fa0ab perf(main): skip impossible advertised URL scans (#13514) 2026-08-10 00:29:26 -07:00
Doyoon LeeandBrennan Benson 33dad13e64 fix: wrap unbroken auto-rename failure output (#12317)
* fix: wrap unbroken auto-rename failure output

* test(sidebar): cover unbroken auto-rename failure containment

happy-dom does no intrinsic sizing, so assert the two declarations that
keep an unbroken token from widening DialogContent's grid column. The
test fails when either min-w-0 or overflow-wrap:anywhere is reverted.

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-10 00:24:00 -07:00
Neil c498d763cd perf(renderer): unmount closed jump palette content (#13525) 2026-08-10 00:18:54 -07:00
Brennan Benson 8a3f704bd1 fix(agent-dashboard): highlight agents awaiting input (#13523)
* fix(agent-dashboard): highlight agents awaiting input

* test(agent-dashboard): cover status halo boundaries
2026-08-10 00:16:54 -07:00
Brennan Benson 0fa3a5bd1d Show directional lineage in agent map (#13503)
* Show directional lineage in agent map

* Route agent lineage links diagonally

* Guard agent map lineage path bounds

* Avoid chevrons in undersized lineage gaps
2026-08-10 00:16:21 -07:00
Neil abd160fadd perf(renderer): defer terminal quick command host work (#13517) 2026-08-09 23:43:58 -07:00