Commit Graph
16002 Commits
Author SHA1 Message Date
OrcaWin 572fbc8a2a test: remove 174 low-value shared agent tests (#37729) 2026-11-03 03:10:24 -08:00
Brennan Benson ed54ecfa9c Use the shared agent picker in workspace and Source Control launches (#35802)
Use one shared agent picker for creating workspaces, continuing conversations, and launching agents from Source Control and its settings.

Preserve saved agent choices, model and effort selection, custom arguments, keyboard navigation, and agent settings. Match the Create worktree menu to its field while keeping other menus compact, with stable model labels and responsive setup placement.
2026-11-03 02:59:57 -08:00
Neil 2169b791b7 refactor(git): group worktree operations and ref owners (#37783)
* refactor(git): group worktree operations and ref owners

* test(git): retarget remaining concrete executor mocks
2026-11-03 02:52:13 -08:00
OrcaWin d01fc8f60b test: remove 103 low-value shared agent tests (#37724) 2026-11-03 02:41:02 -08:00
Kelvin Amoaba debbb5b496 fix(chat): keep streaming replies after their prompts (#37773)
* fix(chat): keep streaming replies after their prompts

* fix(chat): retain queued placement through turn transitions

* fix(chat): preserve queued sends through read errors

* test(chat): keep act callbacks void

* test(chat): align transcript tiers with prompt order
2026-11-03 10:15:37 +00:00
Kelvin Amoaba ee532e571c fix(chat): show device names on answer receipts (#37776)
* fix(chat): show device names on answer receipts

* fix(chat): resolve receipt names across local and remote hosts

* test(chat): type receipt boundary test dependencies

* fix(chat): keep receipt labels within history frame budgets

* test(chat): return complete compatibility attach replies
2026-11-03 10:09:26 +00:00
NeilandCopilot 2f6601da60 feat(editor): add opt-in format on save (#37716)
* feat(editor): add opt-in format on save

Run project-configured stdin/stdout formatters before guarded saves, with an off-by-default setting, host-aware execution, and safe error fallback.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(settings): localize formatter search terms and placeholder

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* test(editor): stub view state in Monaco fakes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(editor): skip SSH formatter guard when no formatter applies

Unconfigured or excluded files in SSH workspaces now save silently instead
of toasting a misleading reconnect error. Configured SSH formatters report
that SSH hosts are not supported yet. Document that include globs skip
dot-prefixed names unless listed explicitly.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-03 01:29:31 -08:00
Kelvin Amoaba 957a82359e fix(runtime): keep worktree names through scan timeouts (#37768)
Fixes #16724
2026-11-03 09:23:18 +00:00
Alonso AlmeidaandAlonso Almeida 3b91fe4971 fix(cli): forward OpenCode --method and --answer from account add (#37622)
Forward OpenCode login methods and form answers into private account enrollment. Reject missing repeated values before login and preserve literal arguments through the common Windows process launcher, with terminal input, JSON output and cancellation retained.

Thanks to Alonso Almeida (@Alonsojrr14) for the original implementation and follow-up fixes. Tracked in #37621.

Co-authored-by: Alonso Almeida <alonsojr1269@gmail.com>
2026-11-03 01:12:19 -08:00
Brennan Benson b49a019e87 Keep merged linked PRs purple in workspace cards (#37730)
* fix(sidebar): preserve lifecycle for linked review collections

* fix(sidebar): keep collection draft labels provider-neutral
2026-11-03 01:07:49 -08:00
Neil 5d5b4f4f3d refactor(ai-vault): organize provider scanners and history owners (#37742) 2026-11-03 01:05:52 -08:00
Brennan BensonandClaude Opus 5.5 dc7cd7bebb Hold queued follow-ups after an agent turn fails (#37181)
* Hold queued follow-ups after an accepted turn fails

* Hold queued follow-ups until a Resume follows the failure

A Resume written while a turn was still running (for example after a Stop
that could not end it) waived that turn's later failure, so one queued card
was sent into the failure. The newest-turn projection now remembers the
journal position where the newest turn first settled as failed, and only a
Resume written after that position releases the hold. After restore or
removal the position is the rebuild point, so an earlier Resume is not
credited. Nothing new is saved.

Publication now checks running work once and reads pending sends from the
input order's index instead of every saved submission, and the scaling test
counts every walk of the item map, including the ones drafts make.

* Give the forked-rewind test's replacement item its owner fence

The replacement item now carries ownerFence 0, the fence the failed turn was written under, so the test type-checks against the required field.

* Check only pending sends when deciding whether a held queue's pause shows

Sends recovered as unknown after a restart stay in the unsettled set forever, so every queue update while a failure or Stop pause showed walked all of them. The input order now also keeps the pending sends on their own, and the pause check reads that list. Both lists share one small cached index. A scaling test seeds recovered sends and confirms repeated publication reads none of them.

* Give the failed-queue scaling test's send rows the journal's own handle form

* Let a /compact that fails on its own terms leave the queue hold as it was

A queued /compact that Orca or the agent refuses, or that ends with its own
"compaction failed" verdict, no longer pauses the cards behind it, and no
longer lifts a pause an earlier failure set. A compaction that hits a usage
limit or the agent's own error still holds them, even when that row arrives
after the compaction ended. Continue after a usage limit now runs ahead of
the held cards; its test says so.

* Hold the queue on the failure beneath refused commands, whenever its evidence lands

The queue's failure hold now follows the newest turn that can decide it,
re-derived from the saved turns and failure rows instead of a number
remembered when a command arrived. A /compact that fails on its own terms
(Orca's refusal, Claude's or Codex's verdict, or an ACP agent's own
"compaction failed" row such as Grok's refusal) neither holds nor releases
the cards waiting behind it. A usage limit, sign-in or provider error on a
command still holds them, even when that row lands after a newer refused
command or before the command's own turn row. Fixing the failure beneath a
refused command now releases the hold, and ordinary failed turns without a
failure row (an ACP agent stopping at its token limit) still hold as before.

* Keep the failure hold's turns in creation order so each row updates only what it touches

The queue's failure hold used to walk every command since the last ordinary turn on each command or evidence row, and rebuilt from the whole history whenever one of those commands was removed. A long run of refused /compact commands, or rewinding them, made that work grow with the conversation.

Turns and context clears now sit in a balanced tree ordered by creation, with each subtree caching its newest turn, newest ordinary turn or clear, and newest turn that can decide the hold. Adding, revising or removing one costs a single root-to-leaf path, reads stay constant, and removals keep the same conservative boundary a rebuild gave, without rescanning. The cost contracts drive real isolated transactions at 100 and 1,000 commands and allow no history or projection walks.

* Count map walks in the failure-hold cost test with plain spies instead of Reflect

* Build the failure-hold tests' status rows with real failure words so they typecheck

The scaling test now words its usage-limit and refusal rows through the same failure-words helper the host uses, and the queued /compact test reads the command turn's item key from the identity it was handed instead of a field the run type does not declare.

* Re-flag only the waiting cards a queue pause can hold when the pause changes

A change in the queue's pause (a new or cleared failure, Resume, Stop, a
context clear or a reopen) used to rebuild the card index from every saved
card, withdrawn and sent history included. The index now keeps the set of
waiting cards with no per-card hold and, on a pause change, updates only those
whose flag actually changed; the other cards' summaries, the legacy domain
index and an unchanged clear list are kept. Held and actionable results are
unchanged.

* Keep an older direct send ahead of newer cards after a sent card settles

After a queued card was sent and accepted, its history was released, but
the card kept its old place in the index a direct send was ordered
against. A later Stop and chat close then recovered a newer queued card
ahead of the older direct send. A pause change now gives those cards the
same place a full rebuild did, visiting only cards changed since the last
pause change; cards placed by an earlier rebuild share one value that
moves with each pause change.

* Hold the queue on a failure at read time instead of rebuilding the card index

A failed turn holds every waiting card alike, so the card index no longer
rebuilds when a failure starts or ends. It keeps main's ordering, rebuilds only
on Stop, clear and reopen as main does, and hides the waiting card and command
from reads while a failure holds the queue. This removes the incremental
re-stamping layer, which reordered tied cards restored from an older build and
kept growing work and memory across pauses.

* Check that a held queue walks no card history during the fold, not only after it

The failed-queue card contract now warms the legacy domain, watches every Map the card index owns, and checks each ensure keeps its indexes and walks nothing. Across fold, adopt and read the canonical cards are walked exactly once per item row, the existing command-refusal scan, and never for a Resume.

* Read the card index fields in the failure-hold cost test directly instead of through Reflect

* Drop the two type casts from the queue failure cost test

* Hold orchestration messages that arrive while a failed turn holds the queue

A message from another agent arriving while the chat sat idle after a failed turn went straight to the agent, and if that turn succeeded it also released the person's held cards. Such a message now waits as a held card with the rest; the person's own send still recovers, and Resume or the card's Send delivers it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Update usage-limit continue tests for failure-held cards

The edited-card test now presses Resume after the limit failure, so its
card is resumed but edit-held and the continuation is still superseded.
A new test covers the continuation running ahead of a failure-held card,
which stays held during that turn and drains after it succeeds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Combine compact test imports after main merge

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-03 00:20:27 -08:00
Neil c6b829ecf1 refactor(main): group WSL host and orcad lifecycle owners (#37728) 2026-11-02 23:58:18 -08:00
Brennan Benson 7863aefbc2 Restore the Orchestration panel experimental opt-in (#37616)
* Restore the experimental orchestration panel opt-in

* Bound crew preview encoding before truncation

* Verify orchestration gate ignores unrelated store updates

* Use stable gate fixture identities

* fix(orchestration): keep expanded details inside crew cards
2026-11-02 23:58:00 -08:00
Neil 6d5edf8c33 refactor(main): organize WSL discovery filesystem and execution owners (#37722)
* refactor(main): organize WSL discovery filesystem and execution owners

* refactor(main): consolidate defining-owner path imports
2026-11-02 23:36:23 -08:00
Jinjing 4be04a7e13 Remove duplicate close button from chat toolbar (#37715) 2026-11-03 00:19:13 -07:00
OrcaWin 706e2e8653 test: remove 474 low-value shared agent tests (#37695) 2026-11-02 23:18:37 -08:00
Kelvin Amoaba a1c02cf3fd test(linear): fix children query selection fixture (#37711) 2026-11-03 06:57:38 +00:00
NeilandCopilot af6cb2cf8c Make settings theme pickers searchable (#37692)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-02 22:30:09 -08:00
Brennan Benson 5c4331e729 perf(linear): load nested children with parent pages (#37667)
* perf(linear): load nested children with parent pages

* test(linear): bound nested child prefetch at the output cap
2026-11-02 22:26:34 -08:00
Brennan Benson 86a2fe9684 Load Linear drawer fields in one issue query (#37663)
* Read Linear drawer details in one issue query

* Keep readable Linear details after optional field errors

* Select only Linear fields needed by each issue reader

* Explain the typed Linear partial response boundary

* Typecheck Linear integration in the mixed-process project

* Update Linear integration fixtures for raw issue reads
2026-11-02 22:25:42 -08:00
a6489eb6e9 fix(remote-terminal): stop the stream watchdog from tearing down a terminal whose output is still flowing (#33971)
* fix(remote-terminal): stop the stream watchdog from tearing down a terminal whose output is still flowing

The delivery deadline anchored at the first in-flight byte and only cleared when no bytes were in flight. Under continuous output that never happens, so a healthy stream was torn down and resubscribed about every 30s (152 recoveries in one crash bundle). Anchor the deadline to the oldest unsettled or unacknowledged chunk instead.

* fix(remote-terminal): ignore deliveries after the stream watchdog is disposed

* perf(remote-terminal): drain watchdog ACK queue in O(1) and arm the deadline once

Replace per-chunk Array.shift() with a head index plus amortized compaction so
one ACK covering many tiny frames no longer blocks the renderer (200k one-byte
chunks: ~17s before, a few ms now). Arm the delivery timer once and recompute
the oldest-pending anchor when it fires instead of re-arming per frame.
Add tests for ACK stall under continuous settled output and the drain cost.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-11-02 22:25:22 -08:00
Brennan Benson ec8b2e2055 Read one full Linear ticket for planning and plain tickets for queues (#37656)
* docs(linear): use plain ticket reads for queues

* docs(linear): preserve selected queue ticket identity
2026-11-02 22:23:28 -08:00
Neil f3088d53c9 refactor(main): group terminal support by lifecycle owner (#37660) 2026-11-02 22:13:39 -08:00
e064cb45c5 fix(linux): refuse realtime audio scheduling under an inherited zero RLIMIT_RTTIME (#36183)
* fix(crash): name an inherited zero RLIMIT_RTTIME in Linux SIGKILL reports

Omarchy launches apps from a shell that holds a hard RLIMIT_RTTIME of 0
(no rtkit, so the portal's zero realtime budget is applied by PipeWire
module-rt). Orca inherits it in every process, and the kernel CPU-timer
watchdog SIGKILLs GPU and renderer processes with no dump while GBs of
memory are free. A hard limit cannot be raised without privilege, so
record it as a startup breadcrumb and in process-gone crash details.

Move the daemon's /proc/self/limits parser into one shared reader so the
terminal warning and crash attribution flag the same zero soft or hard
limit.

* fix(crash): record the zero-rttime breadcrumb from the shared helper and restore timer-armed wording

* fix(linux): refuse realtime scheduling under an inherited zero RLIMIT_RTTIME

Chromium makes audio threads SCHED_RR whenever RLIMIT_RTPRIO allows. Under a
zero hard RLIMIT_RTTIME (Omarchy launcher without rtkit) the kernel's RT
watchdog SIGKILLs that renderer or audio process on its first tick, so any
sound (custom notification sound, browser media, video) killed the renderer
with exit 9. When RTTIME is 0 and RTPRIO is nonzero, zero RLIMIT_RTPRIO with
prlimit for main and its existing zygotes before the first window; Chromium
then falls back to a nice value. The linux_rttime_limit breadcrumb records the
outcome.

* docs(linux): scope the realtime guard to the RTPRIO > 0 audio path it was shown to fix

Evidence (Electron 43.8.1 linux-arm64, the version Orca ships, in Docker
with --ulimit rtprio=95:95; page plays a WebAudio oscillator; guard step is
the same /proc tree walk + `prlimit --pid <pid> --rtprio=0:0` as this module):

  rttime unlimited:      AudioOutputDevi / AudioWorkerThre go SCHED_RR prio 8,
                         renderer survives 6 s
  rttime 0:0, no guard:  "audio started" -> render-process-gone killed 9 (~80 ms)
  rttime 0:0, guard:     "guard lowered rtprio on 5 pids", no RR threads,
                         audio keeps running, renderer survives 6 s

Limits: this is a minimal Electron app, not a packaged Orca build. The only
reachable Omarchy box has RTPRIO 0/0 and RTTIME unlimited, and an
unprivileged user cannot raise RTPRIO there. Under RTPRIO 0/0 the guard
records rtPrio=not-needed and changes nothing, so reported zero-RTTIME
SIGKILLs on such machines (for example the one 2.6 s after load with no
audio breadcrumb) have a different trigger. Treat this as a partial
mitigation plus diagnostics; the crash bucket stays open.

* fix(linux): report a partial realtime-priority lowering when the process tree can't be fully walked

listProcessTree silently skipped unreadable /proc/<pid>/task/<tid>/children files,
so on kernels without CONFIG_PROC_CHILDREN the guard lowered only the main process
yet recorded rtPrio 'lowered'. Track whether any live thread's children list was
unreadable and report 'lowered-partial-tree' in that case. Tests now use a fake
/proc root so tree walking is deterministic on any host.

* fix(crash): carry the startup RTPRIO outcome into process-gone reports

The linux_rttime_limit breadcrumb rotates out of the 30-entry ring long
before a late SIGKILL, so stash the guard's outcome and attach it as
rlimitRtPrioStartup next to the rlimitRtTime fields. A short-lived child
that exits between the /proc walk and its prlimit call no longer turns
the outcome into prlimit-failed. Adds direct tests for the rttime/rtprio
readers and the new crash-detail fields.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-11-02 22:03:38 -08:00
e4804c76df fix(new-workspace): list each same-host checkout in the create-worktree picker (#36180)
* fix(new-workspace): list each same-host checkout of a project in the create-worktree picker

Two local clones of one Git remote share a project id. The sidebar already
shows each clone as its own section, but the create-worktree dialog listed
the project once, its Run on picker kept only the first clone per host, and
an explicit setup id was folded onto that first clone. The second clone was
unreachable, and starting a worktree from its sidebar section created it in
the first clone instead.

v1.4.243 (#32272) split such clones into separate projects, which hid this;
its revert in v1.4.244 (#34662) brought the single picker row back.

- Project picker: add one row per same-host checkout, using the sidebar's
  own checkout-scoped rule; the project row keeps the project's other hosts.
- Run on: one row per host still, but the selected checkout is the one shown.
- Target resolution: only setups for the same checkout path collapse onto
  the first one; a distinct checkout on the same host stays the target.

* fix(new-workspace): name the host on remote checkout rows in the project picker

Remote same-host checkouts were labeled by path only, so a checkout on an
SSH/runtime host could read identically to a local one with the same repo
name and path. Prefix the host label for non-local checkout rows and cover
checkout-row listing, selection and labeling in a focused lib test.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-11-02 22:03:33 -08:00
971e575215 fix(source-control-ai): Copilot generation no longer fails on a model the plan hides (#36174)
* fix(source-control-ai): Copilot generation no longer fails on a model the plan hides

Copilot defaulted to --model gpt-5.4, which many Copilot plans and org
policies do not offer, so branch auto-name, commit messages and PR text
failed with 'Model "gpt-5.4" from --model flag is not available.'

Default Copilot to Auto, which every plan runs, and when Copilot rejects
the selected model before starting a turn, rerun once without --model
(and the effort that belonged to it) so Copilot uses its own default.

* fix(source-control-ai): retry Copilot only on its own unavailable-model rejection

Require a nonzero exit, no stdout, and Copilot's exact stderr error line
for the model Orca passed, so quoted text, exit 0, or partial model
output never triggers a second run.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-11-02 22:03:29 -08:00
404e0472aa fix(updater): keep a moved Windows install in place when it updates (#36831)
* fix(updater): keep a moved Windows install in place when it updates

A per-user NSIS update installs to the registry's InstallLocation. When a user
moves Orca's folder (e.g. from the default per-user path to D:\Apps\Orca), that
key still names the old path, so the update reinstalls Orca on C:, repoints the
shortcuts there and leaves the copy the user runs behind. Pass the running
folder to the installer (/D=) so the update replaces the copy that is running.

* fix(updater): pin a Windows update only to a folder that holds just an Orca install

The pinned folder becomes InstallLocation, which later updates and uninstalls
remove with RMDir /r. Skip drive roots, folders without the Orca uninstaller,
and folders with any entry outside an installed Orca layout, so unrelated files
are never deleted; those cases keep the default install location.

* fix(updater): never pin a Windows update to a folder path with spaces

* refactor(updater): return the Windows update install folder instead of mutating the updater

* fix(updater): only treat exact Electron files as Orca-owned when pinning a Windows update folder

The ownership check accepted any .txt/.json/.html/.log/.bin/.dat file, so a
folder holding user documents next to Orca could be pinned as InstallLocation
and later wiped by NSIS RMDir /r. Match Electron's non-binary top-level files by
exact name and only .dll/.pak by extension. Also move the resolver next to
updater-setup in lifecycle/, where main relocated it.

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-11-02 22:03:24 -08:00
OrcaWinandm4air bebf5a2621 fix(windows): explain an unfinished install instead of crash-looping the window (#34447)
Missing, empty, or locked ffmpeg.dll beside Orca.exe (as an interrupted
update leaves it) makes every renderer die at child init with 0x80000003
and the window crash-loops. Gate the packaged Windows desktop launch on
it after the single-instance preflight and show the standard startup
failure dialog instead.

Rebased onto main keeping the WSL holder and agent-hooks uninstall
preflights ahead of the gate. Message no longer claims the installer
relaunches Orca, and tests cover the gate's skip paths.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-11-02 22:03:20 -08:00
5933df0147 fix(window): ride out Windows renderer launch refusals instead of prompting after 1s (#36827)
* fix(window): ride out Windows renderer launch refusals instead of prompting after 1s

Windows renderer launch-failed exit 18 is Chromium SBOX_ERROR_CREATE_PROCESS:
CreateProcessAsUser for the sandboxed renderer was refused. Field reports show
the refusal clears within seconds to minutes and the same webContents reloads
fine afterwards, but Windows was kept on the 750ms crash breaker, so three
reloads burned in ~1s and a blank window waited on a Try Again prompt.

Use the same ~2 minute launch-failure backoff on Windows as on POSIX.

* test(window): pin bounded prompt for persistent Windows exit-18 refusal

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Neil <neil@stably.ai>
2026-11-02 22:03:16 -08:00
OrcaWinandm4air 4f4d766a85 fix(terminal): hold Enter until a Windows Codex pane reads the typed message (#35558)
A phone send writes text raw and presses Enter after the ingest delay only.
Windows Codex reads the text one key event at a time and keeps an Enter that
lands mid-burst as a newline, so the message stays in the desktop composer.
Add the key-event burst (3 ms/char) to the wait, capped at 20 s total so the
send still answers inside the phone's 30 s terminal.send timeout.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-11-02 22:03:11 -08:00
OrcaWinandm4air 896e2d21a2 fix(combined-diff): load an image diff inside its own row so the diff list can't loop into React #185 (#31552)
The image viewer chunk is lazy. Its first load suspended to the editor panel's
boundary, which hid the whole virtualized combined diff. Hidden, the list
dropped the overscan image row, stopped suspending and re-showed; shown, it
rendered the row again and re-suspended. Each flip re-attached ref callbacks
(the toolbar's 'Show file tree' tooltip trigger first), so the synchronous
commits ran past React's nested-update limit (or tore down Monaco mid-mount).

A row-local Suspense keeps the chunk load inside the image section.

Co-authored-by: m4air <m4air@Mac.localdomain>
2026-11-02 22:03:06 -08:00
Brennan Benson 2d3ad7a07b Let agent message names use the available card width (#37657)
* Let agent message sender names use the available width

* Cover full long sender names after a rename
2026-11-02 21:59:04 -08:00
NeilandClaude dc1a5c00f9 fix(terminal): repaint WebGL atlases once the bundled Nerd Font symbols load (#37688)
Chromium loads the bundled 'Orca Nerd Font Symbols' face lazily, so the
first PUA glyphs rasterized into xterm's WebGL atlas fell back to tofu
boxes and stayed cached after the face landed. On first WebGL attach,
watch document.fonts for that face's loadingdone and reset/refresh all
terminal atlases once, also clearing hidden managers' atlases (without
painting) since light reveal only re-presents retained canvases.

Fixes #37627

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 21:52:42 -08:00
Neil 24832db45d Restore launch submit icons and unify agent row highlighting (#37675) 2026-11-02 21:49:09 -08:00
OrcaWin 46d3998a14 test: remove 153 low-value shared hook tests (#37686) 2026-11-02 21:47:38 -08:00
NeilandCopilot 5c5da5daba Fix worktree icon mouse focus hover (#37678)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-02 21:47:19 -08:00
NeilandClaude 632792aa02 fix(window): don't open a window in a process whose quit teardown has started (#37676)
On Windows, relaunching Orca while the previous process was still quitting
delivered a second-instance activation to the exiting process, which opened a
new main window bound to services already being torn down; the window never
appeared and the exit hung.

focusExistingWindow's canOpenWindow now also returns false once the quit
teardown start gate has fired, and delayed reopen retries re-check
canOpenWindow before constructing a window so a retry scheduled before quit
can't slip through afterwards.

Fixes #37625

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 21:32:27 -08:00
OrcaWin 5f88957b15 test: remove 78 low-value shared listener tests (#37673) 2026-11-02 21:29:54 -08:00
Brennan Benson bff4e364ab Avoid unchanged text attachment updates during cached scrolling (#37644) 2026-11-02 21:18:12 -08:00
Neil a3fd5c2f4c Use native submenus for new-tab agent setup (#37576)
* Make new-tab agent setup feel like a native submenu

* Separate the agent submenu chevron into its own segment

* Restrict agent submenu hover to the chevron segment

* Highlight agent menu sections independently and focus setup search

* Restore agent row highlighting and empty-search back navigation

* Keep the agent chevron filled for hover and keyboard selection

* Match agent launch buttons and add the alternate launch shortcut

* Preserve submenu pointer grace and update launch button selectors
2026-11-02 21:10:07 -08:00
NeilandCopilot 0c209ce68b Use compact worktree identity icons (#37672)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-11-03 05:10:00 +00:00
Kelvin AmoabaandManan Chataut b074306201 fix(omp): retain prompts refused by autonomous busy turns
Retain the original OMP prompt across explicit typed busy refusals, keep queued follow-ups ordered, and cancel recovery on Stop or close.

Fixes #34807

Co-authored-by: Manan Chataut <mananchataut@gmail.com>
2026-11-03 05:08:55 +00:00
OrcaWin 44e63bb18e test: remove 194 low-value renderer web tests (#37668) 2026-11-02 21:02:39 -08:00
Neil fd99549aec Draw workspace cards from a template (card plugins, phase 1) (#37647)
* feat(sidebar): draw workspace cards from a template (card plugins phase 1)

Today's card becomes the built-in card template: a JSON template of
layout primitives and Orca's own card parts, compiled once and evaluated
per card over a documented workspace fact model. Markup parity with the
original composition is tested for 34 states in all three card styles.

* fix(sidebar): card template typecheck

* fix(sidebar): bound card template def expansion and tighten expressions

- Cap expanded elements (maxExpandedNodes 2000), expanded depth (maxDepth)
  and def nesting (maxDefDepth 8) at compile time, so reused defs cannot
  multiply into millions of elements.
- A def reference now keeps the frame's root attributes, rejects props and
  children, and is looked up with hasOwn.
- Chained ternaries count toward the expression depth cap; len(x,) is rejected.
- Parts are documented as hook-free.
- Drop the unread CompiledCardTemplate.roots; schema now reads
  WORKSPACE_CARD_FACTS_VERSION. maxBytes stays for phase 2.

* chore(sidebar): baseline the card template's moved focus read and allowlist non-UI strings
2026-11-02 20:56:01 -08:00
OrcaWin 01ac76d626 test: remove 75 low-value renderer store tests (#37658) 2026-11-02 20:41:35 -08:00
Neil 18f674e69f refactor: group workspace catalog and execution-host owners (#37641)
* refactor: group workspace catalog and execution-host owners

* test: annotate catalog fixtures with portable public mock types

* test(workspaces): preserve filesystem worktree mocks at concrete owners
2026-11-02 20:22:21 -08:00
Brennan Benson 8eba2a0bdc Agent message cards find their sender's agent and status in the same store as the sidebar (#36660)
* Agent message cards keep their sender's agent icon when the agent can't be found

A card names its sender by a snapshot written with the message, but drew the
icon only from a live lookup, so a sender the lookup missed (a worker on
another host, a terminal after restart, a closed agent) showed "?". Every
writer (worker start, mail, task, federated start) now saves the sender's
agent kind beside its name, and the card draws it when no live row names
the agent. Live rows stay the source of icon and status whenever they match.

* Preserve known worker agents on federated cards and mail

* Resolve agent message senders through shared host identity

* Retain acquired worker launch identity for later sender snapshots

* Prune repeated worker sender contract checks

* Combine worker command contract projection imports

* Keep sender identity bounded and scoped per worktree

- A worktree removal frame drops only its own scope; a host stays
  publishing once any frame carried the field.
- Identity history rebuilds follow writes to the facts it reads
  (connection-local triggers), not heartbeats, read marks or receipts;
  new mail is read incrementally.
- One principal per paired peer replaces every federated route ever made.
- Unchanged worktrees keep their scope object; a refresh republishes only
  worktrees whose scope changed. Chat records key on the store's state
  generation instead of serialising every record.
- The publication rides client frames only, and phone frames drop it.
- A failed history read keeps the last good publication and is not
  marked indexed; malformed rows are skipped; opening the database for
  display never throws.
- A located chat keeps its tab's agent icon for cards saved without one.

* Save each agent card's sender identity and open the pane it names

Orca now records who sent each agent message and created each task when it accepts them, and the chat card resolves that saved identity against what each host says runs now. The avatar dot, label and click all read that one answer: a located terminal opens through the sidebar's own activation path, a closed chat reopens through its lineage, and a sender no host can prove shows its saved icon and says it is no longer available instead of opening whichever agent now holds the old pane.

Publication now has the host's pairing key from the RPC server, so it no longer fails on every build.

* Resolve agent card senders by the terminal handle every card saves

A card's sender is now the terminal its saved handle names, the worker lineage its Dispatch continued into, or its chat session. That survives a normal restart, works with hooks off, from a plain shell and for replies, and needs no newly saved sender data, so the hook-conversation records, their table and the saved identity key are gone.

The avatar, link and click read one answer. A terminal that now runs a different kind of agent than the card saved, or a sender two places claim, shows the saved icon as a plain name. A terminal that exited or was respawned keeps the host's own lookup on click without a status dot, behind one switch.

Chat senders rebuild only when a chat appears, moves, clears or closes, and each live pane's worker reads go through the existing partial indexes.

* Send sender identity once per revision and judge every host by one rule

The host's sender publication now carries an in-memory epoch and content revision that move only when what clients read changes. A window's graph sync sends the revision it applied and gets "unchanged" instead of the rows; each session-tab stream sends a worktree's scope once per revision. The window keeps the whole-host publication as its baseline and a newer worktree scope over it, by revision, so a delayed reply never undoes a newer scope and repeated deliveries cost nothing.

An older paired host's cards now go through the same resolution as everyone else's: a terminal that runs a known different agent shows the saved icon as a plain name, and what the host's lookup returns is judged by the same row. Pi and OMP, and Claude and its teams wrapper, count as one agent. Failure text names the agent and says what to do.

WSL chats are published, closed chat history no longer counts as open before the tab table exists, and paired principals are read again only after a pairing changes.

* CI: keep the sender delivery contract test out of the web project and fix its types

The cross-process delivery test moves to tests/e2e, where tests that span main and renderer live, so the web typecheck no longer pulls main files in. It now drives the stream encoder main uses. The worker lineage walk takes a reader type without a this binding, the stream delta composes with the proof delta's own frame type, alias buckets accept terminal and chat tab arrays, and the publication test builds fully typed fixtures.

* CI: share the dispatch-address link rule and align the merged view test with saved-kind icons

The base's worker command contract test reads the shared rule that a
dispatch: address is never a link; the card's link check now calls that
shared rule instead of repeating it. The base's sender view test expected a
different agent's live row to replace the saved icon; this branch shows the
saved kind without that row's status, so the test asserts that.

* Use the sender snapshot resolver in main's new receiving-account tests

* Read a saved "unknown" agent kind as no kind for the card's icon and its replaced check

A hooks-off agent whose last status came from a terminal report without an app id saves the kind
"unknown". That kind proved nothing, yet it vetoed the live agent in its own terminal: the card
showed "?" with no dot as a plain name, and a raced click said another agent was running there.
One shared read now treats it as no saved kind for the veto and the icon, on every path.

* Apply a frame's sender scopes when the window receives it, ordered by each scope's own revision

A stream counts a sender scope as sent once a frame carries it, but the window applied it only
inside the tab apply, behind the tab version, resume census, receipt recovery and frames-draw
checks. A frame those checks dropped could hold the only copy, so a paired host's cards stayed
on stale rows (no dot while the sidebar showed the agent) until that worktree's senders changed
again. Each receipt path now folds the frame's sender scopes in right after its connection,
pairing and runtime checks; the tab apply keeps only a worktree's removal.

A scope now also yields to that scope's own newer delivery, not only to a newer whole-host
baseline, so a delayed list reply can't put back older rows. Every publishing host stamps a
revision, so the content-comparison path for unrevisioned publications is gone.

* Read chat senders from open chats and their /clear predecessors, not every saved chat

Each chat tab opened or closed, chat created or moved, or /clear committed rebuilt the chat
senders by listing every saved chat (42 ms at 10,000 on the main thread) only to keep the open
ones. The record store now keeps an in-memory reverse of the saved /clear pointer, built at
load and updated for the rows each commit writes; nothing new is saved. The sender read starts
from the open chats and follows that index to their predecessors, so its work no longer grows
with closed history.

* Walk live terminals once per session-tab inventory or broadcast, not once per worktree

A one-shot inventory or a broadcast built every worktree's frame through its own sender
refresh, and each refresh walks every live terminal: 20,000 visits for 1,000 terminals over 20
worktrees. Both passes now build their frames from one refresh. The publisher counts its leaf
and terminal visits, and a test drives the real inventory and broadcast methods at 100 and
1,000 terminals.

* Re-read a tab bucket's sender aliases only when a host it read changes

The window's sender aliases were recomputed for every open tab whenever any workspace-owner input
changed, such as switching workspaces or writing a setting, though a bucket reads those inputs
only through one host per worktree. Each bucket now keeps the host values it read and, when
owner inputs move, checks just those before reusing its aliases. The delivery contract test
counts alias work through workspace switches, settings writes and a title-only change.

* CI: restore the single-frame builder declaration and compare sender content without its revision

R4 swapped the inventory's abstract single-frame declaration for the batch one, but the
headless browser-tab emit and the runtime-owned terminal create still build one worktree's
frame through it; both keep the per-frame sender scope. The publisher's content comparison now
takes publications without their revision stamp, which R4 made required.

* CI: give the sender no-op test's heartbeat a fixed timestamp instead of the wall clock

The heartbeat only has to be a write that changes no sender identity, so a fixed time keeps the
assertion and satisfies the flaky-test gate.

* CI: assert one terminal walk per orchestration RPC and no identity reads in the sender refresh test

R4 added leaf and terminal visit counts to the publisher's work counters, and each orchestration
RPC's refresh walks the live terminals once, so the whole-counter comparison failed. The test now
compares history, chat and lineage reads, unchanged, and asserts exactly one walk per RPC.

* CI: reach the sender pass methods through a typed view of their prototypes

The test read the runtime's protected inventory and broadcast methods with Reflect.get and an
object-typed owner. It now names the three methods it drives in narrow types over their real
prototypes and calls them on the same stand-in; the assertions are unchanged.

* CI: list every sender target kind in the link switch and merge the duplicate sender-type import

The link check's switch now names the ambiguous and replaced kinds, which return false as the
default did; the publisher imports its sender types from one statement.

* Skip a paired host's floating-terminal sender scope at receipt, as the tab apply does

Applying sender data on receipt took a paired host's floating-terminal scope that the window
never mirrors, so its sender drew as a link whose click activated a pane this window lacks and
did nothing. The receipt now uses the tab apply's own floating rule for paired hosts: that sender
opens by asking its host, as before. This machine's own floating terminal still publishes.

* Read /clear predecessors through the record store's existing successor index

The sender's chat read reached each open chat's /clear predecessors through an in-memory reverse
index the record store built at load and kept per commit. The store already has an indexed query
for that link, which its lineage read uses; the sender now shares that query and checks each
candidate on its conversation, so branching, unreadable and cyclic predecessors resolve as
before, and the second index and its commit bookkeeping are gone.

* Keep live workers' sender history between builds and re-read only what a write reaches

Any write to a Dispatch, worker terminal or remote attachment re-read the history of every live
terminal (three queries and the lineage reads per pane) on the main process: about 20 ms at 100
live workers and 150 ms at 1,000, for a write none of them read. The connection's triggers now
also record the panes and Dispatch ids a write's old and new rows name. The history keeps each
live pane's reads and each Dispatch's verdict with every key it read, lookups that found nothing
included, so a write re-reads only the panes and lineages it reaches. Federated Dispatches move
their own counter, so worker writes no longer re-read paired principals. A commit from another
connection, which no trigger sees, still rebuilds everything.

* CI: build each sender trigger from a typed event list so its SQL parts are plain strings

* CI: give startup runtime fakes the sender peer-key setter and drop new test type assertions for typed fixtures

* Ask the host to reveal a located sender this window holds no tab for, as the lookup did before

* Keep no worker history read inside an open transaction, and forget workers and keys no live pane reaches

* Test that sender names render only when what they show changes

* CI: pass the sender target's dispatch id explicitly and write a real sidebar body in the delivery test

* Read terminals' existing handles for sender rows instead of issuing them

The sender publication walked every live terminal through the runtime's handle-issuing functions,
so each display build could mint, adopt or rebind terminal handles. During a renderer reload or a
split close that changed which handle a terminal held and what retirement frames published. Sender
rows now read only the handles terminals already hold; a terminal with no issued handle has no row,
and no card can name it.

* Open a located sender's own pane through its host when this window has no tab for it

When a card's sender was found in a pane this window had not loaded yet, the click asked the host
about the card's saved terminal instead. For a worker reopened by a follow-up, that opened its first
terminal, or said the pane was gone, while the card showed the reopened worker running. The click
now opens that same pane: by the handle its status row holds on that host, else by asking the host
for that pane in the host's own coordinates. It checks the card again after the host answers, and a
closed pane says the agent is no longer running. The saved-address lookup stays only for senders no
host has located.

* Read a terminal's start-time handle for its sender row while no window graph exists

When the window graph went away, the host cleared its handle records but kept each terminal's
start-time handle, which its agent's mail cards save as the sender. The read-only handle lookup
required a record, so the running terminal lost its sender row and its cards showed no dot until a
window came back. It now returns the handle issuing would reuse, record or not, and still changes
nothing.

* CI: type the open helper's target as any runtime target so the paired-host case typechecks

* Lease the sidebar rows a sender name's link check reads, as its avatar does

A sender name drawn without an avatar (queued mail, a card's later senders) checked for a different
agent through a source nothing leased, so every store write rebuilt that worktree's sidebar rows.
The name's link now holds the same lease the avatar does, and a card with no saved agent kind
skips the row read entirely.

* Index a build's terminal handle records once instead of scanning them per terminal

The read-only handle lookup fell back to a scan of every handle record for each leafless terminal
holding no handle, on every sender build. A build now gets one reader that indexes the records on
its first miss and answers each terminal from that index, with the same handles issuing reuses.

* Lease a replaced card's sidebar rows from where its sender runs before the kind check

A card whose terminal now runs a different agent resolved no location, so it leased no row
source and rebuilt its worktree's rows on every store write. Both the avatar and the link now
lease from the candidate location the kind check reads; their answers are unchanged.

* Show a paired host's worker status dot on its card when this window mirrors the whole tab

A paired host names a pane <tab>:<leaf>; this window mirrors that tab whole as web-terminal-<tab>
with the leaf ids kept, and its status rows use that key. The alias projection mapped only
per-pane mirrors, so the card located the host's key and found no row to draw a dot from. The
terminal bucket now also maps a whole-tab mirror's host tab, and a host pane takes this window's
name from either form; two names for one pane still locate neither.

* Publish a chat sender change even when the terminal read in the same refresh fails

The chat rows and their key were stored before the terminal read; when that read threw, nothing
was published, and the next build saw both keys as handled, so the chat change waited for an
unrelated identity change. The refresh now publishes whatever changed beside the last good
terminal rows, and the read's error still reaches the build's warning.

* Bound sender projection work to current consumers and lineage facts

* Update runtime call assertions for sender demand options

* Preserve mobile sender navigation availability
2026-11-02 20:09:00 -08:00
Vyacheslav Scherbinin 1b02dc2f31 perf(mobile): keep plugin validation out of plural lookup (#36914) 2026-11-03 04:08:15 +00:00
OrcaWin d2fb04cd9a test: remove 131 low-value renderer store tests (#37648) 2026-11-02 20:07:50 -08:00