* 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>
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>
* 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>
Follow-up to #37699: pr.yml computes defer_shadow once, unit-plan.yml
uses only that input and exposes selection_planned, and the test and
evidence jobs read that output instead of repeating the condition.
Emit the full matrix without dependency installation or graph discovery; retain independent full test discovery and selected-draft provenance. Reuse existing draft plans, and disable unpublished transform writes on warm misses. Automatic cache production was removed after review because the near-quota cache store has no budgeted retention plan. Full required PR CI passed on 658ea5275c.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* 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
* 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>
* 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>
* 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>
* 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>
* 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>
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>
* 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>
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>
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>
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>
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>
* 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
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>
* 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