Commit Graph
1179 Commits
Author SHA1 Message Date
brennanb2025andOrca e46a686f78 Merge branch 'main' into brennanb2025/fix-worktree-no-track
Resolved conflicts in src/relay/git-handler.ts and
src/relay/git-handler.test.ts: kept this PR's --no-track +
push.autoSetupRemote state machine but moved it into addWorktreeOp in
the extracted git-handler-worktree-ops.ts (per main's #1672 split),
dropped the unused `track` param, and dropped the stale
this.context.validatePath calls (context is _context post-#1672).

Co-authored-by: Orca <help@stably.ai>
2026-05-10 23:11:29 -07:00
JinjingandOrca cc9f4bf083 feat(settings): list supported audio formats for Custom Sound (#1685)
Updates the Custom Sound search entry description and keywords to include
the supported formats (MP3, WAV, OGG, M4A, AAC, FLAC), and adds a small
caption under the setting's description in NotificationsPane for clarity.

Co-authored-by: Orca <help@stably.ai>
2026-05-10 21:58:16 -07:00
Brennan BensonandOrca 1041ab4f7c feat(agent-hooks): shared listener + relay adapter (PR 1/N for SSH agent status) (#1678)
* feat(agent-hooks): introduce relay wire envelope + connectionId stamping

Adds the shared `agent-hook-relay.ts` module with the `agent.hook` JSON-RPC
notification envelope, the `agent_hook.requestReplay` /
`agent_hook.installPlugins` method names, and the
`ORCA_FEATURE_REMOTE_AGENT_HOOKS` flag helper. Promotes `AgentHookSource` to
`shared/` so the relay can import it without dragging Electron in.

Threads a `connectionId: string | null` field through `AgentHookEventPayload`,
the `agentStatus:set` IPC contract, and the renderer-bound preload listener.
Local hook posts stamp `null`; the relay-forwarded path will stamp from `mux`
identity in a later commit. Renderer uses the stamp for stale-event filtering
when an SSH connection tears down with notifications still in flight.

See docs/design/agent-status-over-ssh.md §1, §5, §8 (commit #1).

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

* refactor(agent-hooks): extract shared listener; add relay-side adapter

Extracts the listener internals (request parsing, payload normalization,
endpoint-file writing, per-CLI extractors, warn-once Sets, slowloris timer
helper, request size cap, paneKey caches) from `src/main/agent-hooks/server.ts`
into a new transport-agnostic `src/shared/agent-hook-listener.ts`. The shared
module uses only Node builtins (no Electron) so it is safe to import from
`src/relay/`.

Adds `src/relay/agent-hook-server.ts` — a thin HTTP-loopback adapter that
wires the shared listener to a `forward(envelope)` callback so `relay.ts` can
re-emit each parsed payload as an `agent.hook` JSON-RPC notification on the
existing SshChannelMultiplexer. The adapter owns:

- 127.0.0.1:0 socket + bearer-token auth, identical shape to the local server
- per-paneKey last-payload cache + replayCachedPayloadsForPanes() for the
  request-driven replay path used after `--connect` reattach (see §5 Path 3)
- clearPaneState(paneKey) for PTY-exit eviction (symmetric with local server)
- buildPtyEnv() / endpoint-file writing for relay-spawned PTYs

Orca's `AgentHookServer` is now a ~200-LoC adapter over the shared listener
that owns the IPC fanout, listener replay, and `ingestRemote(envelope, connId)`
entry point that bypasses the HTTP path for relay-forwarded events.

See docs/design/agent-status-over-ssh.md §3, §8 (commit #2).

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

* fix(preload): expose connectionId on agentStatus.onSet type

src/preload/index.ts already passes through `connectionId?: string | null`
from main, but the PreloadApi declaration in api-types.ts was missing the
field. Align the type with the runtime contract so renderer call sites
can read connectionId without an `as` cast.

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

* fix(agent-hooks): harden ingestRemote + relay replay; review-driven cleanup

- ingestRemote: re-run normalizeAgentStatusPayload at trust boundary;
  trim+validate connectionId/paneKey/tabId/worktreeId
- relay: preserve source/env/version through replay via sidecar map;
  drop sourceFromAgentType fallback that mis-tagged unknown agents
- shared listener: exhaustive switch+never on AgentHookSource dispatch
  chains; extractPromptText returns trimmed values; export MAX_PANE_KEY_LEN
- preload: tighten connectionId from optional to required (always sent)
- main IPC: reorder spread so explicit envelope fields win on collision

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

* chore(docs): drop agent-status-over-ssh design doc from PR

The design RFC was useful for authoring this PR series but doesn't belong
in-tree — keeping it here would freeze line-number references and design
prose against future churn. Folding it into the PR description instead.

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

* chore(agent-hooks): widen ingestRemote type for env/version (PR2 prep)

Declares `env?: string` and `version?: string` on the `ingestRemote` envelope
parameter so PR2 only needs to add the `warnOnHookEnvOrVersionMismatch`
callsite, not also widen the type. The fields are forwarded verbatim from
the agent CLI POST body on the remote and let Orca's warn-once cross-build
/ dev-vs-prod diagnostics fire identically on remote-sourced events.

Type-only addition; no runtime consumer in this PR.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-10 21:57:48 -07:00
JinjingandOrca 908bc18234 feat(sidebar-filter): replace dropdown with searchable popover for repo filtering (#1684)
Replaces the DropdownMenu-based repo filter with a Command/Popover combo that
supports live search, All/None bulk actions, and a Clear all footer. Scales
to large repo sets without scroll friction. Design doc added at
docs/sidebar-filter-redesign.md.

Co-authored-by: Orca <help@stably.ai>
2026-05-10 21:47:15 -07:00
f446a8b460 fix: pr-bug-scan validated finding from #1680 (#1682)
* fix: address pr-bug-scan validated finding from #1680

On cold open, optimistic comments are now surfaced via a loading-shell fallback in the details memo, with a state tick so the memo re-runs after appendOptimisticComment.

* fix: address react-hooks lint warnings on #1680 fix-PR

- handleSubmit useCallback: add missing itemType dep
- details useMemo: keep optimisticTick (rerender signal for cold-open
  ref reads) with eslint-disable + why-comment

---------

Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
Co-authored-by: nwparker <neil@stably.ai>
2026-05-10 21:29:25 -07:00
buf0-bot[bot]andorca-bug-scan-bot 236087d25d fix: pr-bug-scan validated finding from #1671 (#1681)
Add legacy version-first ID branches (3-5-sonnet, 3-5-haiku) in normalizeModelForPricing so legacy logs map to existing pricing entries instead of returning null.

Co-authored-by: orca-bug-scan-bot <orca-bug-scan-bot@stably.ai>
2026-05-10 21:02:51 -07:00
Jinwoo HongandOrca c88287fa9a Fix Codex account auth read-back guard (#1629)
* Fix Codex account auth read-back guard

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

* Guard Claude auth read-back identity

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

* Fix Claude auth read-back test on Linux

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

* Require positive Codex auth identity match

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

* Address auth read-back review gaps

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

* Harden managed auth read-back state machine

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

* Harden managed auth token read-back

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

* Isolate managed Codex launch homes

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

* Keep managed Codex homes in sync

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

* Revert "Keep managed Codex homes in sync"

This reverts commit bce1ecdc38.

* Revert "Isolate managed Codex launch homes"

This reverts commit 826a6c4773.

* Clarify shared Codex auth routing comment

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

* Route Codex auth read-back by identity

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

* Route Claude auth read-back by identity

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

* Handle corrupt Codex auth snapshots

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

* Reject stale cold-start auth read-back

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-10 20:39:38 -07:00
JinjingandOrca b501a6faa0 fix(github-drawer): eliminate reopen flash via useSyncExternalStore (#1680)
Replace the setState-driven data flow with useSyncExternalStore so the
drawer reads cached work-item details synchronously on first render.
Warm reopens now paint the cached content immediately with zero blank
flash. Adds a pub/sub layer (subscribeWorkItemDetailsCache /
notifyWorkItemDetailsCache) to all cache-write paths so React is
notified on every touch or invalidation. Includes design doc at
docs/gh-work-item-drawer-cache-flash.md.

Co-authored-by: Orca <help@stably.ai>
2026-05-10 19:53:05 -07:00
Brennan BensonandOrca 1f43346c5f fix(resource-usage): hydrate pty-registry at boot; render · remote only for SSH repos (#1667)
* WIP: Changes before auto-review fixes

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

* fix: address auto-review-fix-multi-agent findings

- Replace local ORCA_WORKTREE_ID_SEPARATOR with shared WORKTREE_ID_SEPARATOR
- Make hydrateLocalPtyRegistryAtBoot idempotent (one-shot per process,
  but stays retry-eligible until daemon provider is available)
- Strengthen daemon-pty-adapter strict-parser test to actually exercise
  the new short-circuit (test would have passed under the old loose
  parser too without the change)
- Add eslint-disable max-lines directive to oversized merge test file

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

* chore: archive auto-review context to .context/

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

* fix: address auto-review-fix findings

Drop the destructive reconcileOnStartup call from boot-time PTY registry
hydration: a transient listRepoWorktrees failure (returns [] and only
warns) would otherwise let the reconcile pass kill live local sessions.
The boot path is now read-only against the daemon — listSessions() only.

Also: tighten parsePtySessionId to reject degenerate `::` halves; replace
stale pty.ts:1005 references and a misleading local-unknown comment in
the hydrate module; narrow Store dependency to Pick<Store, 'getRepos'>;
log adapter listSessions failures instead of silently swallowing them;
re-anchor design-doc references on stable symbols and align §1b/§1c/§1d
with the implementation.

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

* docs(resource-usage): update remote badge spec

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

* test(resource-usage): cover boot hydration failure modes + warm-reattach e2e

Adds the regression coverage flagged in PR #1667's test plan that wasn't
already locked down.

vitest (`hydrate-local-pty-registry.test.ts`):
  - daemon offline at first call → no-op, hasHydrated stays false so a
    later macOS dock re-activation can retry.
  - listSessions rejection caught and logged, does not throw.
  - pid-write ordering: a pre-existing registry entry with pid=12345 is
    not clobbered by a stale `pid: null` from listSessions (§1d).
  - SSH-gate: a session whose repo has a non-null connectionId stays out
    of the registry, mirroring the spawn-time gate in pty.ts.
  - Happy-path: a local session is registered with the daemon's pid.

Playwright e2e (`resource-usage-warm-reattach.spec.ts`):
  Full quit→relaunch cycle against the same userDataDir; asserts that
  on the second launch the snapshot includes the warm-reattached PTY
  with a real pid before any pane mount, and that the seeded repo
  resolves as local (no connectionId). Mirrors the existing
  terminal-restart-persistence pattern.

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

* fix(test): satisfy Pick<Store, 'getRepos'> in hydrator vitest

CI typecheck failed because FakeStore's getRepos returned objects missing
Repo's required fields (path, displayName, badgeColor, addedAt). Fill with
placeholder values; the hydrator only reads id + connectionId, but the
type signature still has to line up.

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

* chore(resource-usage): drop bug-doc files; strip dead doc refs from comments

Remove docs/resource-usage-remote-mislabel.md (new in this PR) and revert
docs/resource-usage-merge-spec.md to the PR-base state. Strip the
matching `docs/...md §N` pointers from code/test comments, keeping the
surrounding "why" explanations intact so readers still get the
warm-reattach mislabel context.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-10 17:17:52 -07:00
Neil ad5d5dc841 fix terminal complex script rendering (#1675) 2026-05-10 16:53:24 -07:00
01bab271eb Fix PTY config overlays being overwritten by shell startup files (#1628)
* Fix OpenCode config overlay env in PTYs

* Fix Pi agent dir overlay env in PTYs

* Restore overlay env in Windows and fallback shells

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

* test(opencode): tighten overlay restore guards

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

---------

Co-authored-by: Orca <help@stably.ai>
Co-authored-by: brennanb2025 <brennankbenson@gmail.com>
2026-05-10 16:13:06 -07:00
Brennan BensonandOrca 9290b25307 fix: gate worktree status on live PTYs so sleep reports inactive (#1603)
* fix: gate worktree status on live PTYs so sleep reports inactive

Sleep preserves tab.ptyId as a wake-hint sessionId, so the previous
liveness check (`tab.ptyId != null`) kept the workspace dot green and
agent rows as "working" until the 30-min stale TTL decayed them.
Switch liveness to ptyIdsByTabId (cleared by every pty.kill / sleep)
via a new tabHasLivePty helper, and drop live agentStatusByPaneKey
entries on sleep so the inline rows disappear with the dot. Retained
"done" rows survive — that signal is dismissed by the user, not the
system.

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

* fix: drop retained agent rows on worktree sleep

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

* WIP: Changes before auto-review fixes

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

* fix: preserve slept worktree status liveness

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

* fix: treat slept pty hints as inactive

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

* chore: remove sleep status planning docs

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-10 16:02:16 -07:00
Jinwoo HongandOrca ea9a718e29 fix(ssh): remove relay FS path allowlist to support symlinks outside workspace (#1661) (#1672)
When a remote SSH workspace contains a symlink whose target lies outside
the registered repo/worktree roots, file reads failed with 'Path outside
authorized workspace'. This silently broke common workflows: HPC dataset
mounts, multi-checkout repos, dotfile editing, and any cross-mount
symlink.

Drop `RelayContext.authorizedRoots`, `validatePath`, and
`validatePathResolved` along with all ~33 call sites in fs-handler.ts
and git-handler.ts. The relay's threat model becomes 'the relay runs as
the SSH user and trusts the renderer.'

Why this is acceptable: `pty.spawn` and `git.exec` already concede the
same threat. A renderer that wants to reach `/etc/passwd` can spawn a
shell or run `git -C /etc cat-file`; the FS allowlist was friction, not
a security boundary. Intra-worktree path checks in `getDiff` and
`discard` are intentionally preserved.

Back-compat preserved: `session.registerRoot` (notification + request)
remains a valid RPC, retained as no-ops on new relays. Old main + new
relay and new main + old relay both keep working through the upgrade
window. `registerRelayRoots` is also kept for the same reason. A
narrowed error-translation block in `worktree-remote.ts` handles old
relays still surfacing the legacy error string to users.

Tests: removed two negative-allowlist tests; added a positive control
('reads files outside any registered root') and a direct regression
test for #1661 ('reads files via symlinks resolving outside the
workspace'). All 469 relay/SSH/IPC tests pass.

See docs/relay-fs-allowlist-removal.md for the full rationale,
back-compat matrix, alternatives considered, and follow-up cleanup
plan.

Closes #1661

Co-authored-by: Orca <help@stably.ai>
2026-05-10 15:59:54 -07:00
Brennan BensonandOrca 98b15aeabc feat(telemetry): instrument on_path:false triage on onboarding_agent_picked (#1674)
* feat(telemetry): instrument on_path:false triage on onboarding_agent_picked

Adds path_source and path_failure_reason to onboarding_agent_picked so the
~30% on_path:false rate on dashboard 1562016 can be split between shell
hydration failures and genuinely-not-on-PATH cases before picking a fix.
See docs/agent-on-path-detection.md.

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

* fix(telemetry): close PathSource compile-time-sync hole

Add `_PathSourceSync` guard mirroring `_PathFailureReasonSync` so adding
a new `PathSource` value to the alias without updating the schema (or
vice versa) fails the build. Without it, drift would silently drop
`onboarding_agent_picked` at the strict validator. Also replace stale
line-number references in docs/agent-on-path-detection.md with named
function/handler references that survive future edits.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-10 15:47:14 -07:00
JinjingandOrca 24c1254caa feat(source-control): add Stage Files primary button (#1670)
When there are unstaged/untracked changes but nothing staged yet, the
Source Control primary button now reads "Stage Files" and bulk-stages all
unstaged + untracked paths in one shot, so users can immediately hit
Commit on the next click without manually staging first. This replaces
the previous behavior where Pull/Sync/Push/Publish could appear as the
primary on a dirty tree and then fail with "Please commit or stash them".

Co-authored-by: Orca <help@stably.ai>
2026-05-10 14:45:46 -07:00
Jinjing 36ee48fd9c fix(claude-usage): correct Anthropic model pricing (#1671) 2026-05-10 14:41:46 -07:00
Brennan BensonandOrca 8977c7e917 feat(telemetry): track agent_hook_install_failed per agent (#1668)
* feat(telemetry): track agent_hook_install_failed per agent

Replaces the closure-style installer loop in `src/main/index.ts` with a
labelled `runManagedHookInstallers` so each catch can attribute the
failure to its agent. Adds the `agent_hook_install_failed` event +
`hookInstallAgentSchema` enum (claude/codex/gemini/cursor) and a unit
test pinning fail-open semantics, label routing, and the 200-char
error_message truncation.

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

* fix(telemetry): harden agent-hook installer fail-open

- describeError always returns a string (JSON.stringify can return
  literal undefined for throw undefined / Symbol / function, which
  would crash the catch handler before track fires)
- wrap track() in inner try/catch so a telemetry-side throw can't
  abort the installer loop
- dedupe AGENT_HOOK_TARGETS into one tuple in agent-hook-types so
  the IPC AgentHookTarget type and hookInstallAgentSchema can't drift
- regression tests for object/undefined throws and track-throws

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-10 14:41:40 -07:00
JinjingandOrca 4ded9e6e9d fix(codex-usage): correct Codex model pricing table (#1669)
Update MODEL_PRICING to current Codex rates: add gpt-5.1, gpt-5.4, gpt-5.5;
rename gpt-5.2-codex -> gpt-5.2 with corrected rates; align gpt-5.3-codex
rates. Stop aliasing gpt-5.4 to gpt-5 in normalizeModelForPricing.

Co-authored-by: Orca <help@stably.ai>
2026-05-10 13:58:25 -07:00
Brennan BensonandOrca a18e5c97a5 feat(diff-viewer): scroll to first change when opening a diff (#1620)
* feat(diff-viewer): scroll to first change when opening a diff

On a fresh diff tab open (no cached view state, no pending scroll-to-note),
center the first diff change in the viewport. Cached view state and
explicit scroll-to-note requests still win.

The scroll runs from a dedicated useEffect, not from handleMount, so it
sequences after the comment-decorator inserts its view zones — otherwise
late zone insertion shifts content downward and the user lands on a note
further down the file instead of the first change.

Uses getTopForLineNumber(line, /* includeViewZones */ true) so the math
accounts for whatever zones the decorator added in this render pass.
A one-shot ref guards against re-firing on later effect re-runs.

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

* test(window): mock ipcMain.handle/removeHandler in createMainWindow.test

The pr-bug-scan from #1583 added an ipcMain.handle('window:isMaximized', …)
call to createMainWindow but didn't extend this test's electron mock. Main
already added these mocks (PR #1634); add them here so the branch's CI passes.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-10 13:58:01 -07:00
NeilandNeil Parker 7212118437 fix(windows): tab row overlaps window-controls buttons (#1664) (#1665)
* fix(windows): tab row drag region overlaps window-controls overlay

The top-right tab group's no-drag spacer was hardcoded to 40px (for the
floating sidebar toggle). On Windows the fixed-position window-controls
overlay (138px wide) sits on top of the same corner, making the buttons
unreachable when the tab row's drag surface extended under them.

Widen the spacer to calc(40px + var(--window-controls-width, 0px)) so
it punches a hole for both the sidebar toggle and the overlay. The var
is 0px on non-Windows so this is a no-op there. Fixes #1664.

* fix(windows): remove double-compensation spacers from toggle and sidebar header

Two places were using both a CSS-based offset AND an internal spacer div,
doubling the reserved width (276px instead of 138px):

1. Floating right-sidebar toggle (workspace view): the container already
   uses right:var(--window-controls-width) to position itself clear of
   the overlay. The extra window-controls-titlebar-spacer inside was
   pushing the button further left AND laying an invisible 138px div over
   the pane-actions Ellipsis button, blocking clicks.

2. Right sidebar header (both layout modes): the header already has
   right-sidebar-header-inset = padding-right:var(--window-controls-width).
   The internal spacer was double-compensating, shifting the close button
   far left with wrong spacing.

Remove the internal spacers from both. The single offset mechanism in
each case is sufficient.

* fix(windows): side-mode sidebar header has wrong gap before minimize button

In side activity-bar mode the 40px icon strip sits to the right of the
panel content, so the panel header never reaches the window-controls zone.
The right-sidebar-header-inset class (padding-right: 138px) was still
applied, pushing the close button 178px from the window edge and producing
a 40px visual gap between the close button and the minimize button.

Remove the inset class from the side-mode header only. The top-mode header
spans to the window edge so it still needs the inset.

* fix(windows): side-mode header close button overlaps minimize button

The 40px side activity bar absorbs only 40px of the 138px window-controls
overlay, leaving 98px of overlap on the panel header. The previous commit
removed all inset (making the gap 0), which caused the close button to
sit under the minimize button.

Add .right-sidebar-header-side-inset with padding-right:
  max(0px, calc(var(--window-controls-width, 0px) - 40px))
= 98px on Windows, 0px elsewhere — exactly the uncovered remainder.

* fix(lint): remove unused isWindows variable in right-sidebar

---------

Co-authored-by: Neil Parker <nwparker@anthropic.com>
2026-05-10 12:12:52 -07:00
NeilandOrca 5f0f4b6916 fix(new-workspace): use Linear logo instead of "L" placeholder (#1657)
Co-authored-by: Orca <help@stably.ai>
2026-05-10 00:15:03 -07:00
Neil 4fb2829b2c fix: avoid updater relaunch crash (#1656) 2026-05-09 23:52:31 -07:00
JinjingandOrca ace7db218d perf(github-drawer): cache work-item details + collapse issue fetch (#1655)
Reopening a GitHub issue/PR drawer paid full IPC + `gh` startup latency on
every open. Two changes here:

1. Module-level SWR cache in GitHubItemDialog.tsx keyed by
   (repoPath, issueSourcePreference, type, number). Reopening within 30s
   paints cached data instantly; older entries paint stale-then-refresh.
   Concurrent opens dedupe on a shared in-flight promise. Mutation
   handlers invalidate by (repo, type, number); a cache-generation
   counter prevents in-flight refetches from resurrecting stale data
   after a mid-flight invalidation.

2. Collapsed GraphQL query for issue details replaces 3 serial `gh`
   subprocesses (REST issue + REST comments + GraphQL participants) with
   one round-trip. Falls back to the legacy fan-out on any GraphQL error
   so historical contract is preserved.

Cross-window invalidation rides a new `gh:workItemMutated` IPC broadcast
that skips the originating sender (the source already updated its cache
optimistically — re-broadcasting would race the optimistic write).
`addIssueComment` now takes a `type` so the broadcast scopes correctly
when a PR shares its number with an issue.

Co-authored-by: Orca <help@stably.ai>
2026-05-09 23:46:30 -07:00
JinjingandOrca 8f41634f5f fix: address review findings for project cell click area (#1654)
Co-authored-by: Orca <help@stably.ai>
2026-05-09 22:58:02 -07:00
Neil 7257bb410d fix: preserve mac updater relaunch (#1653) 2026-05-09 22:33:01 -07:00
NeilandOrca b635b12b47 fix(status-bar): hide usage bars for agents not on PATH (#1651)
* fix(status-bar): hide usage bars for agents not on PATH

When a CLI like Gemini isn't installed, the corresponding usage bar (and
its right-click / Settings toggle) was still surfaced — e.g. a fresh
Ubuntu install showing 'Gemini Usage' with no Gemini CLI on PATH.

Gate the Claude/Codex/Gemini bars + toggles on the existing
preflight.detectAgents() result. OpenCode Go is intentionally exempt
(it's a web/cookie-auth provider, not a CLI on PATH). Pre-detection
(null) preserves legacy behavior so nothing flickers on cold start, and
bars/toggles re-appear automatically once the CLI shows up on PATH.

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

* fix(status-bar): refresh agent detection alongside rate-limit refresh

Self-review follow-up: when a user installs a new CLI (e.g. Gemini) after
Orca is already running, clicking the status-bar refresh button should
make the corresponding usage bar appear without an app restart.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-09 21:27:39 -07:00
JinjingandOrca f02787b806 fix: cmd+t always opens terminal in central pane (#1650)
When the active surface was a browser tab (or focus was inside a
browser guest webview), Cmd/Ctrl+T was creating a new browser tab
instead of a terminal. Make Cmd/Ctrl+T always open a new terminal
regardless of active surface; Cmd/Ctrl+Shift+B remains the dedicated
new-browser-tab shortcut.

Co-authored-by: Orca <help@stably.ai>
2026-05-09 21:07:42 -07:00
buf0-bot[bot]andorca-bot de6b3b8e0e revert: remove mid-session defaultTaskSource sync from #1468 (#1649)
Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 20:57:54 -07:00
JinjingandOrca 589076058c refactor(sidebar): tidy worktree list group header layout (#1646)
* refactor(sidebar): tidy worktree list group header layout

Move the collapse chevron next to the group label, swap repo icon for a neutral muted Folder, and adjust header padding for better alignment.

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

* style: minor padding tweaks on worktree group header

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-09 20:32:26 -07:00
Neil f0021d5219 fix: handle ssh transport loss without app exit (#1645) 2026-05-09 19:49:11 -07:00
Neil 41b4a2bc50 Use artifact titles for created workspaces (#1643) 2026-05-09 18:51:07 -07:00
Neil 4789a3cd51 Update titlebar app name controls (#1644) 2026-05-09 18:48:53 -07:00
Neil 3b87505a97 feat: show unread count in macOS Dock (#1641) 2026-05-09 18:28:56 -07:00
JinjingandOrca 7c51f07858 fix: allow any composer ancestor for cmd+enter submit (#1639)
Co-authored-by: Orca <help@stably.ai>
2026-05-09 18:17:39 -07:00
buf0-bot[bot]andorca-bot 778691e6a1 revert: remove re-introduced fetchWorktrees poll from #1572 (#1637)
The buf0-bot fix-PR #1572 (findings from #1524) re-added a 30s
focus-gated fetchWorktrees poll in useGitStatusPolling that #1524 was
specifically removing. The other two findings in #1572 (worktrees:list
auth-cache poisoning and detached-HEAD encoding) are preserved.

Why: parent PR #1524's intent was to reduce background polling; the
bot's 'restoration' was an unintended behavior re-add framed as a bug
fix.

Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 17:44:28 -07:00
buf0-bot[bot]andorca-bot aa70c943f4 Revert "fix: pr-bug-scan findings from #1551" (#1571) (#1635)
Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 17:41:47 -07:00
buf0-bot[bot]andorca-bot 2b133972fa Revert "fix: pr-bug-scan findings from #1468" (#1559) (#1636)
Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 17:40:48 -07:00
Cristian Lopez 1736f08dc7 fix(tabs): close-others/close-to-right on editor & browser tabs
Fix mixed terminal/editor/browser tab context menu actions by resolving visible ids back to unified tab ids and counting all visible tab kinds for Close Others.\n\nAdds regression coverage for TabBar menu wiring and TabGroupPanel visible-id resolution.
2026-05-09 17:19:35 -07:00
JinjingandOrca 2e1a3ab17a Revert "fix: pr-bug-scan findings from #1565" (#1634)
Co-authored-by: Orca <help@stably.ai>
2026-05-09 16:52:34 -07:00
Jinjing cd30a335d1 fix: address review findings (#1633) 2026-05-09 16:32:07 -07:00
NeilandNeil Parker 09ca40e4ac fix(windows): window-controls hover height matches titlebar (#1632)
* feat(windows): custom title bar with renderer-drawn window controls

Replace the default Windows native title bar with a custom renderer-drawn
titlebar to match the macOS experience:

- Set titleBarStyle:'hidden' on win32 to remove the OS chrome
- Add min/max/close buttons (Fluent-style SVG) fixed to the top-right corner,
  rendered last in DOM order so they're never blocked by -webkit-app-region:drag
- Route close through IPC (window:close-requested) so the terminal-running
  confirmation guard stays active; minimize/maximize via window:minimize and
  window:maximize IPC channels
- Add maximize state sync (window:maximize-changed) so the restore icon shows
  correctly
- Add Orca logo + ··· application-menu button on the left in place of the bare
  pl-2 spacer; ··· calls Menu.getApplicationMenu().popup() replicating Alt-key
  reveal
- Add window-controls-titlebar-spacer to reserve 138px on the right of the
  full-width titlebar so content isn't obscured by the overlay

* fix(windows): titlebar logo color and window-controls overlap

- Logo light-mode invert: :not(.dark) selector was matching in dark mode
  because .dark lives on <html> (:root), not on a descendant. Fixed to
  :root:not(.dark) so the invert(1) filter only fires in light mode.

- Overlap with right-side controls: introduce --window-controls-width CSS
  var (138px on Windows, 0px elsewhere) on the root div so every affected
  surface reads a single source of truth:
  - Workspace-view floating sidebar toggle (absolute top-0): right now uses
    var(--window-controls-width) instead of hardcoded 0
  - window-controls-titlebar-spacer width uses the var
  - Right sidebar header: new .right-sidebar-header-inset class adds
    padding-right: var(--window-controls-width) to both the top-activity-bar
    and side-layout header variants so the close button is never hidden

* fix(windows): window-controls hover must not bleed below titlebar

The .window-controls container and .window-controls-btn were both 42px
tall while the titlebar is 36px. The hover background filled the full
button height, painting 6px of highlight into the content area below
the titlebar. Shrink both to 36px to match.

* fix(windows): side activity bar icons obscured by window-controls overlay

In side-bar activity-bar mode the icon strip is flush against the right
window edge. The fixed-position window-controls overlay (138×36px)
covers the top-right corner, making the topmost icons unreachable.

Add --window-controls-height (36px on Windows, 0px elsewhere) CSS var
and apply it as padding-top on the side activity bar via
.side-activity-bar-windows-inset — same pattern used by
--window-controls-width for the horizontal dimension.

---------

Co-authored-by: Neil Parker <nwparker@anthropic.com>
2026-05-09 16:20:02 -07:00
buf0-bot[bot]andorca-bot 616dbb3117 fix: pr-bug-scan findings from #1564 (#1610)
Restored proportional-alpha fade for antialiased magenta-key edges by replacing the hard g>=60 gate with a dominance-floor (dom>0.4) check while keeping purples/pinks rejected.

### Findings addressed
- ✅ [medium] src/renderer/src/components/pet/pet-blob-cache.ts:130 — Magenta key no longer fades antialiased edges, leaving halos

Rebased onto current main; bot's intended file (sidekick-blob-cache.ts) maps to current main's pet-blob-cache.ts (sidekick rename hasn't landed).

Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 04:10:33 -07:00
buf0-bot[bot]andorca-bot e6e45dc22a fix: pr-bug-scan findings from #1565 (#1613)
Added windowsShell parameter to buildAgentDraftLaunchPlan so the post-exit clear-var uses Remove-Item Env: on PowerShell/pwsh and set "FOO=" on cmd.exe; threaded settings.terminalWindowsShell through both call sites.

### Findings addressed
- ✅ **[high]** `src/renderer/src/lib/tui-agent-startup.ts:160-163` — Windows clear-var command only works in cmd.exe, breaks in PowerShell

Rebased onto current main; added settings?.terminalWindowsShell to the useCallback dep array in useComposerState to satisfy react-hooks/exhaustive-deps.

Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 04:07:39 -07:00
buf0-bot[bot]andorca-bot 337ae272b8 fix: pr-bug-scan findings from #1569 (#1611)
Made installRemoteWatcher return tri-state ('installed'|'unavailable'|'cancelled') so scheduleRemoteWatcherRetry only re-arms on 'unavailable', preventing stale overflow after unwatch/shutdown.

Findings addressed:
- [medium] src/main/ipc/filesystem-watcher.ts:540-549 — Cancelled install reschedules retries; stale overflow fires after unwatch

Rebased onto current main to resolve conflicts.

Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 04:06:13 -07:00
buf0-bot[bot]andorca-bot f8837fe3f3 fix: pr-bug-scan findings from #1562 (#1612)
Added DeviceRegistry.rotatePendingDevice and threaded a 'rotate' option through the mobile:getPairingQR IPC + preload + MobilePane so explicit Regenerate clicks mint a fresh pending token instead of returning the same one.

Findings addressed:
- [medium] src/main/runtime/device-registry.ts:44-50 — 'Regenerate QR' no longer rotates the token

Rebased onto current main to resolve conflicts.

Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 04:05:55 -07:00
buf0-bot[bot]andorca-bot f2c01d837d fix: pr-bug-scan findings from #1586 (#1615)
PetOverlay loadStoredPosition now falls back to the legacy 'sidekick-overlay-position' localStorage key and write-throughs to the new key. Deleted orphaned src/main/ipc/sidekick-pet-bundle.ts and its test.

Rebased onto current main to resolve conflicts.

Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 04:03:00 -07:00
buf0-bot[bot]andorca-bot 4541383f87 fix: pr-bug-scan findings from #1599 (#1616)
Made updateWorktreeMeta best-effort in launch-work-item-direct so a meta write failure no longer aborts the already-created workspace and orphans it.

### Findings addressed
- ✅ **[medium]** `src/renderer/src/lib/launch-work-item-direct.ts:243` — Meta update failure now aborts a successfully created workspace

Rebased onto current main to resolve conflicts.

Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 04:02:43 -07:00
buf0-bot[bot]andorca-bot 5c29d5338f fix: pr-bug-scan findings from #1597 (#1614)
Added process.on('exit') restore handler so the renamed spawn-helper is restored even if the vitest worker is killed mid-test.

Findings addressed:
- [low] src/main/daemon/node-pty-fd-leak.test.ts:57 — Test renames helper binary; crash leaves it hidden

Rebased onto current main to resolve conflicts.

Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 04:02:19 -07:00
buf0-bot[bot]andneil 5dfcf1eaca fix: pr-bug-scan findings from #1596 (#1617)
Fixed onboarding next() re-entrance with a synchronous in-flight ref guard, and tightened sanitizeOnboardingUpdate's closedAt to require a finite non-negative number.

Findings addressed:
- [medium] src/renderer/src/components/onboarding/use-onboarding-flow.ts — next() not re-entrant
- [low] src/main/persistence.ts — sanitizeOnboardingUpdate accepts NaN/Infinity for closedAt

Rebased onto current main to resolve conflicts; preserved main's advancedVia parameter and duration_ms telemetry inside the new in-flight guard.

Co-authored-by: neil <neil@stably.ai>
2026-05-09 03:59:33 -07:00
buf0-bot[bot]andorca-bot 9db736c330 fix: pr-bug-scan findings from #1583 (#1618)
Fixed Windows titlebar bugs: WindowControls icon now seeded via new ipc isMaximized() getter on mount; CSS height dropped from 42px to 36px; spacer added to floating right-sidebar toggle and RightSidebar header so content isn't occluded.

Findings addressed:
- [medium] src/renderer/src/App.tsx:50-54 — WindowControls maximize icon wrong on startup if window starts maximized
- [medium] src/renderer/src/assets/main.css:434-460 — Window controls 42px tall but titlebar 36px — bottom 6px overlays content
- [low] src/renderer/src/App.tsx:776-803 — Spacer only rendered in workspace-active titlebar branch

Rebased onto current main to drop ~140 unrelated stale-main reverts; only the 6 Fixer-summary files are touched.

Co-authored-by: orca-bot <bot@stably.ai>
2026-05-09 03:59:12 -07:00