mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
c8996d76a58c70072046027288046722cbb072ab
10813
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c8996d76a5 |
Speed up daemon smoke checks and keep compiler slots busy (#28106)
* Remove repeated daemon smoke builds and idle compiler slots * Test compiler scheduling through its process interface * Keep preview component below the existing line limit with a type-only split |
||
|
|
5e83ca0edd |
fix(lint): move the doc preview guest-focus handoff into its own hook (#28110)
HtmlDocPreview.tsx reached 403 lines on main (#27608 + #27875), over the 400-line limit for .tsx, so lint and the pre-commit hook fail on any branch that merges main. The focus handoff effect moves unchanged into use-doc-preview-guest-focus.ts. Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
1104402f5e |
fix(browser): annotation card and outline follow the picked element (#27875)
* fix(browser): annotation card and outline follow the selected element The grab overlay keeps re-measuring the picked element after the click (scroll in any box, resize, element size changes), and the isolated viewport bridge reports that live box so the pending card follows it, including page zoom. The card's side pick uses its measured height. * fix(browser): bind annotation card to selected element * fix(browser): keep document annotation card on selection * fix(ci): point the main sync-spawn ratchet at the shared ratchet library (#28054) #27756's script imported baseline helpers from check-focus-read-ratchet.mjs after #27788 had moved them into ratchet-baseline.mjs, so it crashed on start and failed every PR that merges main. Use the library's helpers, and record the two daemon-process launches from #27769 that the broken check never saw. Co-authored-by: Orca Worker <orca-worker@localhost> * fix(browser): follow selected element outer-box size * refactor(chat): give the start-refusal resumable table its own module (#28085) #27946 and #26684 together put agent-session-failure-words.ts at 304 lines, over max-lines, which fails lint and the pre-commit hook on every merge of main. The refusal-code table is standalone with one reader, so it moves out. Co-authored-by: Orca Worker <orca-worker@localhost> --------- Co-authored-by: OrcaWin <alpha-eng@stably.ai> Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
7154e9045f |
fix(terminal): keep the tab when a reattach finds its process gone (#28067)
* fix(terminal): keep the tab when a reattach finds its process gone Co-Authored-By: Claude <noreply@anthropic.com> * test(e2e): read the paired retention heap after two collections Co-Authored-By: Claude <noreply@anthropic.com> * fix(terminal): clear the absent owner through the replaced-pane binding writer Co-Authored-By: Claude <noreply@anthropic.com> * test(e2e): fail the paired retention check when the heap cannot be read Co-Authored-By: Claude <noreply@anthropic.com> * fix(terminal): refuse the respawn without a Store; tighten the binding fixture and stop docs Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
acb6299191 | docs(native-chat): say why /clear is refused while the agent works instead of queued (#28101) | ||
|
|
7909732283 |
perf(claude): run the Windows Claude hook as a signed native claude-hook.exe (#27719)
* perf(claude): run the Windows Claude hook as a native orca-hook.exe
Each Claude hook event on Windows started cmd.exe (plus the user's cmd
AutoRun) and then curl.exe on top of the agent's own shell. A small signed
Rust binary now does the same synchronous POST in one process, under Git
Bash, PowerShell and direct CreateProcess alike.
- native/windows-agent-hook: std-only crate, same contract as the .cmd hook
(prints {}, env guards before stdin, endpoint re-read, 0.5s/1.5s caps,
waits for the listener reply, always exit 0). Its installed file name
selects the agent profile, so the registration stays a bare path.
- Packaged as resources/bin/orca-hook.exe (SignPath signs it with the other
inner PEs); afterPack fails on a missing or wrong-machine binary.
- Claude install copies it verbatim to ~/.orca/agent-hooks/claude-hook.exe
(temp + rename, running copy moved aside) and registers it; it falls back
to the .cmd hook when the bundle is missing, unsigned or cannot be copied.
Only Claude opts in, via windowsNativeHookExecutable.
- The managed-command matcher sweeps .exe entries alongside .cmd/.ps1/.sh.
- The CLI launcher and hook builds share windows-rust-executable-build.mjs,
which now also checks the PE machine.
Refs #20913
* fix(build): publish native Windows binaries atomically so parallel builds cannot collide
The Windows CI lane runs every orca-hook.exe suite in one vitest
invocation, each building through build-windows-agent-hook.mjs. The build
copied straight onto native/windows-agent-hook/.build/orca-hook.exe, and
CopyFile opens its destination unshared, so a second build (or a scanner
still holding the fresh image) failed with EBUSY.
- windows-rust-executable-build.mjs skips the publish when the output
already has the built bytes, otherwise stages a per-process temp file and
renames it over the output, retrying briefly while another handle holds it.
- The test fixture hands each suite a private copy of the build output, so
no suite reads or starts the shared file while another build replaces it.
Refs #20913
* refactor(claude): simplify the native Windows hook to one Claude binary
Review follow-up on the native hook (#20913): the same behaviour with less
machinery.
- The binary is built, shipped and installed as claude-hook.exe, so the
installed name matches its PE OriginalFilename. It is Claude-only, so the
file-name profile table and the per-agent opt-in flag are gone; the
registration is gated by the existing Claude-only usesWindowsEntry check.
- Install and refresh reuse writeManagedScript / refreshManagedScriptIfPresent
(now accepting bytes): temp file, rename, skip when identical. A copy whose
hook is still running cannot be replaced; install then registers the .cmd
hook and refresh keeps the old build until a later start, instead of the
rename-aside and *.retired sweep.
- The install-time Authenticode-presence check is dropped. Release CI now
requires resources\bin\claude-hook.exe to be signed (release-cut and the
signing rehearsal), next to resources\bin\orca.exe.
- getStatus counts either Windows form through findManagedEventHookForms in
hook-settings.ts, replacing managed-event-hook-status.ts.
- Rust: plain Claude constants, one endpoint-file lookup (last assignment
wins, as under `call`), one request write and a deadline-bounded drain.
Guard order and form encoding are unchanged.
- Build: PR CI builds the hook once before the Windows tests, so the suites
only read it; the launcher publish goes back to copyFileSync and the retry
loop and its test are gone. The PE-machine check lives only in afterPack.
Cargo.lock joins both crates' build fingerprints, and the launcher's alias
exports are removed.
Refs #20913
* test(ci): run the managed hook stdin-lifecycle suite in the Windows lane
Its claude-hook.exe case (and the other Windows-only cases) are gated per
test, so the lane-registration guard did not require the file and it ran
only on Linux, where those cases skip. Register it in both Windows lists.
Refs #20913
* feat(agent-hooks): ship the native hook as orca-agent-hook.exe <agent>
The native Windows hook (#20913) becomes one general binary that stays
Claude-only in behaviour.
- Named orca-agent-hook.exe everywhere: build output, PE OriginalFilename
and InternalName, resources\bin, the afterPack check, the installed copy
in ~/.orca/agent-hooks, and the release signed-target lists.
- It takes the agent as its first argument and Claude registers
`<path> claude`. The CLAUDE_JOB_DIR exit and the Grok/Devin drain belong
to that agent; an unknown or missing agent answers {} without reading
stdin. The managed-command matcher owns `orca-agent-hook.exe claude` and
still owns the old claude-hook.exe entry, so installs migrate; install
deletes a leftover claude-hook.exe when nothing runs it.
- A copy still running from the previous build no longer forces the .cmd
fallback. Identical bytes are not rewritten; otherwise the temp file is
renamed over the target, and when Windows refuses because the image is
mapped, the running copy is renamed to orca-agent-hook.exe.old first.
Install deletes a stale .old; only when that copy is also still running
does the install fall back to .cmd. writeManagedScript and
refreshManagedScriptIfPresent take the aside path, sharing one helper.
Refs #20913
* fix(agent-hooks): roll back a failed aside rename and keep an installed hook exe
Design-review follow-up on the native hook (#20913).
- If the running copy was moved to orca-agent-hook.exe.old but the new
file then could not take its name, the copy is renamed back before the
error is rethrown, so settings.json never points at a missing exe. The
rename helper now owns the `.old` name, next to the comment that
explains it; a mocked-fs unit test covers both the sync and async paths.
- A failed write, or a build with no bundled exe, keeps registering a copy
that is already installed (every build knows `claude`), so a dev checkout
and an installed build no longer flip settings.json between forms.
- The claude-hook.exe migration is gone: no release ever shipped that
name, so the legacy sweep, the `.exe` matcher needle and their test are
removed.
Refs #20913
* fix(agent-hooks): derive the native hook's agent with win32 path rules
getWindowsNativeHookAgent took the host's basename of the managed script
path, so on a POSIX host (Linux CI) a Windows path was not split and the
registered command became `orca-agent-hook.exe C:\...\claude`. It now takes
the path and applies path.win32.basename itself. The install destination
and the `.old` aside stay on host paths: they name files the host opens.
Refs #20913
---------
Co-authored-by: Orca Worker <orca-worker@localhost>
|
||
|
|
a1f8e6482b |
fix(layout): save terminal rows in the tab groups' order (#28066)
* fix(layout): save terminal rows in the tab groups' order Co-Authored-By: Claude <noreply@anthropic.com> * test(e2e): read the paired retention heap after two collections Co-Authored-By: Claude <noreply@anthropic.com> * test(e2e): fail the paired retention check when the heap cannot be read Co-Authored-By: Claude <noreply@anthropic.com> * fix(layout): name the headless flow behind the row-id group fallback Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
125007b680 |
chore: upgrade terminal dependencies to matching payload betas (#27935)
* chore: upgrade terminal dependencies to the matching payload betas * test: harden xterm payload contract, align mobile pins, fix serialize-at-ref across version bumps - Cover foreign-payload replacement and the shared blank-cell reset in the installed image payload contract (both mutants previously survived). - Bump mobile's xterm, webgl and unicode11 pins to the root's betas. - Resolve the ref's own serialize version and patch so the differential fuzz baseline builds across a version bump. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2233fd3669 |
feat(native-chat): each Claude/Codex chat gets its own permission mode (#26116)
Each native Claude and Codex chat now has its own permission mode (Ask for approval, Accept edits for Claude, Approve for me, Full access), shown and changed from a button right after "+" in the composer. A change takes effect before the next message: the agent restarts quietly and resumes the same conversation, never interrupting a reply or background work. New chats start from Settings → Chat → Permissions, which is seeded once from Agent Permissions. The mode is stored as an ordinary chat option, and the restart reuses the existing "replace the agent before the next message" step. |
||
|
|
f89d51ba02 |
Share any HTML file from the editor and the remote preview (#27608)
* Share any HTML file from the editor and the remote preview HTML could only be shared as an artifact from a local file:// browser tab. The editor offered Share only for Markdown, and the document preview that renders HTML on SSH and paired hosts had no Share at all. The editor now shares HTML files too, and the document preview's toolbar gets the same Share button, reading the page from its owning host. Both use one source key per file per host, so either surface finds the link the other published. Co-Authored-By: Claude <noreply@anthropic.com> * Share every file under one key per host, and preview Share from its grant's host The editor, the rendered preview and a local browser tab each built their own share key, so one file could publish to several links: a Windows path spelled C:/ in one place and C:\ in another, and the preview keyed from whichever host the workspace resolved to at render time, not the host it was reading from. One key function now serves every surface, with main's formats (local path, the CLI's SSH key, ['editor', env, host, path] with the 'remote' fallback) and Windows drive/UNC paths spelled with backslashes. The preview's grant handle keeps the location it was minted for. Share reads the page through that location and keys from it, so a later host change can't move either; an SSH grant keeps its connection id, so its read fails closed instead of reading a local file. Publishing prepares the request once per click, before sign-in and the auth retry, so a retry publishes what the user clicked Share on. Co-Authored-By: Claude <noreply@anthropic.com> * Pin preview Share key parity with the editor for server-proxied SSH workspaces A preview of an SSH workspace a paired server proxies mints its grant on that SSH target, so it already keys the file the same way the editor does; the new test locks that in. Also corrects the SSH read comment: the connection id is kept because dropping it would read the path on this machine. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
d8a89f169b |
fix(sidebar): stop the workspace link icon lighting up on hover (#28078)
* fix(sidebar): stop workspace metadata icons brightening on hover The link, notes and provenance icons on a sidebar workspace row only open the details hover card; clicking them does nothing extra. The hover colour made the link icon look clickable. * chore: remove unrelated lockfile changes |
||
|
|
6440d3c520 |
fix(mobile): keep a not-sent message in place on the phone, using the desktop's logic (#27936)
* fix(native-chat): list not-sent rows at their journal places The shared projection appended rows the host recorded but never delivered after every other row, leaving the reader to sort them. A reader that draws the list as given showed an old not-sent message under newer turns. Merge them in at their journal places, after the stop rows are built, so the list is already in order. The desktop sorts by the same order, so what it draws is unchanged. * refactor(native-chat): move the recorded-rejection line into shared words The desktop's words for a message the host recorded and then rejected now live beside the other rejection words, returning notice parts each client renders its own way, so the phone can say the same thing. The desktop calls it with the same inputs; its words are unchanged. * refactor(native-chat): one projection behaviour for rejected rows Every reader now draws a message the host recorded and then rejected where it was sent, marked not sent, so the rejectedInPlace option goes. The phone was its last off caller apart from the host's conversation outline, which now leaves not-sent rows out itself; a test proves the outline is the same as if the rejected message had never been sent. * fix(mobile): show a not-sent message in place with the reason under it The phone now draws a message the host recorded and then rejected where it was sent, as the desktop does, with one small line under the bubble in the desktop's words. The line is built from the journal the view already receives; when a start-failure or sign-in row already gives the reason, it says only that the message was not sent. The load-earlier header moves to its own file to keep the view under its line limit. * fix(mobile): a send the host recorded is never handed back When the send's own reply said the host recorded the message and then rejected it, the phone put the text back in the composer with a banner, though the host and the desktop keep it in the chat. A recorded send now settles like any other: its row draws it in place as not sent (or its kept card holds it), and the composer stays empty. The banner's failure-fact plumbing, fed only by that branch, goes with it; the transcript states the sign-in guidance once. * fix(mobile): keep each structured send on the shared optimistic list Once a not-sent row stays in the chat, matching a pending bubble by its text breaks: resending the same words after a not-sent message never reached the count the bubble waited for, so a stray copy stayed, and an acknowledgement lost on that resend showed a false "Delivery unconfirmed". A structured send is now one record, kept by the structured session under the id it is sent with. Three parts match the desktop's sender: the id, the drawing (the shared projection draws it at the tail until the host's row under that id lands, in the same pass) and the settle rule (the host's own record of it, a submission, a card, or a card's hand-off, drops it by the one rule the desktop now shares). The rest stays the phone's own: the bubble shows once the host accepts the send, not from the tap; a send whose answer was lost is held undrawn and says "Delivery unconfirmed" only if its deadline passes first, instead of going back to the composer; records are kept whether or not a chat view is open; and one send in flight is the composer's rule, not the sender's. Its photo is kept under the row id it shares with the host's row, so it shows on the bubble, the landed row and a not-sent row. The drafts' text matching, with its older queued-card matching, now serves only terminal-backed chats, whose transcripts carry no ids. * fix(native-chat): merge not-sent rows by the transcript order alone The merge kept a rule for rows with no journal place that no caller reaches and that the desktop's sort does not have; drop it, and say what merging after the stop rows actually keeps. A test pins that the list the phone draws as given is already in the desktop's sorted order, with a moved stop row, a retry run, a cut-turn notice, a held card and two not-sent rows. * fix(mobile): draw the not-sent line as the desktop does Red and capped to the bubble's width, like the desktop's line and the phone's own returned-card caption, and only when there is a notice: the row had a second, unreachable source of words. A send a Stop took back is no failure, so it no longer rebuilds the notices on every streaming frame. |
||
|
|
e83e40e258 |
Session History shows OpenCode, Grok, OMP and Pi chats as chats and refuses a second terminal writer (#27183)
* refactor(chat): answer transcript adoption and Session History from the agent registration Claude and Codex's transcript importers and Session History ownership (row id, resume-command grammar) move onto their runtime registrations as required-nullable fields; every other agent writes null. agentSession.agents publishes the derived transcriptAdoption/sessionHistory flags, and a client reads a host that omits them (or lists nothing) as the old build's answer. Strict parity: only Claude and Codex answer yes anywhere. * refactor(chat): one Session History ownership index, binaries from row agents, fork offer from fork argv Review round 1: the duplicate-adoption check and Session History ownership read one index keyed by the registration's row id (an importer now requires sessionHistory); resume-command binaries derive from rowAgents through the TUI agent config; the Resume in New CLI offer asks getAgentForkArgv instead of naming Claude and Codex. Strict parity: only Claude and Codex answer yes. * feat(chat): Session History owns OpenCode, Grok, OMP and Pi native chats An OpenCode, Grok, OMP or Pi native chat's conversation listed in Session History as a plain terminal row, and resuming it ran the agent's CLI as a second writer to the conversation the chat was still using. Each agent's registration now fills `sessionHistory`, so those rows show as the chat (its name, opening the chat) and Orca refuses a terminal resume of an owned conversation, as it already did for Claude and Codex. - OpenCode lists under `opencode` and `opencode2` (2.x) rows by its ses_ id; `-s/--session`, `-c/--continue` resume, `--fork` does not. - Grok: `-r/--resume/--load` and `-c`; a non-UUID value names a title, so it is read as target-less; `--fork-session` does not resume. - OMP: `-r/--resume/--session` take an id, any prefix of it, or the session file's path; bare `--resume` and `-c` are target-less. - Pi: rows are listed by the session file name's id while the chat holds the file's path; `--session <id|prefix|path>`, `-c`, `-r` (picker). - An optional `resumeTargetMatches` on the registration covers prefix and path targets; it defaults to exact equality. - Each agent now reads every token naming its own binary, so another agent's name earlier in a command (`claude --model pi`, `cd ~/src/codex && claude --resume X`) no longer hides a resume. For Claude and Codex this only ever refuses more than before. - A renamed OpenCode chat tab names its `opencode2` row too. * fix(chat): show owned rows only to clients that open the chat, without a resume command - The list and search projection now asks, per owning agent, whether the requesting client opens that agent's chat. Current mobile renders only Claude and Codex chats, so it no longer receives OpenCode/Grok/OMP/Pi rows owned by a chat (a tap there opened an empty terminal and showed agent_session_conflict). Claude and Codex keep their rule: any client that reads structured sessions. - An owned search hit opens its chat, so it no longer carries a terminal resume command (all agents; `orca` CLI search stopped printing one for a chat). - OpenCode/Grok/OMP/Pi flags match case-sensitively, as their CLIs read them, so `rg foo src/pi -C 3` is not `pi -c`. Claude and Codex still fold case. - A test feeds every resume command Orca builds for an owned row of each agent (Session History, live-tab argv; posix, PowerShell, cmd) into the guard. * fix(chat): keep the resume guard linear and skip chat-tab lookups with no move - Each agent binary mention in a command now reads its arguments only up to that agent's next mention, which reads the rest, so every token is parsed once per agent. A 200 KB text naming agents throughout took 9.4 s on the host's main process; it now takes about 90 ms. Every refusal before still holds: a later mention still reads its own resume. - Right-clicking a native chat tab looks up its Session History row only when the agent's CLI can fork a conversation, the one move a chat tab offers, so OpenCode, Grok, OMP and Pi chat tabs run no list or rescan for nothing. Claude and Codex are unchanged. * fix(chat): read each shell command once in the resume guard The guard tokenizes the text once and splits it into shell commands at &&, ||, ;, |, & and newlines (a newline after a line-continuation mark stays inside its command). In each command, each agent reads its arguments from its first binary token to the command's end; a later token naming it is an argument. A `claude` path inside a Claude command no longer ends that command, so `--session-id <owned>` still cancels a fork after it, and a binary-named path between a resume and its fork flag keeps the fork a fork. Binary names are looked up once per token, which keeps a 16 MB send to about 2 s. Against main's parser, a Claude/Codex command is now allowed only when main refused it for a flag in a later shell command (`claude ; echo --resume X`). * fix(chat): end a resume-guard command at a bare carriage return A PTY's Enter, and many orca terminal send texts, end lines with \r. The guard now treats \r and \r\n as line breaks like \n, including after a line continuation mark, so a later line's resume is read as its own command. * refactor(chat): drop the transcript-adoption and Session History wire flags agentSession.agents no longer publishes transcriptAdoption or sessionHistory, so there is no new field for older and newer peers to reconcile. Their only consumers were renderer gates that could answer from what they already have: "Resume in New Native Chat" eligibility goes back to main's rule (adopting a CLI conversation is Claude/Codex-only, and the host still refuses any other agent from its registration's transcriptImport). Removes the AgentSessionDeclaredCapabilities split, the older-host decoder shim and the generic host-flag reader. * refactor(chat): keep main's Claude/Codex rule for the CLI fork offer "Resume in New CLI" and the chat-tab menu read the agent name again instead of building a synthetic provider session to ask the fork builder, and the chat-tab lookup loses its host Session History flag gate. Only Claude and Codex CLIs fork, so only their chat tabs look up a row, exactly as on main: no new list requests. * refactor(chat): one registration-aware ownership index, no registration union - listStructuredProviderSessionOwnership reads each record's registration for its Session History row id; the callback parameter and its one-function wrapper module are gone (no import cycle: checked value and type imports). - StructuredAgentCliConversations is a plain type: transcriptImport is nullable and sessionHistory is required, since every registered agent now owns its rows. The "importer needs history" union and its null checks go. - A test pins that no two registrations claim the same Session History row agent, since the owner lookup takes the first match. * fix(chat): read resume commands into words as a shell does Separators glued to a word (`opencode -s id; echo`, `cd /x&&claude -r id`) now end the command, and quotes are removed inside a word, so `--session="id"` reads as the id. Applies to every agent, Claude and Codex included. The acp-and-pi allowed() helper now asserts. * fix(chat): count an agent's name only where a shell would run it terminal.send checks agent prompts too, and agentPrompt does not keep the text from a shell (it falls back to a plain PTY write), so prompt text like "Fix the Pi --resume flag" was refused. The resume check now reads each command's program: its first word past VAR=x prefixes, a path, and env/exec/command/sudo/npx/bunx/pnpm dlx. Every command Orca's builders produce, Claude and Codex included and with a user's command override, is still refused. * refactor(chat): compare resume ids in any case; Claude uses the shared option reader The default target match now ignores case (ids are UUIDs or ses_ ids), so Grok's override, which only repeated it, is gone. Claude folds its flags and reads them with resumeInvocationFromOptions instead of repeating the `=` handling. * perf(chat): read terminal text in one linear pass A repeated regex group overflowed the stack on a 16 MB word. A sticky-regex scanner reads words, quoted runs and separators in one pass; an unclosed quote is searched for once per quote kind. * refactor(chat): read a command's resume only when its program is an agent * fix(chat): read an agent run under nohup, time or wsl as the command's program * chore: restore pnpm-lock.yaml * fix(chat): keep the CLI's own title on OpenCode, Grok, OMP and Pi chat rows Session History shows these agents' chat conversations under the title their CLI saved, as it does for their terminal conversations; the chat tab's name and renames stay on the tab. Claude and Codex rows keep the chat's name, as on main. * feat(chat): Resume in New CLI for Grok and Pi chats A Grok or Pi chat's Session History row and tab menu now offer "Resume in New CLI", like Claude and Codex: the CLI opens a copy of the conversation (grok --resume <id> --fork-session, pi --fork <file>) and the chat keeps its own. OpenCode's interactive CLI and OMP have no way to open a copy, so their chats keep only Resume. * fix(chat): offer Resume in New CLI only when the copy command can be built A Pi chat found by search on a remote Orca server has no session file path, so its copy command can't be built; the row no longer offers the button there. * fix(chat): refuse pi --session-id of a conversation a chat owns `pi --session-id <id>` reopens that session when it exists, so it is a second writer like --session. |
||
|
|
9c1d5d2fb7 |
perf(pty): check WSL working directories off the main thread (#27705)
* fix(wsl): start host-side wsl.exe probes through process-host so they never open a console wsl --list, wsl --status, the WSL home and directory probes, and WSL UNC deletes were started with node:child_process directly. The synchronous ones omitted windowsHide, so each spawn from the GUI-subsystem main process flashed a conhost window that could take keyboard focus. Route them through @orca/process-host, which pins windowsHide, and keep the execFile-shaped exit errors the availability cache classifies. Refs #27390 * build(tc): list wsl-exe-process.ts in the web typecheck project wsl-availability.ts is in the explicit web file list and now imports it. * refactor(wsl): drop the unused sync availability probe; classify ProcessResult directly No production code calls the sync isWslAvailable (the IPC and RPC paths already assert they never do), so delete it and its sync guest-probe twin instead of porting them. The async probe now reads the --status ProcessResult itself: an exit code is definitive, a timeout or signal kill is retryable, ENOENT on spawn is definitive. The WSL2-missing-kernel exit codes live in one named set. Availability tests now drive the async probe. * refactor(wsl): shrink wsl-exe-process to a spec builder and stdout reader With the availability cache classifying ProcessResult itself, nothing reads the execFile-shaped code/status error any more. wslExeFailure returns a plain reason string; wslExeStdout throws it; the UNC delete folds it into its own error. The home probe builds its argv with buildWslExecArgs. * perf(pty): probe WSL working directories off the main thread The in-process terminal launch path validated a \wsl.localhost cwd with a synchronous wsl.exe probe, blocking the main process ~70 ms per launch (300-530 ms when the distro is stopped, up to the 5 s timeout). The launch now awaits the existing async probe and the synchronous one is removed. Refs #20497 * fix(pty): let a canceled spawn abandon its pending WSL cwd probe The local spawn awaited the WSL directory probe without its cancellation signal, so a pane closed mid-probe waited up to the 5s wsl.exe timeout before noticing. Pass the signal through validateWorkingDirectoryAsync and report an abandoned probe as the spawn's own cancellation, as the daemon spawn preflight does. * test(wsl): mock process-host in the empty running-list case from main * docs(wsl): the availability probe no longer blocks; drop the stale word * build(ratchet): prune the wsl.exe sync launches this branch removed * build(ratchet): prune the sync WSL cwd probe this branch moved off the main thread --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
fb5d016887 |
fix(wsl): start every host wsl.exe call through process-host so no console window flashes (#27628)
* fix(wsl): start host-side wsl.exe probes through process-host so they never open a console wsl --list, wsl --status, the WSL home and directory probes, and WSL UNC deletes were started with node:child_process directly. The synchronous ones omitted windowsHide, so each spawn from the GUI-subsystem main process flashed a conhost window that could take keyboard focus. Route them through @orca/process-host, which pins windowsHide, and keep the execFile-shaped exit errors the availability cache classifies. Refs #27390 * build(tc): list wsl-exe-process.ts in the web typecheck project wsl-availability.ts is in the explicit web file list and now imports it. * refactor(wsl): drop the unused sync availability probe; classify ProcessResult directly No production code calls the sync isWslAvailable (the IPC and RPC paths already assert they never do), so delete it and its sync guest-probe twin instead of porting them. The async probe now reads the --status ProcessResult itself: an exit code is definitive, a timeout or signal kill is retryable, ENOENT on spawn is definitive. The WSL2-missing-kernel exit codes live in one named set. Availability tests now drive the async probe. * refactor(wsl): shrink wsl-exe-process to a spec builder and stdout reader With the availability cache classifying ProcessResult itself, nothing reads the execFile-shaped code/status error any more. wslExeFailure returns a plain reason string; wslExeStdout throws it; the UNC delete folds it into its own error. The home probe builds its argv with buildWslExecArgs. * test(wsl): mock process-host in the empty running-list case from main * docs(wsl): the availability probe no longer blocks; drop the stale word * build(ratchet): prune the wsl.exe sync launches this branch removed --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
424437a206 |
fix(claude): register the Windows statusLine so usage updates without Git Bash (#27710)
* fix(claude): register a statusLine Windows PowerShell can run
Claude runs the statusLine under Git Bash when present and otherwise under
PowerShell, which cannot parse the POSIX runtime-home command Orca registered.
On Windows without Git Bash the statusline never posted rate_limits, so the
live Claude usage feed went dark. Register the same shell-neutral .cmd
invocation the lifecycle hooks use; the old form is still recognised as
Orca-owned and replaced, and a user's own statusLine is never touched.
* fix(claude): keep the statusLine free of a per-tick PowerShell launch
A profile path the bare form cannot carry (a space, non-ASCII, quotes) fell
back to the encoded PowerShell launcher, which would start a hidden PowerShell
on every statusline tick and print "{}" if the script went missing. Register
the bare .cmd path only when it is cmd-safe and keep the runtime-home form
otherwise, so Git Bash users on such paths still run the .cmd directly.
Fold the registration tests into claude-status-line-install.test.ts and add a
real Git Bash run for a profile path with a space.
* test(claude): pair the stubbed win32 platform with win32 basename
The Windows statusLine case fed a Windows path to getManagedCommand on a
Linux runner, whose posix basename does not split backslashes. Production
only takes that branch on real Windows, where node:path is path.win32.
---------
Co-authored-by: Orca Worker <orca-worker@localhost>
|
||
|
|
1df7d7dd7a |
fix(daemon): verify daemon PID identity from the native Windows process table, not PowerShell (#27703)
* fix(daemon): verify daemon PID identity from the native Windows process table The Windows daemon PID check forked powershell.exe Get-CimInstance through node:child_process with no windowsHide, flashing a console and costing ~850ms per check. Read the command line and creation time from the shared windows-process-table reader instead, and route the POSIX ps queries through @orca/process-host. Refs #27390 * refactor(daemon): drop the ps migration and trim the PID identity tests Keep #27703 to the PowerShell removal: restore the macOS/Linux ps paths, their tests and the process-host baseline entry. Collapse the mocked Windows identity cases into one table, keep only the real-addon native case, and move the creation-time fallback beside queryWindowsProcess. --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
50cc50d33e |
refactor(chat): give the start-refusal resumable table its own module (#28085)
#27946 and #26684 together put agent-session-failure-words.ts at 304 lines, over max-lines, which fails lint and the pre-commit hook on every merge of main. The refusal-code table is standalone with one reader, so it moves out. Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
edd808479b |
feat(settings): move Chat UI's chat settings from Experimental to the Chat page (#28050)
* feat(settings): move Chat UI's chat settings from Experimental to the Chat page * chore(i18n): sync catalogs for the moved chat settings * fix(settings): hide the Behavior group when search matches only a switch the host lacks * Keep Chat behavior search aligned with translations and host support |
||
|
|
889ddcc6bd |
fix(agent-hooks): register forward-slash Windows hook paths for Grok, Devin, ZCode and Antigravity (#27713)
* fix(agent-hooks): register forward-slash Windows hook paths for Grok, Devin, ZCode and Antigravity These four agents registered their native-Windows status hook as a bare backslash path. A Git Bash hook host strips the backslashes, the command exits 127, and no status event reaches Orca. Use the same direct forward-slash form Claude, Codex and Muse already register, keeping the cmd-safe gate and the encoded PowerShell fallback. Existing backslash entries still match the managed-command matcher, so the next install replaces them and keeps user hooks. * perf(hooks): register direct .cmd hooks for Gemini, DSH, Kiro, Droid and Command Code on Windows On a cmd-safe profile path these agents now register the managed .cmd path itself instead of a `powershell.exe -EncodedCommand` launcher, so each hook event no longer pays a second PowerShell start-up on top of the runner's own shell. Profiles the bare path cannot carry (spaces, non-ASCII, UNC) keep the encoded launcher. Same pattern as Claude (#18875) and Muse (#26755). Refs #20913 * test(agent-hooks): expect forward-slash Antigravity hooks after the Unicode upgrade ASCII profiles now register the direct forward-slash wrapper path, so the upgrade-delivery test expects that form and also runs it through Git Bash. Unicode profiles keep the encoded launcher. * test(agent-hooks): assert the registered hook lives under the mocked home Pins that the os mock reaches the agents' node:os imports, so the host test never installs into the real profile. * refactor(hooks): one Windows batch-hook helper and one payload-delivery table - Add wrapWindowsBatchHookCommand (bare .cmd path, encoded launcher otherwise) and use it for Muse, Gemini, DSH, Kiro, Droid and Command Code. - Fold the five agents into windows-hook-payload-delivery.test.ts as rows run under each vendor's shell, from a plain and a spaced profile, with a stale encoded registration seeded per row; drop the separate runner suite and its CI list entries. - Replace the Windows-only per-agent registration tests with ones that stub process.platform, so they run on every CI OS. - Fix stale launcher, helper and DSH comments. Refs #20913 * refactor(agent-hooks): register Grok, Devin, ZCode and Antigravity through wrapWindowsBatchHookCommand Use the shared batch-hook helper from #27717 instead of an inline direct-or-cmd fallback. A UNC home is cmd-safe but has no drive letter; the old fallback registered it as a bare backslash path that Git Bash cannot start, while the helper sends it to the encoded launcher. wrapWindowsCmdHookCommand has no production callers left, so it is removed and its tests point at the helper. Grok, Devin and ZCode join the Windows payload delivery table with a legacy backslash entry to sweep, replacing the separate host test, and the Antigravity migration test now runs on every platform. --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
c0e2b73395 |
feat(native-chat): require Codex 0.136.0 for chats (#26684)
* Require Codex 0.136.0 for native chats
* Add host-owned Codex install and update actions
* Bind Codex checks and maintenance to the selected installation
* Resolve Windows updater cleanup through system helpers
* Use one child environment for Codex checks and launch
* Expire Codex readiness and reconcile current host jobs
* Resolve Codex checks against the child command search path
* Restrict global npm repair to the selected Codex install layout
* Pin the host updater directory through Windows supervision
* Synchronize Codex maintenance fixtures on readiness
* Unify Codex notices and recover version-refused chats
* Route Codex recovery to the operation that remains
* Preserve Codex setup execution errors in the job log
* Preserve UTF-8 in Codex setup logs
* Remove unused Codex host installation detector
* Require host administration for Codex maintenance
* Show a missing Codex explanation once
* test(native-chat): give scripted Codex runtimes their installation fact; keep the registry out of the relay
Runtime tests that drive a scripted Codex app-server still ran the new
version check against whatever codex was on the machine's PATH: refused
on CI (no codex), and on a dev machine it ran the real codex --version.
A scripted transport now must state the Codex it stands for
(readCodexInstallation), asserted at install, and the tests get it from
one scriptedCodexTransport fixture.
The relay's Codex maintenance path reached @orca/windows-registry through
resolvePathEnvKey's re-export in windows-environment-path; import it from
its registry-free module instead.
Also update the catalog-probe test for the shared child environment.
* refactor(native-chat): drop the Update Codex action; keep Install for a missing Codex
A too-old Codex now gets only the plain message ("Codex X is too old for
chats. Update to 0.136.0 or newer.") with no button and no job. The
existing rechecks (window focus, the <=30 s expiry of a saved result)
retry the refused chat once the user has updated Codex themselves.
A missing Codex keeps the Install Codex button: `npm install -g
@openai/codex` with the npm on the chat's PATH, as a host-run job with
its log, then a recheck and recovery. A configured Command that is
missing gets the message only, since a global npm install would not
land at that path.
Removed: the `codex update` command and its 0.126 floor, manual
instructions, npm layout and launcher identity detection, the action
descriptor (install|update) and its titles, the legacy capability, and
the SSH relay maintenance path (structured chat never runs over SSH or
WSL), so the relay preflight handler is back to main's.
* refactor(native-chat): keep Install Codex in Settings only
When Codex isn't installed, main already hides Codex from the New tab menu,
so the in-chat Install button was almost never reachable. Settings → Agents
already shows "Codex isn't installed." with Install Codex.
- Chats and the new-workspace composer now only state "Codex isn't
installed." (no button, no install job from the chat).
- The Install action, its busy spinner and the host-busy subscription move
into the Settings Codex row, the only place that starts the job.
- The store no longer re-checks every other workspace context when a job
finishes. A refused chat recovers through the same re-check a too-old
Codex uses (window focus, or the <=30 s expiry of a saved result).
- The chat recovery key no longer includes the install job id.
- Tests: Settings drives the install; a new test proves a chat refused for
a missing Codex recovers through focus after a Settings install, not
through the job; the expiry recovery test covers missing and too old.
* refactor(codex): check chat compatibility when acquiring the child
* Restore workspace submit guard and simplify Codex maintenance
* Keep only the Codex chat minimum version
|
||
|
|
6af34a4d99 |
fix(chat): name the agent when it refuses a message (#27946)
* refactor: move provider-retry pieces into a sibling words file Pure move of the six provider-retry translation pieces out of agent-session-failure-words-text.ts, which sits at the 300-line limit. No key or behaviour change. Co-Authored-By: Claude <noreply@anthropic.com> * fix(chat): name the agent when it refuses a message "The provider did not accept this message" becomes "{{agent}} didn't accept this message" ("The agent" when the name is unknown), in English and every locale. The providerRejected failure kind is unchanged. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
be25938415 |
[CI] Reduce repeated test imports, waits and unrelated jobs (#28069)
Preserve all 52 Markdown cases while consolidating one file and importing existing direct owners. Advance editor debounce windows through public selective timers, exclude unrelated lint tests from Performance PR triggers, and remove a pane assertion case entailed by retained coverage. |
||
|
|
fe1f0223af |
Native chat: read one saved row per subagent (part 1 of 2) (#27914)
* feat(chat): read one saved row per subagent Adds the singular `subagent` journal block (one row per child, revised in place, with a plain-text twin for older clients) and teaches every reader to draw it: desktop and phone fold a turn's sibling rows into the existing "Ran N subagents" row, the client and off-page rosters name children from their own rows, the reopen pass settles a row a dead host left working, and the phone and worker-transcript wires bound it. No producer writes the block yet; that switch lands in the follow-up. * fix(chat): open subagent background flag, separate nested group ids, page window skips subagent rows - background is an open boolean so a later build's value never fails a chat load - a helper's own helpers fold under a groupId of their own, so the phone opens them apart - each subagent's own row rides along with the page window instead of counting as conversation * refactor(chat): a subagent's group entry as one object |
||
|
|
de5470a900 |
fix(rate-limits): start the Codex usage probe off the main thread so focus doesn't freeze the UI (#27707)
* fix(rate-limits): spawn the Codex usage probe off the main thread On Windows, creating a cold standalone codex.exe can spend seconds in code integrity checks on the calling thread. The usage probe runs on window focus, so that froze the UI. The probe's child is now created and piped on a worker thread and proxied back to the main thread. Fixes #27362 * refactor(rate-limits): type the worker's children through @orca/process-host * fix(rate-limits): kill an orphaned Codex probe by pid when its worker dies Once the worker thread that owns the probe's child is gone, kill() can no longer reach the child through it. The proxy now falls back to a pid-addressed kill; the Codex probe uses the app-server tree kill so a node launcher's codex.exe child goes too, while SIGTERM stays a graceful root signal. * refactor(build): move the main build's entry map out of electron.vite.config.ts The new worker entry pushed electron.vite.config.ts past the 300-line limit. The Rollup input map for the main build now lives in its own module. * refactor(rate-limits): drop the orphan pid kill and trim the worker child-process stand-in A worker thread's death closes its children's pipes, so an abandoned Codex probe already gets stdin EOF, its graceful stop. The pid-addressed orphan kill was redundant with that and with terminateCodexProbeChild's own gated Windows tree kill. Its hard kill also bypassed the tree-kill gate's recycled-pid refusal by turning the handle-addressed fallback into a pid kill. - Remove orphan-pid-kill, killOrphanedCodexProbe, the injected killOrphan, and the orphaned flag. kill() now reports false once a child is no longer tracked. - Process-creation failure is one 'spawn-error' event that the stand-in expands into error/exit/close, replacing the duplicated triple and the exported exit code. Stdin errors arrive as child errors, as the probe already treated them. - Fold both suites into one over a real MessageChannel and real children. Add a real-worker test showing that terminating or crashing the worker lets the child exit on stdin EOF. * test(rate-limits): run the worker child-process suite under Node The suite asserts Node behavior that Electron main relies on: a failed spawn closes with a null signal, and a dead worker thread closes its children's pipes. Bun reports an undefined signal and, on Linux, leaves the pipes open, so the Bun lane failed on runtime differences, not on the product code. * test(rate-limits): count a reaped-by-nobody zombie as an exited child On Linux and macOS a child whose worker thread died gets stdin EOF and exits, but libuv reaps a child only through the handle on the loop that spawned it. Once that loop is gone, nothing waits on the pid, so it stays a zombie and kill(pid, 0) still succeeds. The real-worker tests now treat a zombie as exited, and still require the child's EOF marker. --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
8e8c087581 |
test(orcad): retry launcher-isolation teardown on Windows EBUSY (#28061)
An exited node.exe copy can stay locked for a moment on Windows, so the afterAll rm failed the hourly build's windows-11-arm persistence job. |
||
|
|
8f063f3567 |
perf(copilot): run the Windows status hook as a direct .cmd, faster and UTF-8 safe (#27718)
* perf(hooks): register direct .cmd hooks for Gemini, DSH, Kiro, Droid and Command Code on Windows On a cmd-safe profile path these agents now register the managed .cmd path itself instead of a `powershell.exe -EncodedCommand` launcher, so each hook event no longer pays a second PowerShell start-up on top of the runner's own shell. Profiles the bare path cannot carry (spaces, non-ASCII, UNC) keep the encoded launcher. Same pattern as Claude (#18875) and Muse (#26755). Refs #20913 * fix(kimi): register a cmd.exe-runnable hook on Windows Kimi runs hooks with asyncio.create_subprocess_shell, which is cmd.exe on Windows. Orca registered a POSIX `if [ -f ... ]` command there, so cmd failed with "-f was unexpected at this time" before reaching the script and, since Kimi fails open, no status event was ever sent. On win32 write a cmd+curl kimi-hook.cmd and register it the way the other direct .cmd agents do: the bare forward-slash path on a cmd-safe profile, the encoded launcher otherwise. The ownership matcher already covers every extension of the stem, so the old kimi-hook.sh entry is replaced on the next install. SSH remotes keep the POSIX script. Kimi joins the direct .cmd runner suite as a row run the way CPython's shell=True does, and every row now also runs from a profile with a space (the encoded launcher) and outside an Orca pane. * fix(copilot): run the Windows status hook as a direct curl .cmd Copilot runs a Windows hook as `pwsh|powershell -nop -nol -c <command>`. Orca registered an encoded `powershell.exe -EncodedCommand` launcher there that started a second PowerShell to run copilot-hook.ps1, which posted with Invoke-WebRequest: two PowerShell starts per event (~850-900 ms median), and the .ps1 read stdin through the console code page, so non-ASCII prompt text arrived as "caf?? ...". On win32 write copilot-hook.cmd (answer `{}`, refresh the endpoint, env guard before stdin, curl form POST with hookEventName) and register its bare path with the event as its argument; non-cmd-safe profile paths keep the encoded launcher, which now sets ORCA_COPILOT_HOOK_EVENT for the .cmd. The managed matcher covers every extension of the stem, so old .ps1 entries are replaced on the next install while user hooks stay. SSH remotes keep the POSIX script. Copilot joins the direct .cmd runner suite as a row run under both PowerShells, checking the byte-exact payload and the posted hookEventName. Refs #20913 * refactor(hooks): one Windows batch-hook helper and one payload-delivery table - Add wrapWindowsBatchHookCommand (bare .cmd path, encoded launcher otherwise) and use it for Muse, Gemini, DSH, Kiro, Droid and Command Code. - Fold the five agents into windows-hook-payload-delivery.test.ts as rows run under each vendor's shell, from a plain and a spaced profile, with a stale encoded registration seeded per row; drop the separate runner suite and its CI list entries. - Replace the Windows-only per-agent registration tests with ones that stub process.platform, so they run on every CI OS. - Fix stale launcher, helper and DSH comments. Refs #20913 --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
e02e2bb1d9 | [CI] Advance transcript clocks and skip test-only computer checks (#28060) | ||
|
|
28dc0c9771 |
fix(kimi): give Kimi a Windows .cmd status hook that cmd.exe can run (#27714)
* perf(hooks): register direct .cmd hooks for Gemini, DSH, Kiro, Droid and Command Code on Windows On a cmd-safe profile path these agents now register the managed .cmd path itself instead of a `powershell.exe -EncodedCommand` launcher, so each hook event no longer pays a second PowerShell start-up on top of the runner's own shell. Profiles the bare path cannot carry (spaces, non-ASCII, UNC) keep the encoded launcher. Same pattern as Claude (#18875) and Muse (#26755). Refs #20913 * fix(kimi): register a cmd.exe-runnable hook on Windows Kimi runs hooks with asyncio.create_subprocess_shell, which is cmd.exe on Windows. Orca registered a POSIX `if [ -f ... ]` command there, so cmd failed with "-f was unexpected at this time" before reaching the script and, since Kimi fails open, no status event was ever sent. On win32 write a cmd+curl kimi-hook.cmd and register it the way the other direct .cmd agents do: the bare forward-slash path on a cmd-safe profile, the encoded launcher otherwise. The ownership matcher already covers every extension of the stem, so the old kimi-hook.sh entry is replaced on the next install. SSH remotes keep the POSIX script. Kimi joins the direct .cmd runner suite as a row run the way CPython's shell=True does, and every row now also runs from a profile with a space (the encoded launcher) and outside an Orca pane. * refactor(hooks): one Windows batch-hook helper and one payload-delivery table - Add wrapWindowsBatchHookCommand (bare .cmd path, encoded launcher otherwise) and use it for Muse, Gemini, DSH, Kiro, Droid and Command Code. - Fold the five agents into windows-hook-payload-delivery.test.ts as rows run under each vendor's shell, from a plain and a spaced profile, with a stale encoded registration seeded per row; drop the separate runner suite and its CI list entries. - Replace the Windows-only per-agent registration tests with ones that stub process.platform, so they run on every CI OS. - Fix stale launcher, helper and DSH comments. Refs #20913 --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
0309341ac4 |
feat(native-chat): wrap long lines in code blocks (#26130)
* feat(native-chat): wrap long lines in code blocks Code blocks in native chat now have a wrap-lines toggle next to Copy. It is off by default, per block, and not persisted; when on, the block wraps long lines instead of scrolling sideways. * fix(native-chat): give each document code block its own component The document pre renderer called the code-block renderer as a function after an early return, so a renderer with hooks ran them as the pre's own hooks and React saw the hook order change when a fence switched between diagram and code. * fix(native-chat): keep a block's line wrap when its row scrolls away Wrap lived in the code block's own state, so a row that windowing unmounted, or a growing reply re-cutting its top-level blocks, came back unwrapped and shorter than its measured height. The flag now lives in the transcript's disclosure store, keyed by the row and the fence's offset in the whole message, which appended text never moves. Outside a transcript the block keeps local state as before. * fix(native-chat): key a block's line wrap by its line, not its character offset While a reply streams, its last block is parsed after the streaming fixes escape characters such as x~y mid-line, so a later fence's character offset moved by one when the block was next parsed as written (the reply finishing, another block following, or the reply merging into one block), and the wrap reset. Those fixes never add or remove a line break before a fence, so the block splitter now records each block's starting line and the wrap key uses the fence's line in the whole message. * fix(native-chat): keep line wrap in plan, reasoning and approval cards too Plan cards and reasoning bodies rendered their markdown without a row key, so their code blocks fell back to local wrap state and lost it when the row scrolled away. Reasoning text now uses its existing disclosure key, shared by the live line and the finished row, and a plan card uses plan:<message id>, so neither can share a key with the reply of the same message. The approval card sits in the composer slot, outside the transcript and its store, and is never windowed, so it keeps local state. |
||
|
|
9efce92d91 |
Keep a "chats resumed" entry in the bottom bar until you've seen the result (#27580)
* fix(native-chat): keep a 'chats resumed' bottom-bar entry until the result is seen After every chat resumed, the bottom-bar entry vanished the moment the run finished, leaving a fading toast as the only way back to the list. Show 'N chats resumed' while a finished run's summary has not been shown yet, reusing the run's existing finishedViewShown flag so the entry ends exactly when the summary is viewed and closed. * Keep resume results until their rows are seen * Retire viewed empty resume runs * Show finished resume rows after in-flight view settles |
||
|
|
9fcbb2ce3e |
fix(chat): name orchestration worker chat tabs after their task title (#28045)
* fix(chat): name orchestration worker chats after their task title Worker chats were skipped by chat naming and stayed "Claude Chat". Name them from the task they were started for instead, with no model call. * Fix legacy worker chat titles without prompt generation * Remove unrelated lockfile dependency |
||
|
|
d4d12120c6 |
[CI] Advance test clocks and preserve cleanup checks (#27791)
* [CI] Remove wall-clock waits and stabilize GC fairness check * [CI] Include the final GC timer gap in the fairness check * [CI] Advance test clocks and preserve cleanup checks |
||
|
|
a94092908c |
fix(native-chat): message rail lights a message sent while the agent was working (#27821)
* fix(native-chat): light the tick of a message sent mid-turn on the message rail A message sent while the agent is working joins the running turn's key, and the rail lit ticks by turn key, so that message's tick never lit: not at the bottom, not after clicking it. Light the newest tick at or above the read row within its turn instead. * fix(native-chat): light the nearest tick above the read row, and keep a clicked tick lit Review round 1. The within-turn walk stopped at a row of no turn landing in the running turn, and could return a tick from the turn above. The lit tick is now the newest loaded rail item at or above the row at the fold, falling back to its turn key above the first loaded one (that prompt is in the outline). A jump that cannot bring its row to the top lands clamped at the bottom, and the settled position report then lit the last tick instead of the clicked one. A clicked tick now stays lit until the reader scrolls or starts another navigation (the existing reader-input path), or the set of prompts changes. Rail picks and the start of every navigation move into their own hook, as the list is at its line limit. * fix(native-chat): hold a clicked rail tick by position, not by reader input Review round 2. Releasing the clicked tick on reader input needed every scroll source to report itself, and several do not (scroll-to-top button, inline diff reveal, prompt refold, selection-drag autoscroll); releasing it whenever the prompts changed dropped it on every head trim of a long live session. The hold now records where the jump settled, at the first idle read after the click, and keeps the clicked tick lit while the view rests there. Any movement, whatever caused it, releases it, as does the clicked message leaving the rail. Drops the navigation wiring and the hook it was moved into. * fix(native-chat): anchor a clicked rail tick's hold to its row on screen Review round 3. Holding while scrollTop stayed put recorded the reader's spot when they kept scrolling within the idle period of the jump, kept an off-screen row lit after the viewport shrank, and let go when a row above re-measured late and shifted scrollTop with the content. The hold now records how far below the viewport top the clicked row settled, and keeps the tick lit while the row is still on screen at that offset. |
||
|
|
c34574180b |
Terminal header button: Resume in New Native Chat replaces Show chat view (#27184)
* feat(terminal-pane): header button resumes the CLI session in a new native chat The pane header's "Show chat view" toggle is replaced by the tab menu's "Resume in New Native Chat" move. The Session History lookup runs on click, so an always-visible header never scans in the background. A pane already in chat view keeps its "Show terminal" way back. * fix(terminal-pane): fold the resume gate into the pane's existing store subscription Keeps a mounted terminal pane inside its pinned store-listener budget. * fix(terminal-pane): resume the pane's own conversation, open the chat that already holds it The header "Resume in New Native Chat" button gated on chat-view eligibility but looked up the tab's best conversation, so a Grok pane beside a Claude pane resumed the Claude conversation, and Grok/OpenCode panes showed a button that always failed with a "try again" toast. - Map one pane to its conversation with the tab-title mapping narrowed to that pane (same sources, same Claude/Codex rule), for both the button's visibility and its click; this also keeps the button after the agent exits, as the tab menu does. - A conversation a native chat already holds now matches its history row; the move's gate still refuses it (tab menu unchanged, pinned in the parity test), and the button opens that chat. - Distinct messages: nothing saved yet, cannot be resumed in a native chat, or the existing generic failure. The click forces a fresh scan like the panel's Refresh does. - Call the plain resume launch directly; drop the shared actions module and restore the tab menu. - A tab closed during the lookup no longer opens a chat. * fix(terminal-pane): hide Resume in New Native Chat where the chat route is refused On a local workspace whose project runs in WSL (or needs runtime repair), the header button showed on Claude/Codex panes, but native chat cannot launch there, so every click said the conversation can't be resumed while the tab menu offered nothing. The button's visibility now also asks the same launch-route check the Session History row gate uses (structuredAgentSessionLaunchFeasible). * fix(terminal-pane): offer the header resume only while the pane's agent is running The tab menu now offers Resume in New Native Chat only while the tab's agent runs (#27520). The header button still found its pane's conversation from the retained or sleeping record an exited agent leaves behind, so it stayed after exit. The pane lookup now honours the same runningAgentsOnly option, and both the button's visibility and its click pass it. * refactor(terminal-pane): the header's pane lookup reads only the running agent Every caller of resolvePaneAiVaultTitleRequest asked for running agents only, so its retained and sleeping sources were never read. The pane lookup now maps just the pane's live agent, and collectAiVaultTitleRequests returns to main's shape, sharing only the live-agent mapping with it. |
||
|
|
8a7d19e330 |
Show turn edit diffs inline in native chat (#27758)
* Show recorded turn diffs inline in native chat * Resolve only selected turn diff tool pairs |
||
|
|
c62c5a4cfc |
perf(agent-hooks): drop the extra PowerShell per hook event for Gemini, dsh, Kiro, Droid and Command Code (#27717)
* perf(hooks): register direct .cmd hooks for Gemini, DSH, Kiro, Droid and Command Code on Windows On a cmd-safe profile path these agents now register the managed .cmd path itself instead of a `powershell.exe -EncodedCommand` launcher, so each hook event no longer pays a second PowerShell start-up on top of the runner's own shell. Profiles the bare path cannot carry (spaces, non-ASCII, UNC) keep the encoded launcher. Same pattern as Claude (#18875) and Muse (#26755). Refs #20913 * refactor(hooks): one Windows batch-hook helper and one payload-delivery table - Add wrapWindowsBatchHookCommand (bare .cmd path, encoded launcher otherwise) and use it for Muse, Gemini, DSH, Kiro, Droid and Command Code. - Fold the five agents into windows-hook-payload-delivery.test.ts as rows run under each vendor's shell, from a plain and a spaced profile, with a stale encoded registration seeded per row; drop the separate runner suite and its CI list entries. - Replace the Windows-only per-agent registration tests with ones that stub process.platform, so they run on every CI OS. - Fix stale launcher, helper and DSH comments. Refs #20913 --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
982b3d4234 |
fix(browser): settle WSL tunnel reads so responses past 256 KiB complete (#27625)
* fix(browser): settle WSL tunnel reads so responses past 256 KiB complete The WSL execution route hands the deferred socket a credit-accounted tunnel duplex, but the deferred socket forwarded its data without settling it, so the relay's 256 KiB receive window was never replenished and larger responses stalled. Settle each chunk once tunnel-socket listeners have taken it; their pause() still holds the source, so unsettled bytes stay bounded by the window. Fixes #27356 * test(browser): bound the WSL backpressure wait so a regression fails instead of hanging * test(browser): keep unchanged WSL route test lines in their original form --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
b40554b2dc |
fix(browser): end a background page's mount admission after its first load (#27754)
* fix(browser): end a background page's mount admission after its first load A page opened in the background is admitted so its guest starts, but the admission was only released on close. Its overlay stayed laid out (invisible) in the visible workspace and its browser chrome never unmounted in hidden workspaces. Release the admission when the guest's first load settles, so the normal active-page and paint-retention rules own the page afterwards. STA-7435 * test(browser): pin how a released mount admission parks a background page Covers the overlay contract the release relies on: in a hidden worktree the page's browser chrome unmounts once the admission ends; in the visible worktree it stays mounted and only its slot stops being laid out. Also corrects the page-record comment that still said background tabs sit idle until shown. |
||
|
|
fa4ef2b961 |
ci: stop new main-process code from freezing Orca with synchronous launches (#27756)
* ci: ratchet synchronous child-process launches in main and shared code
The Electron main process freezes every window while a synchronous child
process runs, and on Windows each launch is slow because antivirus scans
it. Nothing stopped new synchronous launches from landing in main-process
code, and the spawn observer behind ORCA_MAIN_THREAD_DIAGNOSTICS only saw
async spawns, so the worst blocks were invisible to it.
Ratchet: check:main-sync-spawn-ratchet parses production src/main and
src/shared files (test-only paths excluded) and fails when a file not in
config/main-sync-spawn-baseline.txt reaches execFileSync, spawnSync or
execSync from child_process, runProcessSync from @orca/process-host, or
one of the synchronous secure-file writers (they run icacls on Windows).
Named, aliased, namespace, default, require() and import() forms count.
A baseline entry whose file no longer launches synchronously fails as
stale, so the list can only shrink. It runs in lint and in the PR
static-analysis job next to the process-host import check.
Observer: runProcessSync now reports to the spawn observer, timing the
whole call (that is how long the thread was stuck) and reporting from a
finally so failing, throwing and timed-out children are counted too.
Runtime behavior is unchanged except that the diagnostics observer now
sees synchronous launches; with no observer registered the sync path
pays one extra branch.
* ci: count sync launches per file and gate the repo's sync wrappers
The sync-spawn ratchet only tracked which files launched synchronously, so a
file already on the list (wsl.ts, win32-utils.ts, git-exec-file.ts) could add
more launches unnoticed, and new callers of the repo's own synchronous
wrappers passed CI.
The baseline now stores a per-file count of uses, in the same format as the
focus-read ratchet: a rise or a new file fails, a lower or zero count fails
until `pnpm check:main-sync-spawn-ratchet --prune` lowers it, and --prune
never raises an entry. Every value reference to a gated function counts
(call, hand-off, alias and its uses, re-export); imports alone count nothing.
Gated wrappers: gitExecFileSync (and the git/runner re-export),
restrictWindowsPathSync, hardenSecurePath when called with sync: true,
grantDirAcl, getWslHome, listWslDistros, wslUncDirectoryExists,
isWslAvailable (and the wsl.ts re-export), isPwshAvailable. Their 18
current caller files join the baseline.
Failure messages now give advice per family: the async process-host API for
child-process launches, the async twin for wrappers, and for the secure
writers a note that no async secure writer exists yet, so the sync one stays
and must never become a plain write (that drops the Windows ACL hardening).
Also refresh two stale blockMs descriptions and drop a no-op line from the
spawn-observer "stays silent" test.
* ci: count hardenSecurePath unless visibly async, and tighten ratchet tests
hardenSecurePath was counted only when `{ sync: true }` was written inline,
so moving the options into a variable or a spread dropped the count and the
check then asked for a prune. It now counts every use except a call with no
options or a spread-free object literal whose `sync` is absent or false.
Also: resolve backslash paths in the importing file as well as the
specifier; still visit heritage and instantiation expressions
(`extends mixin(fn)`, `fn<T>`); state the reference-only counting limit;
and point the secure-writer advice at raising this file's baseline count.
Tests cover the hardenSecurePath shapes, the alias chains that need the
fixpoint loop, and a prune that must not raise a grown row.
* test(ci): pin the main sync-spawn ratchet background step
* fix: count secure hardening calls with spread arguments
|
||
|
|
3fb4b06dbb |
perf(notifications): stop every Windows notification from freezing Orca (#27731)
* perf(notifications): save mobile dismissal history off the main thread Every agent notification recorded its id in mobile-notification-dismissals.json through the secure-file writer. On Windows that writer runs about five synchronous icacls launches per write, so each notification froze every Orca window (STA-9692). The file holds notification ids, sequence numbers and session ids, not credentials, so it now goes through the existing AtomicSnapshotWriter: async temp-plus-rename, mode 0600, bursts coalesced into one write of the latest entries. Memory stays authoritative, so delivery and retirement are unchanged. The pending write is flushed in the quit barrier after chat and RPC teardown, and in the pre-relaunch hook, since renderer relaunch exits without the quit pipeline. * perf(notifications): flush dismissal history when a headless host shuts down orcad never runs the desktop quit barrier, so its cleanup list awaits the pending dismissal write after RPC stops. * fix(persistence): drain a snapshot write requested just after a drain ends AtomicSnapshotWriter cleared its pending-write promise one microtask after the drain loop saw no more requests. A write() in that gap set writeRequested, got the settling promise back, and nothing drained it, so the newest bytes stayed unwritten and waitForPendingWrite() (the dismissal store's flush) resolved without them. The drain now clears the pending promise in the same tick its loop exits, on success and failure, so a later write() always starts a new drain. * test(notifications): flush dismissal writes before deleting temp state dirs Dismissal history now saves asynchronously, and the writer recreates its directory before each write. Tests that deleted their temp dir with a write still pending left recreated dirs behind in the system temp folder and could race the delete on Windows. They now await the controller's flush first. * perf(notifications): close dismissal history at committed exits The shutdown flush only waited for writes already queued. A notification recorded after it (orcad cleanups still running, or the 150 ms before a renderer relaunch calls app.exit) started an async write the exit dropped, so the phone could keep an alert the desktop could no longer withdraw. The store's flush() becomes close(): it waits for the pending write, and every later record saves synchronously through the snapshot writer's existing writeSync (plain fs, no icacls; a failure only warns). It is called only where the exit can no longer be vetoed: the will-quit teardown, a new exit-only hook that app:relaunch runs before app.exit(0) (restart and profile switches share onBeforeRelaunch but quit through will-quit), and orcad's cleanup after RPC stops. The quit test now holds chat teardown and RPC stop and proves the close starts only after both settle, in either order. The orcad push-startup runtime mock gains the method the entry now calls. * fix(notifications): bound the dismissal close before a renderer relaunch app:relaunch waited on the dismissal store's close with no limit, so a stalled userData disk left Restart stuck on "Restarting…" with a half-quit app saving synchronously. The close now races a 2 s cap through the existing settleWithinMs helper, the same cap the restart path's auth preservation uses, and logs when it gives up. * test(notifications): keep async dismissal writes under test between reads Mid-test disk reads used closeDismissals() as a barrier, which switched every later record to the exit-only synchronous path. The store gains a non-closing flush() (close() = mark closed + flush), exposed on the controller as flushDismissals for tests; mid-test barriers use it, and close stays only where a test simulates an exit or teardown. Also notes why the writer's pendingWrite assignment is safe, renames a store test to what it covers, and groups the orcad cleanup-order test under a describe. |
||
|
|
56a12f54cf |
fix(browser): end a page's mount admission whenever it leaves the store (#27755)
* fix(browser): end a page's mount admission whenever it leaves the store A background-opened page's start admission was released only by the two close actions, so a bulk worktree purge (listing refresh, repo or folder removal) dropped the page while its admission stayed in the set. Release it in the one cleanup every page removal already runs through (destroyRemovedBrowserWebview), and drop the per-path copies. STA-7436 * refactor(browser): one removed-page sweep shared by the app and its test Moves the store sweep that destroys removed pages into destroyWebviewsRemovedFromStore so the admission regression test runs the same code the app runs, and adds an eviction case. * test(browser): assert pages were admitted before the eviction case |
||
|
|
b0e73d9342 |
fix(codebuddy): run Windows hooks without requiring PowerShell 7 (#27626)
CodeBuddy spawns hooks registered with shell: 'powershell' as a bare `pwsh`, so on Windows without PowerShell 7 every hook failed with spawn pwsh ENOENT and the failed UserPromptSubmit hook blocked prompts. Register CodeBuddy's hooks the way Claude's are: the managed .cmd path on cmd-safe profiles (runs under CodeBuddy's Git Bash or Windows PowerShell default shell) and the absolute powershell.exe encoded launcher otherwise. The next install rewrites existing registrations. Fixes #27182 Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
25f87544d0 |
feat(terminal): persistent banner to restart a terminal daemon whose files are gone (#28021)
Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
fde0fe35a7 |
fix(daemon): stop giving new terminals to a daemon whose AppImage files are gone (#28011)
* fix(daemon): stop giving new terminals to a daemon whose AppImage files are gone On Linux AppImage, a terminal daemon can outlive the mount it runs from and keep answering health checks until it SIGBUSes. Orca now reads the daemon's /proc exe link and mount table at adoption: an idle severed daemon is replaced; a busy one is kept for its sessions but quarantined, so fresh terminals use the local provider and a healthy RPC never re-admits them. Status and a verified restart are available over RPC and as `orca terminal-daemon status|restart`. Co-Authored-By: Claude <noreply@anthropic.com> * fix(daemon): lift the severed quarantine once a new daemon owns the endpoint Co-Authored-By: Claude <noreply@anthropic.com> * fix(daemon): a severed-daemon restart counts fallback terminals and never stops a replacement The restart re-checks the authenticated endpoint owner before any teardown and again at shutdown, and never falls back to a pid kill when targeted. Status counts the local fallback terminals the restart also ends. Co-Authored-By: Claude <noreply@anthropic.com> * chore(daemon): merge duplicate import Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): classify the terminalDaemon RPC namespace as host-owned Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
5f1f9ea07a |
fix(serve): give the first AppImage serve one unpacking deadline and progress (#28015)
Direct AppImage serve now unpacks its stable copy once, under one overall deadline that also bounds the registration lock wait and both extraction attempts, prints progress to stderr, and refuses fast when the private cache is not writable, not executable, or too full. Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
cb92b6ce57 |
feat(serve): run the --supervise supervisor from a copy outside the app (#28007)
* feat(serve): run the --supervise supervisor from a copy outside the app * fix(serve): record supervisor copy users beside the copies so a cleanup never races a fresh copy * fix(serve): remove a partial supervisor copy when copying fails * test(serve): skip the unreadable-copy case where mode 000 does not block reads --------- Co-authored-by: m4air <m4air@Mac.localdomain> |
||
|
|
dedea9c76c |
fix(updater): clear a cancelled macOS install request before staging the next update (#28010)
* fix(updater): clear a cancelled macOS install request before staging the next update * fix(updater): match only Orca's ShipIt and recheck owners right before clearing --------- Co-authored-by: m4air <m4air@Mac.localdomain> |
||
|
|
3d27142407 |
fix(linux): keep extracted AppImage copies that something still runs from (#28002)
* fix(linux): keep extracted AppImage copies that something still runs from New builds extract into a namespace that pre-lease builds never prune. Pruners now delete a generation only when no same-user process runs from it and no lease names a live process (pid, start ticks, boot id). Co-Authored-By: Claude <noreply@anthropic.com> * fix(linux): skip non-dumpable processes in the AppImage residency scan Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
65a1611926 |
fix(serve): explain what to run when an SSH host's orca cannot start or install a server (#28003)
* fix(serve): explain what to run when an SSH host's orca cannot start or install a server * fix(serve): keep an app launcher on PATH usable from a server terminal; share the app-CLI check --------- Co-authored-by: m4air <m4air@Mac.localdomain> |