mirror of
https://github.com/stablyai/orca.git
synced 2026-10-07 16:02:29 +00:00
ccfc8fe2c464bdfb052fcea9a5206b4e0acddd2e
12705
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ccfc8fe2c4 | Update README downloads badge | ||
|
|
6f8eee3776 |
fix(test): pass getInsertionRange in the image-insert access test (#25351)
#25176 replaced insertPos with getInsertionRange and #24489 added a test using insertPos; together they broke main's typecheck. |
||
|
|
51fe6f3fba |
fix(editor): restored tabs for files outside your projects no longer fail with Access denied (#24489)
* fix(editor): read files outside projects without a grant a restart loses
A file opened from outside every project (e.g. ~/notes.txt from the floating
workspace) read through an in-memory grant. After a restart the restored tab
only renewed that grant when it stored a full path, so a tab saved relative to
the floating workspace folder failed with "Access denied" and Retry repeated it.
Single-file reads (read, stat, exists) and open-editor-tab saves now resolve a
path outside every project in place. Paths inside a project keep the full
containment check, so a project's symlinks still cannot escape it, and every
other write stays inside projects.
* fix(editor): re-grant restored floating-workspace tabs by owner, not path shape
Problem: a file opened from the floating workspace (e.g. ~/notes.txt via
Cmd-click in the floating terminal, the floating markdown picker, or a .md
opened from the OS) loads until restart, then shows "Access denied: path
resolves outside allowed directories". Main's external-path grants live only
in memory. On restore the editor re-granted only tabs that stored an absolute
path, but floating tabs store a path relative to the floating root (~ by
default), which is deliberately not an authorized root, so they were never
re-granted. Restored floating notebooks also failed to start a kernel.
The previous commit on this branch let main read and save any path outside a
project without a grant. That widened fs:readFile/stat/pathExists for every
caller, including automatic reads of untrusted content (markdown preview
images), which opened a Windows UNC credential leak and a /dev/zero
main-process memory blowup. This reverts that model entirely.
Fix: one helper decides which client-local path a tab needs re-granted by
ownership: a floating-workspace tab, or a tab stored outside its own project.
It never grants paths a local project root covers (a grant would also
authorize a project symlink's outside target), and skips SSH-owned,
runtime-owned and not-yet-hydrated owners. Every reader that can touch a
restored tab before or without the editor loader uses it: the loader, the
restored dirty-tab conflict scan, and the paired-mobile markdown bridge.
* fix(editor): let main decide which restored-tab paths a project already covers
Problem: the restore re-grant helper decided "already inside a project" in
the renderer from its worktree list. At startup that list only holds repos
the session references, so a floating tab inside an unlisted repo was granted
(including a symlink's outside target), and the renderer's path matcher
disagrees with main's on WSL \\wsl$ vs \\wsl.localhost, which stranded a
folder-workspace tab with "Access denied" after restart. The helper also
treated a folder workspace with a missing or ambiguous host as local.
Fix: the renderer now decides only by owner (a floating-workspace tab, or a
tab stored outside a project whose owner is explicitly local) and asks main
with `skipIfInsideAllowedRoots`. Main checks the path against its own allowed
and registered roots, in both the named and canonical-parent spelling against
both root spellings: a path a project covers gets no grant, an alias spelling
of a project path gets only that spelling, and a project symlink's outside
target is never granted. Explicit-open grants (Cmd-click, drag, explorer) are
unchanged. Tests now prove each reader waits for the grant before reading.
* fix(fs): decide a restored tab's project membership from every ancestor's real path
Problem: the restore re-grant decided "inside a project" from the named path
and the real path of its parent only. When a tab path crossed a project
directory symlink and named the project through a spelling that was neither
the registered root nor its realpath (a second alias, a `..` segment, a case
variant on a case-insensitive disk, a /var-style alias of an ancestor), no
check matched, the path took the full grant, and the symlink's outside target
became readable and writable.
Fix: a path is inside a project when the named path is inside a root, or the
real path of any ancestor folder is inside a root in its registered or real
spelling. Such a path gets at most its named spelling, never its realpath. An
ancestor that fails to resolve for any reason other than "missing" now fails
closed to the named-spelling grant instead of falling through to the full one.
Tests cover each spelling; the non-symlink case also runs on Windows.
* fix(fs): read local files as regular files only, from one bounded handle
Problem: fs:readFile stat'ed a path and then read it to EOF. A character
device such as /dev/zero reports size 0, passes the size limit and never ends,
so the main process buffers until memory runs out; a FIFO hangs the open.
Writes could also target an existing device or FIFO.
Fix: every local fs:readFile (editor and log snapshot) opens the path once,
non-blocking, refuses anything but a regular file, and reads the size check,
binary probe and content from that same handle, capped at the limit even if
the file lies about its size. The AI Vault log tail opens non-blocking too,
and fs:writeFile refuses an existing non-regular target.
* feat(fs): let desktop file requests declare their shape
Problem: main decided every local file request against one allow-list plus a
set of in-memory grants the renderer had to recreate after every restart, so
a file the user opened outside a project (for example from the floating
workspace) was denied once Orca restarted.
This adds the request shape the common pattern uses, alongside the grants for
now:
- no shape (the default): the path must be inside a project root main
recognises, symlinks included. Desktop requests also accept the app-owned
floating-workspace folder; paired-client RPC never does.
- user-file: a single file the user named by absolute path, used in place.
Only fs:readFile/stat/pathExists and saving (fs:writeFile) accept it.
- document-resource: an image or PDF a document references, limited to every
project root when the document is in one, else to the document's folder,
and refused by path text before any disk or network access.
Notebook kernels and AI Vault log tails check their open file as user-named.
* feat(editor): send each local file request's shape from the renderer
Problem: after a restart, a tab opened outside every project (a floating
workspace file, a file opened by absolute path, an OS-opened markdown) could
only be read if the renderer first re-granted its path, and readers that ran
before the editor loaded the tab had no grant at all.
The renderer now says what kind of request it is making, and main checks that:
- A persisted tab opened outside its owner's root (floating workspace, or an
absolute stored path) whose owner is explicitly local reads and saves as a
user-named file, from every reader: the editor loader, the restored-tab
conflict scan, the change banner and compare dialog, the paired-phone
markdown bridge and the save queue. Project tabs stay inside their root.
- Clicks, drops, typed paths and browser-opened notebooks stat as user-named.
- Markdown preview and rich-editor images are document resources, limited to
the document's roots or folder. Images the user pasted or attached into a
chat show as user-named; agent images stay inside the project.
- The image cache keys on the shape, so one shape's image never answers
another's request.
A ratchet test lists every renderer file allowed to create a user-named
request.
* refactor(fs): delete the in-memory path grant system
Problem: main kept a set of paths the renderer had asked it to allow
(fs:authorizeExternalPath). The set lived only in memory, so a file the user
opened outside every project could be read until Orca restarted and was then
denied, and every new reader of a restored tab had to remember to recreate
the grant first. Three rounds of re-deriving grants at restore each found
another reader or path spelling it missed.
Now that every desktop request declares its shape, nothing needs a grant:
- delete the grant set, authorizeExternalPath, the restore re-grant from the
earlier commits on this branch, the fs:authorizeExternalPath channel and its
preload and web-client entries;
- delete every renderer grant call (terminal and markdown link clicks, drops,
typed paths, the file explorer, AI Vault logs, chat attachments, browser
notebooks) and every main one (floating markdown picker and folder, OS-opened
markdown, keybindings.json, pasted images, import and upload sources);
- the floating workspace's picker-approved folders stay a terminal-cwd
allowlist only.
Main now holds no per-path permission, so a restart can't change any answer.
* feat(editor): open project links that lead outside the project as named files
Problem: a file inside a project that is a symlink to something outside it
opened fine from the file explorer or a terminal Cmd-click, then showed
"Access denied" after a restart: its tab was stored as a project file, and a
project request is refused when it resolves out of the project. A folder link
out of the project expanded in the explorer until restart and then failed with
a raw access error.
Now the click decides and the tab keeps that decision. Both gestures stat the
path inside the project first; if only the user-named check passes, the path
leads out of the project:
- a file opens by its absolute path, so it reads and saves as a file the user
named, the same before and after a restart;
- the explorer does not follow a folder link out of the project and says so
("This folder links outside the project, so it can't be opened here.").
Paths that stay inside the project still open as contained project tabs. Also
drops the AI Vault "path not authorized" message, which nothing shows now.
* chore: drop the casts the changed-code quality gate flags on this branch
The FileContent casts in the editor loader and the paired-phone markdown
bridge were never needed (the read result is already assignable). Tests stub
window.api through vi.stubGlobal and pass narrow stores without casting; the
one test store that still needs a cast states why.
* fix(fs): load chat images by type, and keep escaping project links readable
Problems found in review:
- Chat transcript images were trusted by message role: any user-role
"[Image: source: <path>]" (an injected Claude record, `orca terminal send`,
a paired client's image-ref) became an automatic user-named read as the row
scrolled into view, of any file type, and on Windows a network-share path
would have opened an SMB connection to that host.
- A document image named like an image but linking to a text file
(logo.png -> .env) was read as text.
- Windows device names (NUL.png, COM1.jpg) passed the path-text check of the
automatic image loads.
- A project symlink leading out of the project, opened by a typed path, a
tab-strip drop or a browser file:// notebook, was stored as a project tab
and immediately refused.
Fix:
- New chat-image request shape for every transcript image and the composer
preview, whoever's turn named it: an absolute local path whose requested and
real targets are image files, a regular file, size-capped; network-share and
device-namespace paths and Windows device names are refused by path text
before any filesystem call. Pasted screenshots still show after a restart,
and agent images outside the project now render.
- Document resources check the real target's type too, and refuse Windows
device names by path text.
- Typed paths, tab-strip drops and browser notebooks stat through the same
check as the explorer and terminal, and open an escaping link by its
absolute path.
- Tests pin the shape at the change banner, compare dialog, markdown preview
and image prewarm; a second ratchet lists every file that can open a tab the
tab rule reads as user-named, and its comment says what it can't see.
- Stale grant wording removed.
* fix(fs): tighten automatic image loads and the project-link check
Problems found in review:
- Two unit tests went red on this branch: the browser-share test still
expected reads without a shape, and the rename test's electron mock had no
app, which the desktop root check now needs.
- The device-name check ran on the raw path, so `NUL.png\.` or
`COM1.png\x\..` (reachable from markdown ``) reached the
filesystem; a document image whose real target was a device name passed.
- Chat images in a project that lives on a Windows network share no longer
rendered, though the markdown preview showed them.
- Any failed project check (a missing file, a dropped connection) was taken
as "this link leads out of the project" and opened as an absolute tab.
- Every local read allocated about 2 MiB, even for a tiny image.
Fix:
- Device names and device-namespace paths are checked on the resolved path
and on the real target, for chat images and document resources alike.
- A network-share path in an automatic load is read only inside a project
root (the user chose that share when adding the project); anywhere else it
is still refused by path text before any filesystem call.
- Only main's "outside allowed directories" refusal marks a project path as
leading out of the project; other errors surface as before. The message now
lives in shared code so both sides agree on it.
- Reads size their first buffer from fstat and confirm EOF with a 1-byte
probe; a file that grows past its reported size is still read in bounded
chunks up to the cap.
- Fixed the two red tests.
* refactor(fs): name file access by its role, not its structure
Problem: the static-analysis anti-slop check failed the PR because the new
code named the request's file access a "shape" (`shape`, `RequestShape`,
`TabShape`), which describes structure rather than the role.
Rename the main-process module filesystem-request-shape.ts (and its tests) to
local-file-access-resolution.ts, rename the symbols to fileAccess,
FileAccessResolution and TabFileAccessFields, and say "file access" or
"access kind" in the comments and test names. No behaviour change.
* fix(fs): refuse every Windows device-name spelling in automatic image loads
Problem: the device-name check split a file name only on '.', so names such
as NUL:.png, COM1:.png, NUL:stream.png (an alternate data stream) slipped
through, and CONIN$, CONOUT$, CLOCK$, COM0 and LPT0 were not listed. Those
reached the filesystem from a document or chat image before being refused.
Split on ':' as well, list the missing device names, and test each with
Windows path rules and zero filesystem calls. Also cover the case of a local
link that leads onto a network share outside every project (refused for chat
images), and correct the shared comment on chat-image access.
* fix(editor): let users rename and insert images into files opened outside projects
Renaming a file opened outside every project (tab double-click, editor
header) and inserting an image into such a markdown document failed with
"Access denied", even before a restart: both writes only passed the
project-root check. Document resources and chat images were also limited
by file type more strictly than users expect.
- Add a "document-folder" access kind for writes beside a document the
user opened: main allows renaming only that document, to a name inside
its own folder, and importing new files only into that folder, checked
by path text and again by real path, with Windows device names refused.
The renderer sends it only for local user-named, writable tabs (rename,
its undo/rollback, image insert); SSH and runtime requests never carry it.
- Document resources: drop the image/PDF type allowlist; folder
confinement, regular-file reads, the cap and path-text refusals remain.
- Chat images: judge only the real target's type, against every
previewable image type (AVIF added).
* fix(fs): a declared file-access kind never refuses what the project check allows
A full-path tab for a file inside a project (for example a link that
leads out, opened by its absolute path) was renamed under the
document-folder rule, which limited the new name to the file's own
folder, although the same rename with no declared access could move it
anywhere in the project. Any declared kind could be stricter than the
default in the same way.
Every desktop local file request now goes through one resolver,
resolveLocalRequestPath: it runs the default project check first (roots,
Orca's floating folder, symlink containment, outside-root path text
refused before any filesystem call) and only on a refusal applies the
declared kind's rule, which adds paths outside projects. Reads, saves,
rename source and target, and import destinations all use it, so a new
kind gets the rule for free. Automatic loads (document and chat) still
refuse Windows device paths and names by text first, even inside a
project; a device is never a file to show.
The document-resource rule no longer needs its own project branch, and
chat images no longer re-run the roots check for shares.
* fix(fs): symmetric outside-project renames, notebook real folder, same-share images
- Renaming a file opened outside every project accepted a name in a
subfolder (`archive/todo.md`), but the Undo and the rollback rename,
declared from the moved file, were then refused and the file stayed
moved. A rename under document-folder access must now land directly in
the document's own folder (checked by path text before any filesystem
call), so rename, Undo and rollback are symmetric. Image import still
accepts the folder or a folder under it. Inside projects the default
check still allows any in-project target.
- A notebook opened through a link inside a project started its kernel in
the link's folder instead of the real file's folder (main's behaviour),
because notebook and AI Vault log-tail paths skipped the project check.
Both now resolve through resolveLocalRequestPath (project check first,
then the user-file rule).
- A markdown file opened from a Windows share outside every project could
not show the images beside it. Document images on a share are now
allowed inside the document's own folder; the folder text check refuses
every other host and share before any filesystem call.
- resolveDesktopAuthorizedPath is async, so a synchronous failure in the
default check rejects like any other refusal.
* fix(fs): refuse share images outside projects again; keep renames and kernels as on main
- Reverts the same-share document image rule from the previous commit.
Its folder check compared hosts case-insensitively, so a host spelled
with U+212A KELVIN SIGN (or a decomposed accent) passed as the
document's own share and was contacted, reopening the network
credential leak. Document and chat images on a share outside every
project are again refused by path text before any filesystem call;
tests now cover the look-alike hosts with zero filesystem calls.
- Renaming a file opened outside every project into a project folder
passed the project check, but its Undo (declared from the new path)
was refused and the file stayed moved. When the rename source is
allowed only as the opened document, the new name must now land
directly in the document's folder even if a project would accept it
(resolveLocalRenamePaths).
- A notebook opened through a link outside every project started its
kernel in the link's folder; main used the real file's folder. The
kernel cwd is now the real file's folder in every case.
* fix(fs): a file opened outside every project renames to any path, and keeps its access
Renaming a document the user opened (floating workspace or full-path tab) now
follows the user-file rule: the source must be the opened document, and the
new path can be any absolute path, so a rename into another folder, a
subfolder or a project works, and its Undo (declared from the moved file)
comes back from there. Any other rename keeps the project check only. Remove
the same-folder rename rule and its tests; image import stays in the
document's own folder.
After a move, a tab stored by its full path keeps its full path instead of
being recomputed project-relative, so it keeps user-file access for save,
the next rename, image insert and restore after restart. Folder moves go
through the same remap.
Also un-export unused resolver exports and avoid a copy for single-chunk reads.
|
||
|
|
955dce5a5a |
Keep workspace deletion dialogs steady while changes load (#25321)
* Keep workspace deletion warnings from shifting the dialog * Tighten spacing in workspace deletion confirmations * Address deletion dialog review and synchronize localization catalogs |
||
|
+2 |
8e5080c132 |
Validate OpenCode worker model preferences on the execution host (#24624)
* feat(orchestration): support OpenCode worker model selection Allow supervised OpenCode workers to use per-launch model overrides through the existing launch-preference and receipt path. Preserve existing OpenCode agent arguments while replacing only model flags, and reject unsupported effort values explicitly. Keep Native Chat option exposure unchanged and update the worker CLI and orchestration guidance. * fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(orchestration): gate OpenCode worker model preferences by host capability Co-authored-by: user141514 <user141514@users.noreply.github.com> * feat(opencode): probe launch capabilities on the execution host * feat(opencode): probe execution-host CLI capabilities * feat(opencode): probe launch capabilities on the execution host * feat(orchestration): resolve explicitly configured command aliases * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(orchestration): verify available OpenCode model on execution host * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): unsubscribe hook settings during async host shutdown * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * test(readiness): census recorded OpenCode composer boots * fix(opencode): reject redirected overlay parents before cleanup * fix(orcad): retain runtime cleanup when subscribing to hook settings * refactor(launch): extract OpenCode config and attachment authority * fix(opencode): retain host version selection across relay restarts * fix(opencode): pass run prompts as positional messages Preserve run flags and use the existing shell quoting and run-command detector to append the initial message after --, reusing an existing separator. TUI launches retain their version-selected prompt transport and draft behavior. Original run-order work: @coelho-doti (#13065, tracked in #17551). * fix(opencode): keep wrapped run tasks positional Recognize supported environment prefixes and PowerShell call operators without mistaking prompt arguments for executables. Keep environment and run separators separate, preserve the task text and exclude run commands from native submission. Source-parent: |
||
|
|
e2460907c3 |
Preserve image clipboard targets and content across editor changes (#25176)
* Preserve image insertion targets with one captured destination * Set image paste test caret through the editor selection |
||
|
|
d3afb5c5a9 | Preserve large paste destinations and native Undo boundaries (#25177) | ||
|
|
cecb62158a |
fix(ui): restore IME Enter protection in workspace details (#24099)
Restore IME Enter protection in workspace details by reusing the existing composition tracker. Reset Notes ownership at textarea detachment and preserve sizing behavior. Repair isolated native test-window delivery without changing the production foreground policy or original native input assertions.
Fixes #24097
Related contributor history: #10711, #11067, #13128, #13282.
Original implementation and macOS recordings: @setodeve, commit
|
||
|
|
75344e5850 | docs: align contributor guidance with the PR template (#25034) | ||
|
|
1978469fd2 |
fix(mobile): keep the working rings turning on the OTA page (#25299)
* fix(mobile): keep the working rings turning on the OTA page Animated.loop starts a native loop whenever the timing asks for the native driver; the web has none, so the JS fallback ran one turn and froze at 360deg. Ask for the native driver only off the web. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * test(mobile): pin the native driver on native spinners Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * refactor(mobile): share the working ring rotation between both rings Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb |
||
|
|
3b01ba6d0d |
fix(native-chat): show "Sending…" on a message until the host confirms it (#24606)
* fix(native-chat): no "unconfirmed" line while Orca resends a send on its own A send whose answer was lost (for example after reopening the chat mid-send) showed "Message delivery is unconfirmed." with a Retry for the moment before the automatic resend under the same message id confirmed it. One rule now decides both: the resend runs, and the notice stays quiet, only while the send's answer is lost, the user never retried it, it was not still going out when the user pressed Stop, and the host has no record of it yet. Once the host has any record of it, the line and Retry are exactly as before. * fix(native-chat): say "Sending…" on a message until the host confirms it A send whose answer was lost was resent quietly under the same id but looked like any delivered message. Every message still in the outbox with no failure to show now says "Sending…", muted, in place of its time, until the journal holds a row for it. Rows that say a message did not go through keep only that line and its Retry. The notices read the outbox through the same reconcile as the transcript, so a row that lands clears the marker in one step. * fix(native-chat): keep "Sending…" until the host has the message, in the time's slot A message the user retried, a second message in doubt, or one requeued over a rejected row had a journal row that did not hold it, so it showed nothing and looked sent. "Sending…" now stays until the row is pending or accepted. The marker took the place of the whole meta row, so the copy button went away while sending and the row jumped when it cleared. The row now stays mounted: copy keeps its hover reveal and "Sending…" sits where the time goes. * test(native-chat): move the delivery probe tests into their own file NativeChatStructuredSessionDelivery.test.tsx went over the 800-line lint limit after main was merged. The eight tests for the automatic probe of an unconfirmed message move unchanged to NativeChatStructuredSessionDelivery.probe.test.tsx, which uses the shared structured-session test harness for its mocks. The outbox seeding and probe clock helpers move into that harness so both files share them. The at-most-once reliability gate now lists the new file, with a fresh evidence run. |
||
|
|
52b3766f48 |
Clarify keep-awake tooltip behavior by platform (#25323)
* fix: make keep-awake tooltip lid behavior platform-aware Extracted platform-specific lid behavior notes into a reusable function and updated the keep-awake tooltip to show accurate descriptions for each OS: macOS explains that closing the lid may still sleep the device, Windows references device power settings, and Linux clarifies Orca's lid-close request behavior. Updated copy to be device-agnostic instead of Caffeinate/MacBook specific. * fix: clarify macOS keep-awake tooltip copy and add translations Update agent keep-awake descriptions on macOS to accurately explain that the feature prevents idle sleep (not all sleep modes) and only works with the lid open. Add translations for Spanish, French, Japanese, Korean, and Chinese. |
||
|
|
0c761a7610 | Admit short required auxiliary checks after PR preflight (#25317) | ||
|
|
3655bd9fc2 |
fix(terminal): stop old output bleeding into Claude's screen when revisiting a remote tab (#24926)
* fix(terminal): leave the alt screen before replaying a pushed host snapshot A remote terminal running a full-screen agent (Claude Code) could show old output (e.g. a setup script's pnpm log) interleaved with the agent's screen after switching back to the tab. The host's pushed snapshot is a serialized image that starts on the normal buffer and enters the alternate screen itself, but the replay drain cleared with ESC[2J without leaving alt. The image's history painted into the agent's screen, its own ?1049h was a no-op, and the agent's diff paints landed on top of the stale cells. The remote-runtime transport now marks snapshots as serialized images, and the drain grounds them with the shared snapshot prologue (switching to the normal buffer first). Raw byte replays (SSH relay ring buffers) keep the in-place clear. * fix(terminal): paint folded remote snapshots from the normal buffer everywhere Review follow-ups: - Rename the flag to carriesNormalBuffer: what the painters rely on is that the image starts on the normal buffer and enters alt itself. - Hidden-output restore had the same bug for remote requested snapshots (history folded into data, alternateScreen set): the painter entered alt first and painted the normal buffer into the TUI's screen. Requested remote snapshots now carry the flag and take the normal-buffer start. - Flag pushed snapshots replayed after a cancelled shutdown too. - Pushed snapshots carry only the screen, so over a live TUI the drain keeps the normal-buffer history it covers instead of wiping it. - Read the pane's buffer after queued output parses. - Tests compare whole buffers against a fresh terminal, use production image shapes, and pin the raw-replay path with the same oracle. * fix(terminal): let the replay drain own the recovery snapshot clear The recovery prefix's own \x1b[3J ran after the drain's prologue and wiped the history the drain keeps under a live TUI. Keep only the latch release, which still makes an empty recovery snapshot non-empty so it is applied. * fix(terminal): keep the recovery snapshot's own screen clear Consumers that write recovery snapshots straight into xterm (no replay drain) rely on the prefix clearing the stale screen. Restore \x1b[2J\x1b[H and drop only \x1b[3J, which wiped history the image does not carry. * test(terminal): drive the drain with the real recovery payload The multiplexer prepends its own screen clear; replaying that exact payload pins that the prefix cannot wipe the history a TUI covers. * fix(terminal): keep TUI-covered history only when the grids match Second review follow-ups: - A pushed image carries only the host's screen; the pane's frozen history continues it exactly only on the same grid. On another grid keeping it duplicated or dropped lines, so the image replaces it there. - Tests replay the pane's writes and grid changes into a real terminal and compare whole buffers with the host, including a mismatched-grid case. - The split branch shares the normal-buffer preamble; drop the now single-use abort helper. - Type serializeBuffer as RemoteRuntimeSnapshotImage so the flag is carried by type, not by object pass-through. - Register the grid and raw-replay cases in the reliability gate. * fix(terminal): keep TUI-covered history only while the host is still on alt The drain kept the pane's history whenever the pane was on the alt screen. If the host's TUI exited while the tab was hidden, the shell wrote past that history and the kept lines no longer continued the host's screen. Require the host's own alternateScreen too; an absent flag proves nothing, so the image replaces history as on main. Also: one buildSnapshotReplayPreamble for every first replay write, the drain's image and raw clears as separate branches (raw byte-identical to main, comment restored), and a single paneAtSourceGrid check. * fix(terminal): gate kept history on the host's shell-owner proof The host sends alternateScreen only with terminalOwner 'shell', i.e. once it has proven the TUI exited, so `alternateScreen === true` never held for a live TUI and the drain wiped the history it should keep. Replace the history only once the host proves the TUI exited; tests now use production snapshot shapes. Move the relay-overlap comment into the raw-replay branch it describes. * fix(terminal): keep TUI-covered history only on a proven shared grid An image without its grid cannot prove the pane's history continues its screen, so it now replaces history. Also update a stale recovery-prefix test comment. * test(terminal): replay host-serialized snapshots through the real wire and drain Hand-written replay meta hid a gate that production never satisfies. Drive the host's own emulator, ownership mirror, serializer and recovery publisher through the real wire, client parser, remote transport and pane drain, for a live TUI and after the host proves it exited. * fix(terminal): repaint only the alt frame over a live TUI, leaving history alone Keeping the pane's history by clearing only the normal screen assumed a pushed image carries no history, which the host does not guarantee: a 0-row push can reuse a concurrent requested capture, and its history then landed twice in scrollback. It also wiped history on a grid mismatch, where main kept it. When pane and image are both on alt, the image's normal part adds nothing (the normal buffers froze together), so paint only its alt payload after an alt-side clear, split at the host's own boundary (splitAtAlternateScreenEntry, now shared with the daemon). Any other image paints from the normal buffer. This drops keepScrollback, the owner and grid gates, and the recovery-prefix change, so history behaves exactly as on main. * test(terminal): pin the parse wait and the cancelled-shutdown flag Final-review follow-ups: a drain test where the TUI's ?1049h is still queued when the image arrives, and a transport test replaying a push buffered during a cancelled shutdown; each fails when its guard is removed. The requested-image test now names the exited-TUI case it covers, requestSnapshot shares the snapshot image type, and the clear comment no longer implies every clear drops scrollback. |
||
|
|
baa56fd10d |
Simplify the phone-control and phone-size terminal dialogs (#25307)
* Redesign the phone-control and phone-size terminal dialogs Drop the eyebrow label and circled icon, shorten the copy so it no longer restates the buttons, and give each state one primary action with a quieter "all" action. Collapse moves out of the button row into a Minimize icon in the corner. Behavior is unchanged. * Point the phone settings copy at the renamed Restore button; drop dead ko overrides The phone app and desktop update independently, so name only "Restore", which matches both the old and new desktop banner labels. |
||
|
|
fb77c14386 |
fix: update Caffeinate tooltip copy about MacBook lid behavior (#23091)
Update tooltip and settings pane help text to accurately describe Caffeinate's behavior: it prevents idle sleep while active, but MacBook lid closing may still trigger sleep per device power policy. The previous copy incorrectly suggested Orca could prevent lid-close sleep. |
||
|
|
4a41e246db |
Fix: settle sortEpoch in store to prevent React update depth exceeded (#25313)
* fix(sidebar): stop Manual sort from mirroring sortEpoch into state In Manual mode the sort hook copied every sortEpoch bump into state from an effect, adding a nested React update per bump. A burst of store bumps at startup stacked those into 'Maximum update depth exceeded' (React #185). Manual now reads the live epoch directly; debounced modes are unchanged. * feat(sidebar): tell people when a drop switches sort to Manual Reordering by drag still switches the sidebar to Manual so the drop sticks, but it used to happen silently. Show a toast with a 'Back to <previous sort>' action; it retires itself on any later sort change so it can't override a newer choice. Drops while already in Manual stay silent. * feat(store): settle sortEpoch in the store instead of in React state Add settledSortEpoch plus a 3 s settle timer owned by a store listener installed in the state creator. Every write path (slice actions, the web session sync patch) goes through it, so the settled value stays correct with no sidebar mounted. Manual, a sort-mode switch, and a bump that changes the non-archived row count settle in the same notify; other bumps restart the window. A reset that lands settled clears the timer, and the disposer runs on HMR teardown. * fix(sidebar): read the settled sort epoch instead of mirroring it into state The sort hook no longer copies sortEpoch into React state from an effect in any mode; it reads the store's settledSortEpoch directly. That pattern added a nested update per bump and stacked into "Maximum update depth exceeded" (React #185) under flushSync bursts. Tests cover Manual, add/remove, burst reset, no-bump row changes, mode switch, and 80 flushSync bumps in Recent while worktrees are added. * cleaning up * fix(store): settle bumps when rows update during pending window Detect structural changes on worktreesByRepo updates in addition to sort epoch changes. When a row arrives without its own bump during a pending settlement window, the changed composition must still trigger settlement. |
||
|
|
a753affffe |
Isolate code editor text and Undo history by execution host (#25174)
* Isolate code editor text and undo history by execution host * Verify editor owner resolution and Windows model path isolation * Respect native model line endings in content sync history coverage * Preserve selection and scroll when editor ownership resolves * Verify owner synchronization against a reachable editor change callback |
||
|
|
8e8efb1947 | Reduce avoidable work in PR checks and SSH test setup (#25309) | ||
|
|
8ff6ec9fb1 |
Install OpenCode hooks in the terminal's config directory (#25296)
* test: reproduce OpenCode plugin installation in the wrong config root * fix: install OpenCode hooks in the execution config directory * test: isolate config installation from CLI version probing * style: format consumer config installation controls * fix: use checked startup environment and supported relay shell context * fix: install OpenCode hooks using the selected execution shell * test(opencode): assert consumer config root in PTY fixtures --------- Co-authored-by: Codex <codex@openai.com> Co-authored-by: Orca <orca@stably.ai> |
||
|
|
f371532707 | Bound search preview retention and stop canceled remote scans (#25303) | ||
|
|
6c07570040 |
fix(cursor): keep usage cookies on the selected account (#25243)
Keep Cursor quota requests tied to the selected account by omitting ambient Electron session credentials. Preserve explicit account cookies and redirect handling. Credit: Li-Sanze for the original credential-mode fix in #23626, carried through #24575; jjongsta and chengjiaxiao for the reports. Native HTTP/HTTPS cookie isolation, mutation controls and proxy behavior were verified before merging. This does not claim to resolve the separate initial-authentication failure in #23612. |
||
|
|
ca774091d7 |
fix(agents): recognize Pi bundled npm entrypoint
Carry the focused patch from boris-papevis/orca PR #25040 onto current main, with independent npm runtime and regression verification. |
||
|
|
b1e12d7bb4 |
fix(native-chat): a new structured chat's model list comes from the machine that runs it (#25143)
* fix(native-chat): a new structured chat's model list comes from the host that runs it agentSession.modelCatalog builds the structured-session host like agentSession.options, so a host with no saved chats since it started answers instead of refusing. When the host answers unknown because its first listing runs in the background, the picker re-reads on a bounded schedule until that listing lands. Local terminal-backed chat skips the structured catalog when a custom launch command is configured. * fix(native-chat): wait on the host's first model listing instead of re-reading on a timer A new structured chat's picker read the host catalog once; on an account the host had never listed, the answer was "unknown" while a background listing ran, and the client re-read on a 1-30 s schedule. Replace the schedule with the host's own completion signal: - The host answers a cold read with `listingInProgress: true` (new optional field) once it has started or joined that listing. A read that passes the new optional `waitForListing` param awaits the same joined listing and answers with it, or a plain "unknown" if it failed. The at-rest options read never waits. A host that predates the field never sends it, so the client never sends the param to a host that would refuse it. - The picker reads once per open and attach; after the host's report it sends one waiting read, with a 90 s client timeout above the slowest listing. While that read is out, the model pill keeps its label but cannot open or be set (typed /model included). An answer, failure, timeout, hide, attach or the provider's own list releases it. - `agentSession.modelCatalog` builds the structured-session host only for a read that names a session (a structured chat). Terminal-backed chat's session-less read keeps the non-building gate, so a desktop that never runs structured chat never opens the session journal. * fix(native-chat): one waiting model-list read per chat, and no late menu open The waiting catalog read was owned by one run of the picker's effect. Attach (a new fence), hide/show or a send re-ran the effect: the cleanup released the model picker onto the built-in list for a round trip, and the new run sent a second waiting read while the first, which cannot be withdrawn, kept a remote call slot until the listing ended. The waiting read now belongs to the chat (runtime target + agent + session): a small registry keeps one in flight per chat, every re-run or remount joins it, and the entry is deleted when the read settles. The picker hold is derived from that entry being in flight, so it lasts across attach and hide/show and ends when the read settles, the provider reports its own list, or the pane switches to another session. Answers still pass the stale and record checks. A bare /model typed while the list loads no longer opens the model menu by itself when the list lands: the menu stays keyed on the request, and only its initial open is suppressed while pending, so the request is spent shut and the end of the pending period never remounts it. * fix(native-chat): release the model picker in the same commit as the host list When the waiting catalog read settled in the chat that started it, the registry dropped its entry and told subscribers first, and the host list was applied a few microtasks later. React committed once with the picker enabled on the built-in list, then again with the host's list. Joiners now hand the registry their apply callback, and the registry runs every joiner (with the answer, or nothing when the read failed or timed out) before it deletes the entry and notifies. The release and the list land in one commit. An effect cleanup leaves the wait instead of flagging itself stale. * fix(runtime): queue model catalog reads in the long-wait lane A model catalog read that waits on a host's first listing replies only when that listing ends, yet it took one of the 8 foreground call slots for its server. Enough chats opened during one cold listing would stall that server's sends and interrupts until a wait settled. agentSession.modelCatalog now joins worktree.rm in the long-wait lane: same concurrency, counted apart from the foreground calls. The queue classifies by method only, and a warm catalog read answers at once, so the whole method moves. |
||
|
|
0971479866 |
Add shared workspace settings note and prevent filter modal expansion (#25300)
* fix(mobile): say that workspace sort, grouping, and filters are shared The Manual sort option was subtitled 'Server order', but it orders by the desktop's drag ranks. Sort, grouping, and filters on the phone all write the host's shared view settings, so changing them also changes every other device on that host, which the screen never said. Relabel Manual as 'Desktop drag order' and add 'Shared with other devices on this host' under the Sort By, Group By, and Filter titles. The note avoids naming a desktop sidebar because headless hosts have none. * fix(mobile): prevent filter modal heading expansion Add flexShrink: 1 to allow the heading container to shrink when space is constrained. Update comment to clarify why workspace view is shared across devices. * update wording |
||
|
|
e42768fb23 | Update in-app Android APK links to mobile 0.0.52 (#25168) | ||
|
|
f0b5b8566c |
Bound OpenCode history reads and repeated worker failures (#25292)
* fix(opencode): keep scan budgets across queue waits and batches Reuse the scan-owned lifetime proposed in #10708 by @AmethystLiang with the existing shared worker queue. * test(opencode): check nonempty session fixtures and lint scoped controls * Derive OpenCode scan deadline message from its budget --------- Co-authored-by: Neil Parker <nwparker@MacBook-Pro-3.localdomain> Co-authored-by: OpenCode issue campaign <codex@localhost> |
||
|
|
97fa6aee74 |
fix(native-chat): show a message Orca accepted and then failed to deliver as "Not sent" in the chat (#24710)
* fix(native-chat): keep a message the host accepted then rejected in the desktop chat as not sent Draw it in place from the host's history, so a crash that loses the outbox no longer makes it vanish. A later copy of the same body supersedes it; the outbox row wins while it holds the message; the phone is unchanged. * test(native-chat): pin the same-id rule apart from the body match * test(native-chat): type the rejected-in-place fixture body as a text block * fix(native-chat): let the host's row own a message it recorded and then rejected Once the host's journal records a send as rejected, the desktop outbox lets it go, as it already does for delivered and Stop-withdrawn sends: the host's row shows it as not sent, with the host's reason and no Retry. The outbox keeps only sends the host refused before recording them, which keep their Retry. A send whose own reply says it was rejected is drawn by its outbox entry, with no Retry, until the journal carries the row; a copy left by an earlier session is dropped when the chat opens. - the transcript no longer hides a host row behind an outbox entry with the same id or the same text; those rules and their cache are gone - a rejected message the queue holds (a draft's hand-off, or a live card under its id) is drawn as its card, not as a row - a later copy of the same text hides a rejected row only when it was sent once the rejection was known, so a deliberate repeat stays - delivery notices read the same visibility rule as the transcript; a chat whose only rejection a Stop withdrew no longer rebuilds them per batch - the body fingerprint helper goes back to the host, its only user * test(native-chat): keep one row when copies of a rejected message share an instant * refactor(native-chat): let the host's notice replace the outbox's under the same id * test(native-chat): pass the queued card ids in the tool-stream cost transcript * fix(native-chat): keep the host's record as what lets a rejected message go - the outbox no longer drops a host-rejected message when a chat opens; the reconcile lets it go once the journal's submissions say it was rejected, and that drop is written to storage, so nothing reads as still owed - a message the host rejected while the chat watched waits for its journal row with no Retry; one read back from storage with no row loaded keeps its Retry under a new id, since the host may have lost it - the delivery notices keep the same map and notice objects across a batch that words every row the same, so a submission batch re-renders no row - a rejected command such as /compact stays hidden: its own reply reports it - the desktop transcript requires the queued card ids, with a controller-level test that a card holding a rejected message keeps its row hidden * fix(native-chat): draw a queued message where the host rejected it A message accepted to hand over later and rejected before any handover now sits at its rejection, as a handover places one: what the agent did while it waited happened before it, and the newest history page holds it. One handed over, or dispatched as it was recorded, keeps its place. An older host does not move it, so it stays at its submission, still drawn. A failed start now rejects the queued messages and writes its row in ONE journal append, the messages first: no reader ever meets one without the other, and the messages still draw above the row that says why. * test(native-chat): pin that rows written together roll back together * fix(native-chat): draw every rejected message where it was rejected Not only a queued message: one handed over into a turn and then rejected, or sent directly and rejected, also sits at its rejection, in no turn. A message in doubt stays where it was, a plain bubble: it may have reached the agent. * fix(native-chat): decide a rejected message's Retry from the host's stored fact - a message the host recorded and then rejected has no Retry on any mount, however that mount learned of it, and a Dismiss that clears it from storage; a send refused before the host recorded it keeps its Retry - the rule that keeps a rejected command such as /compact out of the transcript moves into the one visibility function rows and notices share - the outbox state docs say what lets a recorded message go: the client holding its rejected submission, whose row the host places at the rejection * fix(native-chat): write no start-failure row when a Stop withdrew every queued message first * test(native-chat): pass the Dismiss action in the delivery-notice hook tests * fix(native-chat): keep a rejected message's outbox copy until its row loads An older host leaves a rejected message where it was sent, which may be older than the loaded window: the chat then holds the rejected submission but not the row that draws it. The outbox copy now stays until that row loads, marked as the host recorded it (Dismiss, no Retry, in the host's words), and leaves once the page holding the row is loaded. Derived from the loaded rows each time. Tests that label their projection as the phone's now pass the phone's own setting. * test(native-chat): type the outbox hook props that carry loaded rows * fix(native-chat): write nothing when a journal batch settles nothing in the outbox The outbox re-reads the journal on every batch since it waits for a rejected message's row to load. Its reconcile now returns each unchanged entry, and the list, as themselves (a message left in doubt included), so a batch that changes nothing writes nothing to storage. The reconcile moves to its own module. A copy the host recorded and rejected owes no delivery, so it no longer keeps a hidden pane reading the journal. * test(native-chat): count storage writes on the outbox's own storage object * fix(native-chat): let a recorded rejected message's outbox copy leave on its own, with no Dismiss The outbox copy of a message the host recorded and then rejected draws it only while the host's row is not loaded, and leaves on the batch or page that loads that row. It owes no delivery and offers no control: sending it again is a new message. The Dismiss that let the user clear it is gone, from the outbox, the notices and the session controller. |
||
|
|
ab41610ba6 | Fix reordering workspaces with collapsed children (#25302) | ||
|
|
b99d28e32f |
A resent chat message gets its recorded answer, never an early refusal or a made-up record (#25158)
* fix(native-chat): a resent send id gets its recorded answer, never an early refusal or a made-up record The host now looks a resent send id up before preparing the session. A row that settled refused answers with its refusal before the chat is opened. A resend whose chat cannot be opened or made ready answers unknown instead of a refusal. A /clear in flight refuses only ids the ledger does not hold. A send row now records the journal epoch it was admitted into. An unsettled row with nothing written in that same epoch runs for the first time; under a later epoch the host answers unknown instead of reconstructing a submission it never had. The host advertises agent-session.send-answers-proof.v1. * test(native-chat): pass the ledger row to the thread-goal rerun check * fix(native-chat): a send's answer commits with its write, and a resend is answered before any write A send (and /compact) settles its ledger row `succeeded` in the same SQLite transaction as the submission or queued draft that accepts it, so a row still `pending` proves nothing was written and a resend runs it for the first time. The unknown-before-run mark and the per-row journal epoch go. A resent id is answered from its row and the journal before preparation starts an agent and before any write transaction: a recorded refusal with nothing opened; otherwise the conversation is opened (no agent start for a send) and replayed, and a conversation that will not open answers unknown. * fix(native-chat): a ledger refusal is answered first, and a /clear refuses only a send's first run An id the ledger refuses (expired, conflict, invalid, capacity) is answered as admission would, with no journal read, preparation or write, so a closed chat or a read-only store answers it too. A re-read after the replay open that comes back refused returns that refusal. Whether a /clear is in flight is read when a send arrives and applied in the send's preparation for a first run only: an id the ledger holds by the send's turn, including one whose earlier attempt was queued ahead of the clear, is answered from its record. MutationPlan makes settlesWithWrite and settledOutcome exclusive; the capability text no longer promises a refused id never sends. * docs(native-chat): say what a replay's preparation does for every plan |
||
|
|
ddefd523e0 |
Keep selected text navigation from rewriting document links (#25175)
* Keep selected text navigation from rewriting document links * Check model selection before document link arrow coverage |
||
|
|
cbe64383dc |
Reuse source-line calculations for Markdown review selections (#25173)
* Reuse source-line calculations for Markdown review selections * Use typed editor probes in review selection performance coverage |
||
|
|
b32462f246 |
Replace patched JSON parser with stream-json (#25202)
* Replace patched JSON parser with stream-json * Isolate dependencies for historical server compatibility builds |
||
|
|
41cc77509f | Keep active notebook cells current after external reloads (#25172) | ||
|
|
a5b8b7e2bb | Delete docs/reference/jcode-hook-events.md (#25288) | ||
|
|
95753a10c6 | fix(jcode): report missing and outdated managed hooks (#25135) | ||
|
|
0f9bc5aaad |
fix(codex): keep Orca-only MCP servers when refreshing the retained shared home (#24983)
* fix(codex): keep Orca-only MCP servers when refreshing the retained shared home The refresh for panes that outlive an update treated the old shared home's whole MCP root as owned by ~/.codex, so it deleted servers the user had added from an Orca terminal, which existed only there. Read the home's settings baseline instead, as the normal mirror does: drop only servers the last mirror copied from ~/.codex. No baseline keeps the old behaviour; an unreadable one skips the refresh. The baseline is not advanced, keeping the refresh one-way. STA-9109 * test(codex): type the MCP ownership baseline fixture --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
8d87d2cf67 |
feat(codex): tell Windows users once that Codex in Orca now shares ~/.codex (#24916)
* feat(codex): tell Windows users once what stays behind when Codex moves onto ~/.codex When Windows' system-default Codex first runs on ~/.codex (launch prep or the usage poll), main decides once whether Orca's managed home was ever used and which MCP servers lived only there, and persists that in UI state. The renderer shows one dismissible toast when a Codex terminal exists, after the server-isolation notice rather than on top of it, and clears the notice when shown. The "kept only in the managed home" MCP rule is extracted into isRuntimeOnlyMcpServer, which the config mirror merge now uses too, so the notice names exactly the servers the mirror would have kept. * fix(codex): stop counting Orca's own config.toml as use of the old Codex home Orca's hook install writes that home's config.toml on every startup, so its presence was true for nearly every Windows user with Codex. The home now counts as used only with recorded sessions or an MCP server of its own. Resolver tests keep one case per input source. * refactor(codex): ask main for the shared-settings notice instead of persisting it The persisted missing/object/null field, written from launch prep and the usage poll, becomes a plain codexSharedSettingsNoticeSeen flag mirroring codexTerminalServerIsolationNoticeSeen. When a Codex terminal first appears and the flag is unset, the renderer asks codexConfigSync:sharedSettingsNotice once; main answers read-only (Windows, system default on ~/.codex, managed home path without mkdir) and maps any read error to null. Runtime-home routing, launch and the test harness return to main's code. The notice no longer waits for the server-isolation toast; they may stack. The Codex-terminal watch moves to codex-terminal-presence.ts. * refactor(codex): watch for the first Codex terminal in one place for both notices The server-isolation notice now passes its due check to whenCodexTerminalAppears instead of keeping its own copy of the presence scan, input filter and subscription loop. Its behaviour and tests are unchanged. * docs(codex): trim isRuntimeOnlyMcpServer's comment to why it is shared * refactor(codex): keep McpServerTomlOwnership private to its module * test(codex): cover the shared-settings notice channel without type assertions Handlers are looked up by channel now that two are registered, so the status tests no longer depend on registration order. * refactor(codex): show the Windows shared-settings notice without asking main Every way of detecting who relied on Orca's old Codex folder had false positives, so the renderer now shows one static toast on Windows the first time a Codex terminal exists. This drops the main-process resolver, its IPC channel, preload line, web stub and shared type, and the MCP-names variant of the description. * refactor(codex): restore the MCP server ownership helpers to main's shape The static notice no longer reads MCP servers, so the shared isRuntimeOnlyMcpServer extraction has no second caller. * refactor(codex): let each notice decide when it is due, so the Codex watcher only watches The isolation notice now selects its due predicate and starts the watcher only while due, so whenCodexTerminalAppears no longer takes an isDue or re-checks hydration and settings. The shared-settings notice uses isLocalWindowsDesktopClient, its test stubs the user agent instead of mocking pane-helpers, and the hydration safeguard it relies on is now tested on the UI slice itself. * test(codex): drive the Codex notices through a reactive store, and drop a redundant hydration gate The server-isolation notice now reads "is it due" through a store selector, but its test mocked the store without re-rendering, so a due change after mount (persisted UI loading, the setting turning off) was never exercised. The notice tests now share one harness backed by a real zustand store, the shared watcher gets its own test, and both notices cover the seen flag loading after mount. persistedUIReady is dropped from isNoticeDue: the seen flag defaults to true and only hydration clears it, in the same update that sets persistedUIReady. Both notices now gate the same way. * fix(codex): keep the shared-settings toast until dismissed, and shorten it It is marked seen before it shows, so a 15s auto-close could lose it for good while the user is typing in the Codex terminal that triggered it. Every other one-shot notice that marks itself seen on show stays until dismissed; this now does too. The text drops the sentence that repeated the title and keeps only what to expect and do. --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
ea6a6d6077 |
Pass wrapped OpenCode run prompts as positional messages (#25001)
* fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): unsubscribe hook settings during async host shutdown * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * test(readiness): census recorded OpenCode composer boots * fix(opencode): reject redirected overlay parents before cleanup * fix(orcad): retain runtime cleanup when subscribing to hook settings * refactor(launch): extract OpenCode config and attachment authority * fix(opencode): retain host version selection across relay restarts * fix(opencode): pass run prompts as positional messages Preserve run flags and use the existing shell quoting and run-command detector to append the initial message after --, reusing an existing separator. TUI launches retain their version-selected prompt transport and draft behavior. Original run-order work: @coelho-doti (#13065, tracked in #17551). * fix(opencode): keep wrapped run tasks positional Recognize supported environment prefixes and PowerShell call operators without mistaking prompt arguments for executables. Keep environment and run separators separate, preserve the task text and exclude run commands from native submission. Source-parent: |
||
|
|
d77c57022e |
Verify shared preflight selection and record full unit timings (#25239)
* Strengthen shared preflight contracts and record unit timing results * Record rejected shard-weight holdouts |
||
|
|
53899251db |
Preserve Windows SSH upload failures unless pwsh is missing (#25185)
* test(ssh): reproduce missing-pwsh text in staging paths * fix(ssh): classify missing PowerShell from command exit evidence * test: expose generic Windows upload error misclassification * test: await armed SSH upload before advancing fake clock * test: retain real immediate delivery around upload timeout control * fix: classify PowerShell absence from command exits only * test: expose missing-command text inside SSH stderr paths * fix: require missing pwsh diagnostic command identity * test: keep mixed write errors out of missing-command fallback * fix: require complete missing PowerShell diagnostic * test: capture complete native missing pwsh diagnostics * fix: recognize complete missing pwsh native diagnostics * test(ssh): cover source-derived NormalView localization and wrapping * fix(ssh): identify complete missing-pwsh records across NormalView layouts * test(ssh): cover raw-wrap separators and repeated error headers * fix(ssh): preserve wrapped separators and reject repeated error headers --------- Co-authored-by: Orca Campaign <campaign@localhost> |
||
|
|
70cf91299b |
Clean up retired OpenCode configuration copies safely (#25222)
* fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): unsubscribe hook settings during async host shutdown * STRICT launch CI contract correction * CAPS launch CI contract correction * INTENT launch CI contract correction * test: initialize Claude prompt state in output retention fixture * Wait for OpenCode location hydration in intent startup * Bind OpenCode startup readiness to the current location in intent startup * Collect retired source-scoped OpenCode configuration overlays conservatively Credit brennanb2025 for the original bounded, delayed overlay garbage-collection contribution in PR #7627. Preserve ambiguous legacy and shared-service state. * Correct inaccessible-source fixture without spying on native ESM exports * Keep delayed OpenCode cleanup within existing file limits * Reuse the overlay manifest module for existing owned-entry operations * Use the existing filesystem import in the ownership mock * test(opencode): keep overlay GC link tests portable --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> Co-authored-by: Adnan Khan <adnank11427@gmail.com> Co-authored-by: Orca startup hydration review <agents@stably.ai> Co-authored-by: OpenCode Campaign <opencode-campaign@users.noreply.github.com> |
||
|
|
87bc51d371 | Reduce test deadline waits and exact byte comparison costs (#25187) | ||
|
|
8c617301f7 |
fix(opencode): keep overlay manifest cleanup inside owned directories (#24763)
* fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): confine overlay manifest cleanup to owned directories Co-authored-by: Adnan Khan <adnank11427@gmail.com> * fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): unsubscribe hook settings during async host shutdown * STRICT launch CI contract correction * CAPS launch CI contract correction * INTENT launch CI contract correction * test: initialize Claude prompt state in output retention fixture * Wait for OpenCode location hydration in intent startup * Bind OpenCode startup readiness to the current location in intent startup --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> Co-authored-by: Adnan Khan <adnank11427@gmail.com> Co-authored-by: Orca startup hydration review <agents@stably.ai> |
||
|
|
d9173ffbdb |
Keep Orca CLI first after shell startup (#25130)
* Restore the owning Orca CLI path after shell profiles * Use a literal marker for the Bash lookup regression * Preserve plain panes and initialize zsh after prompt hook replacement * Preserve user line-editor dispatchers during deferred startup * fix: retain CLI startup when global Zsh replaces prompt hooks * test: replay global Zsh hook replacement after host startup * test: isolate controlled Zsh widgets from distro keyboard setup * fix(shell): preserve user hooks during deferred zsh initialization * Keep completed Zsh startup hooks retired when the wrapper is sourced again --------- Co-authored-by: Codex <codex@openai.com> Co-authored-by: Orca maintenance <orca-maintenance@users.noreply.github.com> Co-authored-by: Orca campaign <orca-campaign@local.invalid> |
||
|
|
c4e8735f45 |
Share PR preflight setup to reduce runner demand (#25150)
* Share PR static analysis and compiler runner * Preserve evidence document final newline for concurrent merges * Keep readiness reuse contracts aligned with the physical preflight gate |
||
|
|
b407d06c1e | Reuse buffer cells during terminal cursor context scans (#25161) | ||
|
|
f62bd7dc20 |
feat(csv-viewer): detect semicolon-separated CSVs (#19894)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Neil <neil@stably.ai> |
||
|
|
e8310d5a4f |
fix(opencode): submit admitted native startup briefs without overwriting input (#24762)
* fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): unsubscribe hook settings during async host shutdown * STRICT launch CI contract correction * CAPS launch CI contract correction * INTENT launch CI contract correction * test: initialize Claude prompt state in output retention fixture * Wait for OpenCode location hydration in intent startup * Bind OpenCode startup readiness to the current location in intent startup * Retry interrupted OpenCode startup prompt claims --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> Co-authored-by: Orca startup hydration review <agents@stably.ai> Co-authored-by: Orca <dev@stably.ai> |
||
|
|
58bd15fa3f |
Fix ripgrep result completeness, filename handling, and search errors (#25156)
* Preserve ripgrep search results, filename identity, and failure diagnostics * Fix adversarial Unicode and Explorer filename findings * Register search failure localization fallback * Preserve host filename identity through document and watcher consumers |