Commit Graph
16594 Commits
Author SHA1 Message Date
YohanandNeil 90e5072c8b fix(window): restore native fullscreen after a restart (#40540)
Persist windowFullScreen on enter/leave-full-screen (frozen once the window
starts closing) and re-enter fullscreen on reveal after the saved maximize,
skipping background launches. Ignore the spurious unmaximize macOS emits
while a launch-maximized window enters fullscreen so windowMaximized and
windowBounds keep the pre-fullscreen state.

Fixes #40510

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-11-11 03:29:12 -08:00
Wooseong KimandNeil 079b5de1ac fix(ai-vault): show the recorded folder workspace on session history chips (#41053)
Session History picked each session's workspace chip by matching cwd, so
when several folder workspaces shared one folder every row showed the
first workspace in the list. Prefer the live (non-archived) workspace
recorded in structuredSession.workspaceId on the session's host, and fall
back to the existing cwd match otherwise.

Fixes #41044

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-11-11 03:23:58 -08:00
Wooseong KimandNeil da8e4be7cb fix(workspace): focus the active split pane when Cmd+J or the tab switch menu selects a terminal (#41015)
Picking a split terminal tab from Cmd+J or the tab bar's switch menu
focused the first pane, because the picker already held focus and the
tab-wide focus query fell back to the first xterm textarea. Pass the
tab's stored activeLeafId to focusTerminalTabSurface (and to the paired
host activation) so input returns to the pane that was last active.

Co-authored-by: Neil <neil@stably.ai>
2026-11-11 03:13:12 -08:00
Wooseong KimandNeil e93c65f9ed fix(file-explorer): stop waiting to reveal paths the listing never shows (#41047)
The explorer drops node_modules and .git from every listing page, so a
reveal under them waited for a row that never appeared. The request stayed
pending and auto-reveal ignored later editor tabs.

getRevealTarget now cuts the reveal off at the first folder the listing
filter rejects. A nested hidden folder selects the folder that holds it; one
directly under the root clears the request. Hidden folders are never
expanded or read.

Fixes #41039

Co-authored-by: Neil <neil@stably.ai>
2026-11-11 03:07:48 -08:00
Wooseong KimandNeil 21ff9b8da2 fix(claude): exec Claude from the profile subshell so it leads the foreground group (#40962)
The Orca claude shell function launched Claude inside a ( ... ) subshell.
Bash can keep that subshell as the pane's foreground process, so Orca saw
"bash" instead of Claude. The subshell now unsets the claude function and
execs the binary, leaving Claude as a direct child of the pane shell.

Co-authored-by: Neil <neil@stably.ai>
2026-11-11 03:07:38 -08:00
Wooseong KimandNeil 00b8a78063 fix(droid): stop installing the unsupported PermissionRequest hook (#40612)
Factory Droid has no PermissionRequest hook event, so `droid doctor`
flagged the hook Orca wrote into ~/.factory/settings.json as unsupported.
The installer no longer registers it; reinstall drops only the
previously managed Orca command on that event and keeps user hooks.
Approval waits continue to come from PreToolUse and Notification, and
the now-unreachable PermissionRequest listener handling is removed.

Fixes #40607

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-11-11 03:07:28 -08:00
Wooseong KimandNeil aff87e9247 fix(sidebar): keep the activity bar position across restarts (#40891)
The right sidebar's Activity Bar Position lived only in renderer state, so
choosing Side reset to Top on the next launch.

Persist it with the other right-sidebar UI fields: PersistedUIState, the
paired-client update schema, the default and startup-fallback UI state, the
renderer write baseline and writer, and hydration. Profiles without the field
stay at Top, and hydration maps any value other than 'side' to 'top' so a
corrupt value cannot hide the activity bar. The ActivityBarPosition type
moves to shared ui-chrome-types so the persisted contract can use it.

Keep the field pairing-local for web clients, like sidebarOpen: older hosts
parse ui.set with a strict schema and would reject the whole update, so the
browser strips it from host writes and pins its own value on ui.get. Desktop
persists it through IPC.

Fixes #40887

Co-authored-by: Neil <neil@stably.ai>
2026-11-11 03:07:14 -08:00
Wooseong KimandNeil d56a5a6079 fix(plugins): hash dev workers with the same .orca skip as discovery (#40729)
Dev-folder plugins are hashed at discovery with DEV_FOLDER_SKIPPED_DIRECTORIES
(e.g. .orca/), but the worker activation integrity check re-hashed the whole
tree. Once Orca wrote typings into .orca/types, the activation hash no longer
matched the reviewed hash and the dev worker refused to start. Pass the dev
flag through to the integrity check so both hashes skip the same directories.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-11-11 03:01:48 -08:00
Vyacheslav Scherbinin fbda1db91e test(orchestration): keep scripted Codex homes in each test directory (#40964)
The scripted Codex fixture hard-coded /home/dev/.codex as the account
home on every platform. Startup now reads hook configuration from the
account home, so coordinator-worker tests stalled on macOS before the
scripted connection opened. Build the fake account home inside each
test's temporary fixture root and pass that root to every attach caller.
2026-11-11 03:01:39 -08:00
02e8b0c2a8 fix(skills): sort complete manifest paths before computing package identity (#40812)
Package identity hashed files in a segment-wise depth-first walk order, so a
file like references/refs.md sorted after references/refs/image.webp. The
manifest validators require complete paths in code-unit order, so such
skills failed with skill-bundle-manifest-path-order. Sort the complete
paths by code unit in both the runtime identity and the build-time manifest
generator, and cover the sibling file/directory layout with a round trip.

Co-authored-by: yukurust <76849725+yshi112358@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
2026-11-11 02:56:01 -08:00
Wooseong KimandNeil b981783e5d fix(dashboard): paste macOS Cmd+V in the agent dashboard pop-out (#40866)
The dashboard pop-out only claimed zoom chords in before-input-event, so
Kitty-mode xterm encoded Cmd+V as CSI u and consumed it before the Edit
menu accelerator could fire, typing a stray "v" instead of pasting.
Claim the chord with the shared isMacAppPasteInput matcher and route it
through the existing ui:appMenuPaste owner, matching the main window.

Fixes #40862

Co-authored-by: Neil <neil@stably.ai>
2026-11-11 02:55:49 -08:00
Neil 1a4b0c76b1 fix(agent): match AGY acronym to Antigravity in new worktree and new tab (#41128) 2026-11-11 02:46:09 -08:00
Neil 386afed0ca refactor(persistence): organize profile state and Store domains (#41106)
* refactor(persistence): organize profile state and Store domains

* fix(test): locate relocated profile state worker fixtures
2026-11-11 02:44:06 -08:00
OrcaWinandOrcaWin e5a98cf8a4 test: remove 127 low-value cases and unused observer harness (#41118)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-11 02:20:10 -08:00
OrcaWinandOrcaWin 7d92d106f4 test: remove 168 low-value tests across eleven suites (#41108)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-11 01:59:49 -08:00
Kelvin Amoaba 389a9be763 fix(ai-vault): budget OpenCode 2 captures by decoded text, not stored tool state (#41101)
OpenCode 2 charged the 64 MiB capture budget against raw session_message
rows, which are mostly tool input and metadata the transcript never keeps,
so a session with ~65 MiB of rows and a few hundred KB of text was dropped
whole. Count decoded transcript text instead, as OpenCode v1 does, and
copy truncated message text so a 256 KiB slice no longer pins its
oversized source string while the capture is held.

Fixes #28791
2026-11-11 09:41:16 +00:00
OrcaWinandOrcaWin aca88b05cc test: remove 83 low-value test definitions and seven suites (#41098)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-11 01:38:28 -08:00
Jinwoo Hong 818055fcbb feat(orchestration): answer workers' permission prompts from the coordinator (#40756)
* feat(orchestration): deny a worker's permission prompt, and say when mail is held

A chat worker that stops at a permission prompt now escalates with the prompt
itself as structured data (approval id, state, worker, summary, allowed
actions). The coordinator can deny it with a reason through
`orchestration deny`; the worker carries on and gets the reason as mail.
Only a person can allow a prompt: the answer method decides "person" from
the transport, never from params. The stop report keys one escalation per
approval and sends one closing line when it is answered, and no longer tells
the coordinator that `orchestration send` answers a prompt.

`orchestration send` now warns when the delivery gate would hold the mail
right now (an open prompt, a blocked status, typed text), and says delivery
state is unknown for a worker on a paired server.

* fix(orchestration): only the desktop app counts as a person for worker approvals

A paired device can carry a remote CLI, so it is treated as an agent: it can deny with a reason but never allow.

* fix(orchestration): approval answers and held receipts follow the real gates

- A same-option answer counts as Orca's only when Orca recorded it; a retry returns the same
  receipt with no second reason mail.
- An unreadable chat is not a closed prompt: the answer refuses, and the closer keeps watching.
- A closing line tells a reason only when it went to the worker as mail.
- The terminal held receipt prints the delivery gate's own refusal; the chat one prints what the
  pointer's admission and queue gate would do (not attached, refused, or behind an open prompt).

* fix(orchestration): read the held receipt only after the mail is stored

An await before the insert let a worker settle meanwhile, so the mail could land on a settled
Dispatch after its follow-up scan. The closer also removes only the approval map it read.

* fix(orchestration): tell the coordinator not to block on a worker's permission prompt

The approval escalation now says the worker is waiting for permission, tells a chat
coordinator the user has been shown Allow/Deny (a terminal coordinator: a person must
answer it in Orca or the worker), asks it to carry on with other work and not message
the worker until the answer arrives, and offers deny only as the way out when the
prompt is holding up the task. The guide and CLI docs say the same.

* fix(orchestration): a paired coordinator without an Orca session id mails a deny reason from its Run

* feat(orchestration): answer a Claude terminal worker's permission prompt

A worker pane's PermissionRequest hook now waits for Orca's answer, so the coordinator can deny
it with a reason (the worker continues) and a person can allow it. One record per waiting hook,
keyed by Claude's prompt and tool call; it is answerable only while the hook waits and the dialog
is on screen, and anything else gets `{}` as before.

* test: annotate the fake screen instead of casting

* test: wait on the hang-up instead of sleeping

* fix(orchestration): claim a terminal answer only from what Claude shows

An answer is written only while a caught-up screen still shows the dialog
in the same process run, and claimed only once Claude shows it applied: the
hook's deny line for a deny, no other close for an allow. A Yes, a No or the
2:00 auto-block that wins the race is refused and named from the screen.

A hook that hangs up is not an answer: with the dialog still up the
coordinator is told a person must answer it in the worker's terminal.

A PermissionRequest entry the user made async stays async: it prints {}
first and never waits for a decision.

* fix(orchestration): name a terminal prompt's close from its tool_result

The screen could show an older prompt's close, so who answered is now read
from the tool_result Claude's transcript records for that tool call: Orca's
own deny text credits Orca, the user's No and the 2:00 safety-check block
name themselves, and a run names an allow. Hook events cannot say this: a
deny or a No fires no PostToolUse. The screen only says whether the dialog
is still up before a write, and a PostToolUse seen mid-answer is kept.

* fix(orchestration): read a prompt's tool_result without blocking main

The transcript read is async, reads only its tail, and skips any path that
is not a regular file, so a FIFO or device cannot stall the main process.
A closed prompt still awaiting its result gets one last read when the lead's
turn stops, so a result written late still names the close.

* feat(native-chat): answer workers' approvals from the coordinator chat

A worker's open permission prompt appears as a card at the end of its coordinator's chat, drawn
from the escalation payload as soon as it is stored. The person allows or denies it there; the
card's buttons answer the worker's own prompt over the desktop app's IPC, so only a person can
allow. Once answered, the card turns into a receipt saying who answered.

* fix(orchestration): read a terminal prompt's countdown when it is first escalated

* refactor(orchestration): give a terminal prompt's hold state its own module

* fix(native-chat): let a worker's approval card answer, and drop it once it lapses

The window's runtime calls never carried the orchestration contract
version, so the card's Allow and Deny were refused as an obsolete client.
The renderer ships with its main process, so desktop IPC states the current
contract. An open card whose agent's own countdown has passed, with no
closing message (the app restarted while it was open), is no longer shown.

* test: say why the desktop fence test's runtime stub is enough

* fix(orchestration): a chat worker's approval asks to allow its tool, like a terminal worker's

* fix(native-chat): pause the approval countdown while the window is hidden

* chore(i18n): protect the approval card's worker line copy

* fix(orchestration): close a terminal prompt's card as soon as Orca can't answer it

When the dialog leaves without an answer through Orca, the closing line is
published at once, so the coordinator's card becomes a receipt; a tool
result that arrives later adds a second line naming how it closed, without
waking the coordinator. On startup, open terminal prompts left by an earlier
run are closed the same way, since their holds lived in memory. A Claude
terminal card's reason is the warning Claude prints under the command.

* fix(orchestration): keep the dialog-warning patterns ASCII for the orcad bundle

* fix(native-chat): say when a deny reason reached the worker as a separate message

A coordinator's deny reason for a chat worker whose prompt takes no message is sent
as mail. The receipt showed it the same as a reason that went with the denial, so it
now labels it 'Reason, sent as a message'.

* chore(native-chat): follow main's moved window-activity and agent-session modules

* fix(orchestration): only Orca's own reports draw approval cards, and every card closes

- Cards and the startup sweep read approvals only from rows whose id is the stop report's own
  stable id for that approval, through one shared parser; a worker's send cannot draw a card.
- A chat worker's card closes as soon as its own chat answers it (a journal watch replaces the
  turn-edge check), when an answer finds the prompt already gone, and after a restart.
- A terminal coordinator is told nobody was shown the prompt and to tell the user; the
  terminal-only close asks the same and goes out as an escalation.
- A chat coordinator's line names only the answers its card offers; a prompt with none is a
  plain prompt with no card.
- A person's Deny on a chat worker mails no extra reason.
- A record a quit or budget end closed stays closed.
- One closed-approval builder; `waitingOn` becomes `awaitsReply`.

* fix(orchestration): a failing read cannot hang an answer, fail a stored send, or fail the database open

* refactor(orchestration): add the held-send line in send-delivery-hold, keeping send-methods under the size cap

* test(orchestration): read the worker's mail with a schema, not a cast

* fix(orchestration): an open approval stays visible and closes even behind many closed ones or a missing database
2026-11-11 04:36:35 -05:00
Jinwoo Hong d0a15d824f feat(orchestration): a worker started with --on becomes the paired computer's own worker (#40731)
* feat(orchestration): records, import and settlement for workers a paired server owns (inert until B5)

* fix(orchestration): name the re-pair when a closed link refuses a send

* feat(orchestration): offline reads of workers a paired server owns (inert until B5)

worker-show from this Orca's record when the server can't be reached, labelled
with the server and when it last reported; remote rows in worker-list named by
server; unreachable failures said in the server's terms, apart from the
server's own unknown outcome.

* fix(orchestration): remote rows share the page limit, label re-made pairings, and say what the record's time means

* fix(orchestration): keep remote rows in every page's total, date the record by state only, and retry only by request ID

* chore(orchestration): annotate the remote count query's row type

* test(orchestration): check CLI views of remote workers at the CLI layer

* docs(orchestration): say remote rows get their own page limit

* feat(orchestration): run commands about a paired server's workers there, and switch new pairs to it

* feat(orchestration): offline show and server-named failures for forwarded commands

* fix(orchestration): forwarded start timeout, receipt Run and stop key in the caller's terms

* fix(orchestration): forwarded answers name this Orca's Run

* fix(orchestration): a remote worker's question is answered only by its Run's coordinator; tests for the forwarder

* fix(orchestration): a start answered after its Run was reset says so

* fix(orchestration): refuse a chat session terminal before asking any server; test the late start after a reset

* test(orchestration): lint

* fix(orchestration): review fixes for the forwarder: retry-of stays local, legacy retries stay legacy, unknown outcomes stay fenced, refused starts leave no Task

* chore(orchestration): no type assertions in the forwarder

* fix(orchestration): a start answered after a re-pair frees its Task

* fix(orchestration): worker-show of a worker whose pairing was re-made gives this Orca's record

* fix(orchestration): a retry with --on names the server's Task instead of resending its spec

* fix(orchestration): a read about a remote worker gives up within seconds on a sleeping server

worker-show then answers from this Orca's record, as it does for a server that is off. Changes keep their longer wait.

* fix(orchestration): a refused remote start keeps the Task it created, failed

A local start that fails after creating its Task leaves it failed; deleting it here left any dependent added while the start waited pointing at nothing.

* fix(orchestration): worker-show of a remote worker reads this Orca's record, never its server

Show answers at once whether the server is awake, asleep or off, and agrees with worker-list.
Its note says when the record is from and what the pull loop last heard from the server; a
prompt wait already arrives as the server's mail. worker-read stays forwarded with its 5 s cap.

* refactor(orchestration): drop the orphaned-start lookup; the server's queue item adopts a lost start

A start whose answer was lost stays reserved until the server's dispatch-insert item names its
Dispatch, which adopts it. The 30 s dispatchShow lookup and its two placement columns repeated that.

* fix(orchestration): a stop or abandon the server does not answer settles the Task here at once

As a local stop does, the Task goes blocked so it can be retried, and the stop stays owed with its
count. The first result stands: a later state from the server changes only the attempt's record.

* fix(orchestration): task-update on this Orca's own Task applies here, by the local rule

A Task placed on a paired server is this Orca's; its update goes through the ordinary owner, which
refuses it while the worker there holds it, exactly as for a local worker. Stop first: an
unanswered stop settles the Task here at once. Nothing is forwarded to the server.

* fix(orchestration): a link that can no longer answer fails the Tasks it held, with the reason

When a re-pair closes a link, or its server is removed from this Orca, each Task a worker there
still held fails here through the ordinary Task half ("The pairing with devB was re-made. Its
worker may still run there."), and its placements go. Before, the Task stayed dispatched for good.

* fix(orchestration): a paired Orca's reads on this server are no longer narrowed to its Run

* test(orchestration): a lost start is never looked up on its server

* fix(orchestration): review fixes for the remote Task settlements

- An abandon the server does not answer stops nothing, as a local abandon: it settles the Task here
  and owes no stop, with abandon's own receipt.
- A link a re-pair or removal closes tells the Run's coordinator about each Task it failed, as a
  local worker failure does, naming the server in the reason.
- An unreleased database drops the placement lookup columns and gains task_settled_here on open.
- A failure settling a removed server's Runs no longer ends the pull loop's bookkeeping.

* fix(orchestration): retries of a remote attempt follow the local rule, and owed stops go out on reconnect

A retry here may follow the Task's attempt on a paired server once it settled there or was
abandoned here, exactly as a local retry follows a local prior; an unproven stop, like a local
stop_unknown, leaves nothing to follow yet. When a server answers again, every stop and cancel
owed to it is due at once through the existing resend, so a retry there follows the proven stop.

* fix(orchestration): a re-pair settles held Tasks at once, lists the Run there, and refuses reuse of its Tasks

- the pull loop closes links of a changed pairing, so their held Tasks fail without a call through them
- worker-list --on lists a Run's workers by its server Run even after its link closed
- a start --on of a Task placed through a closed link is refused here, naming the server
- the server's restart recovery readies its Task, and this Orca follows as the local rule does
- a closed link's note gives why it closed and the server's recorded name

* fix(orchestration): review fixes for the re-pair settlements

- worker-list picks the Run's latest link a server Run answered for, so a refused start's new link hides nothing
- a start answered after a re-pair keeps its placement, so the Task's next start there is refused here
- worker-list --on errors read in this Orca's terms, as other forwarded reads do

* fix(orchestration): a re-pair fails a Task a stop left blocked, and a reset still fails a readied Task

- a closed link also fails a held Task an unanswered stop blocked, which nothing can prove now
- a server reset's removal fails the Task even after its recovery readied the server's Task
- a closed link keeps why it closed when a later queue item cannot be read

* fix(orchestration): a re-paired Run's worker-list says so plainly, with no new read path

- worker-list --on for a Run whose link a re-pair closed names the re-pair instead of runtime_error or an empty page
- a Task placed through an earlier pairing still starts on another server

* fix(orchestration): a re-made pairing's refusals keep their own error code

server_pairing_changed passes through RPC instead of becoming runtime_error.

* fix(orchestration): a re-pair fails a blocked Task only while its stop is owed

A Task a proven stop or an abandon blocked stays blocked; only an unanswered stop, which nothing can prove now, fails it.

* fix(orchestration): a refused start writes no link, and a re-paired Run's list tells a reset apart

- the refusal of a Task an earlier pairing placed runs before any link is written, so the Run's list still names the re-pair
- worker-list decides from the Run's newest link: closed says re-paired, a reset lists nothing, a link closed mid-call says re-paired

* test(orchestration): a paired Orca reads another Run's work on this server, and still cannot change it
2026-11-11 04:25:36 -05:00
Kelvin Amoaba 1e23050330 fix(native-chat): usage-limit Hand Off passes the chat's full saved history for every agent (#41096) 2026-11-11 09:24:07 +00:00
Neil 2195eae589 refactor(main): group search and profile implementation owners (#41082)
* refactor(main): group search and profile implementation owners

* test(browser): isolate retained preview grant callbacks
2026-11-11 01:02:18 -08:00
Neil 729f757b59 style(onboarding): compact icon-only Color mode picker and shorter copy (#41079)
* style(onboarding): compact icon-only Color mode picker and shorter copy

* test(e2e): drop removed folder trust prompt wait in golden-core-flows
2026-11-11 00:58:25 -08:00
OrcaWinandOrcaWin 2d2056b2d0 test: remove 117 low-value test definitions and orphaned fixtures (#41085)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-11 00:49:08 -08:00
Kelvin Amoaba 4252d46693 fix(agents): deliver new-workspace prompts to dsh-TUI 0.19, which runs as dsh-tui (#41086)
* fix(agents): deliver workspace prompts to dsh-TUI 0.19, which runs as dsh-tui

dsh-TUI 0.19 loads DSH in-process, so no dsh process holds the PTY.
Follow-up delivery only accepted the configured expectedProcess, so the
new-workspace prompt never reached it. Share launched-agent-foreground's
rule (recognized agent or expectedProcess) with follow-up delivery.

* fix(agents): use the shared agent-foreground rule in every paste readiness fallback

* fix(agents): keep generic launcher names out of the agent-foreground delivery rule
2026-11-11 08:49:00 +00:00
Kelvin AmoabaandKooooojun 801db2bb4c fix(native-chat): show Claude/Codex startup dialogs as a chat card and lock Send while one is up (#41083)
* fix(native-chat): answer Claude/Codex folder-trust dialog from a chat card

* fix(native-chat): show a chat card for Claude/Codex startup menus

* fix(native-chat): keep startup-menu cards holding Send; drop hand-typed identify retries

Startup-menu cards now hold the composer like the folder-trust card, so collapsing one can't free a Send whose Return would pick the highlighted choice.

The hand-typed agent probe retries and agentless hold are left out; Orca-launched panes already know their agent, and hand-typed native Claude identification predates this fix.

* fix(native-chat): read the whole screen for a tall startup dialog's heading

* fix(native-chat): drop the unreachable cwd prompt from startup-menu reasons

* fix(native-chat): show startup-menu warning text and give its choices no default

A startup-menu card now carries the dialog's body (Claude's bypass, API key, MCP and import warnings) under its heading, and its choices render as equals on desktop and mobile so Orca never nudges a consent choice. Long mobile option labels wrap inside their button.

---------

Co-authored-by: Kooooojun <edisonhuang1122@gmail.com>
2026-11-11 08:37:51 +00:00
Kelvin Amoabaandrumoii b2d98e276e fix(kimi): launch Full access with --auto instead of --yolo (#41080)
Kimi Code's --yolo is now Ask When Needed; --auto is its Never Ask mode.
Kimi refuses --yolo (or -y, --yes, --auto-approve) together with --auto,
so a Kimi approval flag the user put in Arguments keeps control.

Co-authored-by: rumoii <123233666+rumoii@users.noreply.github.com>
2026-11-11 08:27:59 +00:00
OrcaWinandOrcaWin 0db6fe6c44 test: remove 337 low-value test definitions across 13 suites (#41071)
* test: remove 337 low-value test definitions across 13 suites

* test: brace relay assignment fixture conditionals

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-11 00:15:57 -08:00
Kelvin Amoaba 215197f46d fix(editor): live-update tabs reached through a symlinked folder (#41075)
The workspace watch never follows a symlinked folder, so a tab opened
through one (target outside the root) got no change events. Watch each
such tab's folder directly; main checks for the link with an lstat walk
and already rewrites the folder watch's events to the link spelling.
2026-11-11 08:12:54 +00:00
Kelvin AmoabaandKien Le d8ef014a0c perf(emulator): stream the iOS Simulator pane as H.264 video (#41073)
* perf(emulator): stream iOS Simulator video as H.264

The iOS Simulator pane decoded serve-sim's MJPEG stream (~24 updates/s,
p95 latency 77 ms). serve-sim 0.1.47 already serves /stream.avcc, so iOS
sessions now decode it with WebCodecs (~59 updates/s, 26 ms).

- Main derives the AVCC URL from the session registry by device id; the
  renderer never supplies a stream URL.
- A decode-queue backlog restarts the stream from a fresh keyframe; repeated
  backlog falls back to JPEG.
- Any H.264 failure falls back to JPEG for that session, including a socket
  silent longer than serve-sim's 5 fps idle floor allows. A late idle timer
  after sleep gets a fresh window instead of failing.

* test(emulator): drop the wall-clock simulator video stall tests

They froze the event loop and raced real socket timers, which the repo's test
rules forbid; the JPEG fallback they guard is covered in the renderer test.

* fix(emulator): start the simulator video stall timer at the first byte

serve-sim writes nothing on /stream.avcc until capture starts, so a slow cold
start could trip the 3 s stall and pin the session to JPEG. The renderer's
first-frame timeout already covers the wait before the first byte.

* fix(emulator): re-arm the first-frame timeout when H.264 resyncs

A resync opens a new helper connection, and main's stall watch only starts at
its first byte, so a silent reconnect would freeze the canvas with no JPEG
fallback.

---------

Co-authored-by: Kien Le <122910950+kien-ship-it@users.noreply.github.com>
2026-11-11 08:06:02 +00:00
Kelvin Amoaba 3477cb17d4 fix(agents): point DeepSeek Harness install link at the dsh-TUI it launches (#41069)
The catalog's Install link opened DeepSeek's site, which installs only
dsh. Orca launches the community @deepseek-harness-tui/dsh-tui, so users
either stayed undetected or guessed the dead unscoped dsh-tui package.
2026-11-11 07:59:05 +00:00
Kelvin Amoabaandagustin2606 83ec1c09dd fix(browser): keep Orca shortcuts working while an HTML document preview has focus (#41066)
* fix(browser): forward Orca shortcuts from focused HTML document previews

Workspace-document preview guests never installed the guest shortcut
forwarder that browser pages and plugin frames use, so once a preview
took focus Ctrl+Tab and the other window shortcuts stopped reaching
Orca. Install it in attachWorkspaceDocGuestPolicies, bound to the
preview's own host, with browserPage: false so browser-page chords stay
with the document, and dispose it with the rest of the doc policy.

* test(browser): pin Ctrl+Tab forwarding from a focused HTML document preview

* fix(browser): activate a document preview's split when it is clicked

A press inside the preview never reaches the host DOM, so forwarded
shortcuts such as Close acted on whichever split was active before.

* refactor(browser): read a document preview's page id from its guest policy

---------

Co-authored-by: agustin2606 <agustinvarela2606@gmail.com>
2026-11-11 07:40:31 +00:00
Kelvin Amoaba e33a851d8e fix(claude-accounts): restart sessions after a phone or CLI account switch instead of asking on the desktop (#41064)
A switch made from Orca Mobile or the CLI opened the 'restart running sessions?' dialog on the desktop, where the person switching can't see it. Under the 'Ask' setting these switches now restart the moved sessions the way 'Always restart' does: each waits for its turn to end and resumes its conversation on the new account.
2026-11-11 07:29:01 +00:00
Neil 280bcbc48a refactor: organize usage and CSV modules by concrete owners (#41059) 2026-11-10 23:26:07 -08:00
Kelvin Amoaba c96271dc5b fix(mobile): say Update mobile on desktop chats an old phone app can't show (#41063)
An old mobile app lists a desktop-created structured chat it cannot render
with the title 'Update to view', which doesn't say whether the phone or the
desktop needs the update. Name the phone app, and document the symptom and
recovery steps in the mobile troubleshooting docs.
2026-11-11 07:25:05 +00:00
OrcaWinandOrcaWin fce98d7d21 test: remove 167 low-value cases and 93 suites (#41057)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-10 23:17:08 -08:00
Kelvin Amoaba e183ba8bac fix(daemon): stop the macOS logout watch adding a login record every two minutes (#41056)
* fix(daemon): stop the macOS logout watch writing a login record every two minutes

The watch ran /usr/bin/login as its session-health probe, and each run adds an
entry to the macOS login history. Check DNS health first and only run the login
probe when the resolver already looks dead, which retirement requires anyway.

* fix(daemon): keep probing login after a rejection until PAM accepts again

Gate on the last login verdict instead of the rejection streak, so a sleep reset
of the streak cannot leave a rejected verdict cached while DNS looks healthy.

* test(daemon): keep coverage for not retiring once DNS recovers

* test(daemon): drop the duplicate retirement replay from the resolver gate test
2026-11-11 07:07:45 +00:00
Neil d47ed1c468 fix(agent-status): skipping a Codex async question clears it on SSH panes too (#41031)
* fix(agent-status): skipping a Codex async question clears it on SSH panes too

An SSH pane's Codex hooks are normalized by orcad on the host, so the
desktop's own hook server had no row to apply the skip keystroke to. The
renderer now sends a remote pane's skip to the owning runtime through a new
terminal.inferCodexQuestionSkip RPC, which applies it to the host's tracker.

* test(e2e): skipping a Codex async question clears a managed SSH terminal's row
2026-11-10 23:07:24 -08:00
Neil 7803c9b91c fix(source-control): name the base by its short ref in the empty state (#41033)
The Source control empty state named the base by its fully qualified ref ('…no changes ahead of refs/remotes/origin/master'). Show it the way people know it ('origin/master') with a small shortRefLabel helper.
2026-11-10 23:01:35 -08:00
Kelvin Amoaba b0c431c1a3 fix(orchestration): archive a released chat worker's journal up to the byte bound, not one 200-row page (#41049) 2026-11-11 06:36:42 +00:00
Neil 3217e60e84 refactor: give pane conversations a concrete owner and remove redundant wrappers (#41038) 2026-11-10 22:36:36 -08:00
Kelvin Amoaba 37ae7de470 fix(cursor): list your account's Cursor models in the agent launch picker (#41046)
* fix(cursor): read the default marker in cursor-agent model rows

* feat(agent-launch): list a terminal-only agent's own models in the launch picker

* fix(agent-launch): cache Cursor listings and keep the seed for fallback lists

* fix(agent-launch): keep the host catalog for agents that have structured chats

* refactor(agent-launch): resolve the picker's discovery runtime once per render
2026-11-11 06:33:00 +00:00
Neil d5022c6e46 style(new-workspace): icon-only Create From tabs and shorter Create button (#41036)
* style(new-workspace): icon-only Create From tabs and shorter Create button

* style(new-workspace): let Tabs primitives own source-tab spacing

* chore(i18n): add Create button label to English catalog
2026-11-10 22:31:35 -08:00
BoyceandKelvin Amoaba 42f55bfa37 fix(session-history): index Codex rollouts archived as .jsonl.zst (#40593)
* fix(session-history): index Codex rollouts archived as .jsonl.zst

Codex compresses rollouts idle for 7+ days to rollout-*.jsonl.zst. The
session scanner only discovered .jsonl files, so every Codex chat older
than about a week disappeared from Agent Session History. Discover .zst
rollouts, decode them through a shared zstd stream wrapper above
openTranscriptReadStream (native, WSL UNC, and SSH alike), never resume
a compressed archive from an offset, and drop a .jsonl.zst candidate
when its plain .jsonl twin is listed, matching Codex's own rule.

* fix(session-history): admit only rollout-named zst archives and close raw zstd streams early

Review follow-up on #40593: a filePredicate limits compressed discovery
to rollout-*.jsonl.zst so unrelated .zst files are never decompressed,
and zstdTranscriptStream links the raw and decoded streams with pipeline
so an early close of the decoded stream releases the raw stream's fd.

* fix(session-history): cover archived Codex rollouts by compressed size and collapse .zst twins in every listing

Archived rollouts keep the bounded resumable reader but never resume, and report their compressed stat size as the read cursor, so search coverage checks match. The .zst suffix is dropped from Codex alias keys with the plain file preferred, which also dedupes scoped walks and rollouts archived in only one home.

* fix(session-history): prefer the live rollout over an archive in another Codex home

---------

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-11-11 06:20:22 +00:00
Kelvin AmoabaandPr1p 4c8feb5621 fix(native-chat): open or reveal folder links, labeled "Open folder", instead of doing nothing (#41040)
* fix(native-chat): open and reveal folder links instead of doing nothing (#40675)

* fix(native-chat): reveal folders in their owning worktree and localize the no-route toast (#40675 review)

- Activate a folder's owning worktree before revealing it: the explorer only
  reveals inside the worktree it shows, so a paired host folder in another
  worktree stayed hidden.
- Reject a paired folder outside the worktree root (e.g. a chat scratch
  folder): the explorer drops those reveals, so report the unavailable route
  instead of returning silently.
- Add an `unavailable` FileOpenFailure verdict with its own localized toast,
  replacing the English error string that other locales would show.

* fix(native-chat): report a folder the OS could not open (#40675 review)

`openFilePath` returning false or rejecting left a local folder click with no
feedback. The directory route now reports the unavailable path in both cases,
with a test covering a refused local folder open.

* fix(native-chat): reveal SSH folders in the explorer and report a failed Shift-open of a folder

Folders below an SSH workspace root still ended in a 'can't open' toast;
the workspace explorer reads through any host, so it shows them. A
Shift-open of a local folder that the OS refused returned silently.
The trailing-separator hint now also hides the download row.

* fix(native-chat): match the owner's host and explorer spelling when revealing a folder

A same-ID workspace on another host counted as already selected, a
superseded folder click could still toast after a newer one, and an
SSH reveal used the chat's separators instead of the explorer's.

* fix(file-explorer): reveal a target spelled with other separators, and skip duplicate folder rows and toasts

The explorer built a reveal's ancestors in its root's spelling but
looked the target up as given, so a forward-slash path under a Windows
root selected nothing. A local folder link no longer repeats its open
as 'Open with default app', and a blocked folder workspace no longer
toasts twice.

---------

Co-authored-by: Pr1p <zwq19980411@gmail.com>
2026-11-11 06:13:32 +00:00
Kelvin Amoaba 681dab3ff9 fix(speech): keep the old speech model when an update can't be moved into place (#41037)
* fix(speech): keep the old model when the new one can't be moved in

Deleting the old folder before the rename lost both copies when the rename
failed, e.g. a Windows antivirus lock.

* fix(speech): keep an interrupted swap's backup and let delete wait for it

Retry renames through Windows file locks, and keep .previous when it is the
only old copy left.

* fix(speech): remove the migration source's model backup on delete

* test(speech): assert the kept model, not the backup folder name

* refactor(speech): remove each model folder's leftovers in one loop on delete

* fix(speech): check model folders with async stat during the swap
2026-11-11 06:09:57 +00:00
Hotragn PettuganiandKelvin Amoaba 05edb8fd89 fix(azure-devops): recognize vs-ssh.visualstudio.com SSH remotes (#40369)
* fix(azure-devops): recognize vs-ssh.visualstudio.com SSH remotes

Organizations on the older visualstudio.com URLs clone over SSH with
<org>@vs-ssh.visualstudio.com:v3/<org>/<project>/<repo>. The repository
parser only accepted ssh.dev.azure.com, so these remotes parsed to null
and the repo got no Azure DevOps pull request or status features.

Accept vs-ssh.visualstudio.com in both the SCP and ssh:// forms, and
resolve it to the same reference the org's https://<org>.visualstudio.com
remote already gets.

Fixes #ISSUE

* fix(azure-devops): validate vs-ssh org names and fix renderer PR links

A vs-ssh remote's org becomes the API hostname that receives the Azure
DevOps PAT, so reject anything but a plain org name. The renderer's
manual PR link parser also missed vs-ssh remotes and built a link on
vs-ssh.visualstudio.com; resolve it to the org's visualstudio.com repo.

---------

Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
2026-11-11 06:00:53 +00:00
Jinwoo Hong 5e342d7e1a fix(orchestration): a worker report during an Orca restart is not rejected as a changed identity (#41014)
* fix(orchestration): a worker report during an Orca restart is not rejected as a changed identity

* refactor(orchestration): share the startup bounded wait; skip long-poll checks

* chore(orchestration): drop casts in the restart identity wait

* fix(orchestration): only long-poll checks skip the restart identity wait

* fix(orchestration): ordinary mail never waits for the restart identity restore
2026-11-11 00:59:18 -05:00
OrcaWinandOrcaWin d3ef8b4255 test: remove 216 low-value cases and 42 whole suites (#41030)
* test: remove 216 low-value cases and 42 whole suites

* test: retire unprotected snapshot adoption gate

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-10 21:57:58 -08:00
Kelvin Amoaba ada663ef62 fix(bitbucket): connect access tokens and API tokens without account access (#41029)
* fix(bitbucket): connect access tokens and API tokens without account access

Bitbucket answers GET /2.0/user with 403 for a credential it accepts but
that has no account access: every repository, project or workspace access
token, and API tokens without read:user:bitbucket. Orca treated that 403 as
a rejected credential, so those tokens could never connect. Only 401 now
means rejected; 403 connects without an account name.

* test(bitbucket): type the 403 fetch stub without a cast

* fix(bitbucket): accept a /user 403 only when Bitbucket sent it
2026-11-11 05:56:15 +00:00
Neil 80026db12a refactor(renderer): place remaining library features with their owners (#41024) 2026-11-10 21:48:26 -08:00