* fix(terminal): verify an exact stop through an overlapping liveness inventory
terminal.stopExact re-read the PTY inventory once after the stop. When a newer
inventory started meanwhile (the exit's own session republish triggers one),
the older read was voided as stale and the confirmed stop came back as
terminal_liveness_unavailable, so hibernating a remote pane on a busy host
rolled back. Retry the post-stop read within one list budget.
* test(terminal): keep the post-stop liveness failure fixture unavailable across retries
* fix(agents): preserve quick-launch presets in legacy tab creation
* fix(agents): + quick launch on a paired host uses the desktop's launch settings
An empty-prompt agent tab opened with + on a paired or SSH-tunnelled host
sent only the agent id, so modern hosts used their own default args and
legacy hosts rebuilt the command from host settings. Send the same
startup plan the prompted launch already sends, so both
terminal.createAgentSession (agentArgs) and the legacy
session.tabs.createTerminal fallback get the desktop's arguments.
Replaces the legacy-only legacyStartupPlan field and its linux/darwin gate:
one launch shape now serves both paths, matching prompted launches.
Fixes#31986
Co-authored-by: StrangerG <8511644+StrangerG@users.noreply.github.com>
---------
Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: StrangerG <8511644+StrangerG@users.noreply.github.com>
* perf(emulator): accumulate MJPEG chunks instead of re-joining partial frames
A simulator frame spans many socket chunks, and extractJpegFrames re-concatenated
the growing partial frame on every chunk, which is quadratic in chunks per frame on
the Electron main thread. Hold chunks until one could complete the frame, then join
once. Held chunks are copied, so no caller chunk memory is retained.
* perf(emulator): ignore empty MJPEG chunks in the accumulator
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* refactor(worktrees): remove unreachable legacy worktree list IPC
The desktop and web preloads both always provide `worktrees.listDetected`,
so the renderer's fallback to `worktrees.list` never ran, and nothing calls
`worktrees.listAll`. Remove both IPC handlers, their preload/web wrappers,
the renderer fallback, and helpers only they used. Tests that observed
behaviour through the removed handlers now go through `worktrees:listDetected`.
* test(worktrees): drop removed list channels from SSH listing matrix
Address review: the canonical SSH listing test built channel names dynamically
and still invoked worktrees:list/listAll. Also fold the detected-result reader
into the shared worktree test fixtures, refresh stale comments, and assert the
backfill no-op test listed authoritatively.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* refactor: project structured status once per host emission
* test: keep host fixture literals checked against Tab
* test: declare the nullable bridge store without a cast
* refactor: compare tab membership directly at the read gate
* test: isolate approval activity fixture from GitHub refresh
* fix: recover status projection cleanup and bound removal work
* test: give status apply spy a callable type
* Scope structured status membership to host groups
* Type structured status lifecycle fixture tabs
* fix(native-chat): a goal set while the agent rests clears the composer
Setting a goal starts the agent when none is running, which moves the
session's runtime fence before the host answers. The composer dropped
that successful answer as stale, so the objective and Goal chip stayed.
Keep the reply for goal changes as for the other writes that may start
the agent.
* fix(native-chat): settle each command independently of runtime changes
* fix(native-chat): scope rewind timeout feedback to its issuing pane
* test: use checked native chat command fixtures
* test: complete native chat presentation fixtures
* fix(native-chat): admit Stop before capability discovery
* test(native-chat): consolidate overlapping startup coverage
* test(native-chat): preserve IME composition on goal acceptance
* fix(native-chat): capture each action before async preparation
* fix(native-chat): preserve shared Stop failure reporting
* test(native-chat): cover already-sent queue notices after disposal
* fix: keep stale linked-reference status inline
* fix: shimmer stale reference rows without a clock
* docs: compare row and shadcn text shimmer treatments
* fix: shimmer only stale reference metadata
* fix: remove obsolete row shimmer class
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* test: strengthen hook, build, and mobile lifecycle coverage
* fix: use relocated Jira types in issue user field
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* feat(agents): store each agent's permission itself instead of typing flags into Arguments
Terminals and new chats read one stored choice per agent (Use the agent's own
settings, Ask for approval, Accept edits, Approve for me, Full access). Orca adds
the flag at launch; Arguments hold only the user's own text. A one-time move
lifts Orca's flags out of saved Arguments. Older clients still see and write
the flag as part of Arguments; the host translates.
* fix(agents): say the all-agents switch resets agents set separately; keep primitives unstyled
* test(agents): the one-time move returns every launch-profile field
* Fix permission carrier ownership and surface-specific defaults
* Preserve uncertain permission operands and name the option inventory
* Check env entries without indexing typed agent maps
* Combine Chat permission capability imports
* Use folder execution-host platform for permission environment
* Preserve launch map replacement and acknowledge permission saves
* Keep permission feedback fallbacks statically discoverable
* Provide preload platform to Agents settings render tests
* Preserve Gemini approval arguments under Full access
* fix(settings): retain complete environment edits through save outcomes
* fix(settings): narrow local failure scope and preserve host messages
* fix(settings): retire argument drafts after acknowledged saves
* fix(settings): keep Goose environment editable after reset
* fix(settings): show resolved arguments for legacy hosts
* Preserve pending environment resets and bound launch settings work
* Keep optional settings fallback in repository metadata reads
* Read repository visibility defaults through the raw settings fixtures
* Prepare whole Environment edits and retire unchanged drafts
* Keep Environment settings transitions in an acyclic module
* Update raw settings reader test fixtures
* Place test fixture safety notes on assertion starts
* test: pin permission settings work and recovery contracts
* test: type permission settings work fixtures
* test: cover migrated permission inputs and captured CLI grammar
* test: preserve typed permissions in WSL Claude restarts
* Transfer keyboard focus when a sibling chat pane opens
* fix(native-chat): hand focus to newly opened chat composer
* fix(native-chat): keep tab bar controller within line limit
* fix(chat): split into a fresh conversation beside the current chat
* test(chat): declare the split fixture store without an assertion
* fix(chat): route the split to the source conversation host
* test(chat): keep the split regression focused on the launch contract
* test(chat): give the command palette split fixture its conversation agent
* test(chat): seed the legacy command fixture without expanding its asserted shape
* test(chat): isolate pane identity commands from the split launch boundary
* Prevent chat splits from starting a terminal on host refusal
* Cancel structured launches when their destination pane closes
* Model live destination groups in agent launch test fixture
* Capture split chat focus intent at the user action
* feat(chat): add the terminal pane hover action cluster
* fix(chat): keep pane controls above the conversation surface
* refactor(chat): share the tab resume launch hook and format pane controls
* style(chat): document reuse of the terminal header button styles
* refactor(ui): share the pane title button variants between terminals and chats
* fix(chat): keep header actions scoped to the displayed chat
* fix(chat): abandon Resume when its destination pane closes
* test(chat): declare destination fixtures without type assertions
* fix(chat): keep Resume visible when its source pane closes
* fix(chat): reuse tab menu Resume placement unchanged
* test: fix Resume regression harness setup
* fix(chat): hand input to the split pane during admission
* fix(chat): Split opens a fresh chat beside the current one
Split Right/Down on a native chat used to move the chat into a new pane.
It now opens an empty pane beside the chat and launches a new chat of the
same agent on the same host into it through the New Chat launch, so the
new composer takes focus at once. A launch that never opens a tab closes
the empty pane. Drops the earlier admission and focus-transfer changes
that main now covers.
* fix(chat): Split palette search words describe a new chat, not a move
* fix: remove misleading chat move shortcut hints
* fix(chat): a new chat stays in its pane until its host lists it
A host tab list built before a chat's create landed can arrive after the
create reply. Once the reply settled the launch, nothing protected the new
tab, so that older list dropped it: Split's new pane collapsed and focus
moved to another chat, and the next list re-added the chat elsewhere.
Keep a small in-memory record for a chat this client created that no host
list has shown yet. While it exists, a list that omits the chat keeps its
tab. The record ends when an accepted list from that host includes the
chat, when the tab closes, on workspace teardown, or 30 seconds after the
reply, when the worktree is re-read from its host (including an unchanged
version) so a chat the host really closed is dropped then. The launch
lifecycle, status, persistence and settlement are unchanged.
* test(chat): type the faked create replies without an assertion
* Keep new chat protection tied to accepted host lists
* Update paired chat close regression to current suppression API
* fix(chat): Portuguese Split palette words describe a new chat
* test(chat): use the destination group option in split fixture
* Avoid History projection in native chat header and currentness checks
* fix(native-chat): keep Find below pane controls
* fix(ui): keep noninteractive tooltip layers pointer-transparent
* Mount native chat actions only for shown panes
* Use checked property access in header instrumentation
* Read Continue eligibility records through workspace selectors
* Cover native header Find clearance and tooltip click passage
---------
Co-authored-by: Orca Worker <orca-worker@localhost>
Reserve-aware cell status for the director: reserve cells report their own runtime and seat feed, drain causes are attributed per cell, and paced 503s on a host leaving a draining cell are recorded as the drain's.
* fix(jira): pick real users for required create fields
* test(jira): keep user picker coverage within renderer boundary
* fix(jira): preserve known user identities and metadata choices
* test(jira): preserve full dialog fixture model type
* test(jira): target metadata Select trigger
* fix(jira): show matching people before known ID action
* fix(editor): reuse unchanged model text before EOL normalization
* fix(editor): preserve paired CRLF separators during live updates
* test(editor): drop the Monaco content-sync heap probe
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
* fix(memory): avoid character arrays when decoding image bytes
* fix(web): use bounded-allocation base64 decoding for encrypted replies
* refactor(memory): drop heap-probe tests and reuse the shared base64 decoder
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Rehome on reconnect for reserve-mode cells: a desktop reconnecting on a reserve cell outside its preferred region is placed fresh in that region, only while the region has at least 10% of seats free, at most once a day per desktop, rate-limited, and switched off by default (ORCA_RELAY_RESERVE_REHOME_PERCENT=0); the regional rehome switch stops it.
* fix(editor): open files dragged from the explorer in the target group
* fix(editor): preserve selected drop resources and owner routing
* test(editor): narrow accepted workspace drag result
* test(editor): bound workspace drop processing work
Before refusing a placement with relay_capacity_exhausted, the director tries a reserve seat in the desktop's own region, then the other region, through the cell's own reserve API; if every region paces it answers the shortest Retry-After.
* fix(terminal): explain agent startup failures in plain words
* fix(i18n): use the established Japanese agent label
* fix(terminal): preserve uncertainty in startup error messages
* Reuse pane agent identity and bound startup toast work
* test: render startup notices with shipped locale catalogs
uresourced before 0.5.5 answers every attribute write on the scope's cgroup by
re-setting its CPU and IO weights, which makes systemd rewrite the oomd xattr
again. The loop pins systemd --user and eventually stops it starting new
terminals. Per-terminal scopes already keep oomd from taking every terminal.
* fix(relay): count region selection on every assign lane, fallback only for new placements
Co-Authored-By: Claude <noreply@anthropic.com>
* test(relay): pin placed marker on isolated re-place and kept pins; drain-return fallback
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix(orcad): add --reclaim-stale-lock for a lock no start may judge
On a Linux host with no machine id whose ~/.orca is on a network or FUSE
home, a lock left by the host's own previous boot names a PID that is
evidence only on the machine that issued it, so every start after a
reboot refused it, and the only way out was deleting orcad.lock by hand.
Starts still refuse it: losing contact is not proof of exit, and a home
other machines may share must never be taken over automatically. Now:
- `orca serve --reclaim-stale-lock` (and `orcad --reclaim-stale-lock`)
checks that the lock was written on this host, in an earlier boot, at
least 2 minutes ago, and that nothing answers at its holder's
endpoints. It prints the pid, host, boot and age and warns about other
machines sharing the home, and clears the lock only with --yes,
through the normal race-safe reclaim of that exact record.
- Lock records now name their host, as evidence for that command.
- The refusal has its own code, orcad_instance_lock_holder_unverifiable,
names the command, and exits 3, so `orca serve --supervise` waits on it
instead of giving up, and the desktop refuses on it like a held lock.
- orcad advertises orcad.stale-lock-reclaim.v1 so a client can offer
the command on hosts that have it.
Fixes#32177
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(orcad): let --reclaim-stale-lock clear a reclaimer cut short by the reboot, and probe IPv6
A reclaimer from the same earlier boot on this host that the reboot cut
short left a recovery owner the command could never judge, so --yes
always failed. The confirmation now covers such an owner too, and only
one from this host's earlier boot. An IPv6 WebSocket endpoint is probed
by its bare address.
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(cli): ship the stale-lock reclaim module with packaged builds, and refuse an unreachable lock
The CLI loads main modules from out/main after the main build replaces
it, so the reclaim module becomes a stable plain-Node entry and is
unpacked from the asar. A lock that cannot be stat'ed for any reason other
than absence (a permission error, say) is now a refusal, not "nothing to
reclaim".
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(orcad): make --reclaim-stale-lock name the real data root and report a status
- The refusal prints a runnable command for the data root it refused:
an orcad names its own runtime and entry plus `--data-root <dir>`,
since managed hosts have neither `orca` nor `orcad` on PATH and their
data root is not the default. The hint is Linux-only.
- Both entry points take `--data-root` and `--json` and report one of
none, eligible, refused or reclaimed, each with its own exit code
(4, 2, 1, 0), so a missing lock never reads as a recovery.
- The evidence says nothing answers on this machine, and that the host
name and boot checks cannot rule out another machine with the same
name; --yes stays the gate.
- wss endpoints default to port 443, a same-boot branch that could never
run is gone, and the supervisor's standby line points at the command.
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(orcad): point the eligible message at the same command plus --yes
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(orcad): refuse an empty --data-root, and name the right program in reclaim hints
- `--data-root` with no usable value (a trailing flag, an empty or blank
string) prints usage and exits 1 on both entry points, never falling
back to the default profile.
- A refusal raised while the reclaim command itself runs names
`orca serve --reclaim-stale-lock`, not the binary the CLI runs under;
an orcad still names its own runtime and entry.
- The supervisor's standby hint includes this profile's --data-root.
- The unreadable-lock test is skipped when running as root.
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* test(cli): reuse the existing client stub for the --data-root refusal test
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
---------
Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com>
* fix(usage): ignore an idle Claude session's older usage for the same window
Claude Code re-sends each session's last-seen rate limits to the statusline,
dropping only windows whose reset has passed. An idle session days old keeps
posting the current weekly window at the value it saw back then, so the
weekly figure flipped between that stale value and the current one while the
5-hour figure held. Usage inside one window only grows, so a lower value for
the same reset (or an earlier reset) is dropped, and a post with nothing newer
leaves the snapshot and the OAuth poll timing untouched.
Fixes STA-10493 (#28418). Ports the rule from #23421.
Co-authored-by: Gabriel Petrovic <243207667+gabba6@users.noreply.github.com>
* fix(usage): separate Claude display receipts from corrective checks
* fix(usage): honor Claude retry eligibility when selecting refreshes
* test: verify fresh usage checks after service recreation
---------
Co-authored-by: Gabriel Petrovic <243207667+gabba6@users.noreply.github.com>