Persist windowFullScreen on enter/leave-full-screen (frozen once the window
starts closing) and re-enter fullscreen on reveal after the saved maximize,
skipping background launches. Ignore the spurious unmaximize macOS emits
while a launch-maximized window enters fullscreen so windowMaximized and
windowBounds keep the pre-fullscreen state.
Fixes#40510
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Session History picked each session's workspace chip by matching cwd, so
when several folder workspaces shared one folder every row showed the
first workspace in the list. Prefer the live (non-archived) workspace
recorded in structuredSession.workspaceId on the session's host, and fall
back to the existing cwd match otherwise.
Fixes#41044
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
Picking a split terminal tab from Cmd+J or the tab bar's switch menu
focused the first pane, because the picker already held focus and the
tab-wide focus query fell back to the first xterm textarea. Pass the
tab's stored activeLeafId to focusTerminalTabSurface (and to the paired
host activation) so input returns to the pane that was last active.
Co-authored-by: Neil <neil@stably.ai>
The explorer drops node_modules and .git from every listing page, so a
reveal under them waited for a row that never appeared. The request stayed
pending and auto-reveal ignored later editor tabs.
getRevealTarget now cuts the reveal off at the first folder the listing
filter rejects. A nested hidden folder selects the folder that holds it; one
directly under the root clears the request. Hidden folders are never
expanded or read.
Fixes#41039
Co-authored-by: Neil <neil@stably.ai>
The Orca claude shell function launched Claude inside a ( ... ) subshell.
Bash can keep that subshell as the pane's foreground process, so Orca saw
"bash" instead of Claude. The subshell now unsets the claude function and
execs the binary, leaving Claude as a direct child of the pane shell.
Co-authored-by: Neil <neil@stably.ai>
Factory Droid has no PermissionRequest hook event, so `droid doctor`
flagged the hook Orca wrote into ~/.factory/settings.json as unsupported.
The installer no longer registers it; reinstall drops only the
previously managed Orca command on that event and keeps user hooks.
Approval waits continue to come from PreToolUse and Notification, and
the now-unreachable PermissionRequest listener handling is removed.
Fixes#40607
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
The right sidebar's Activity Bar Position lived only in renderer state, so
choosing Side reset to Top on the next launch.
Persist it with the other right-sidebar UI fields: PersistedUIState, the
paired-client update schema, the default and startup-fallback UI state, the
renderer write baseline and writer, and hydration. Profiles without the field
stay at Top, and hydration maps any value other than 'side' to 'top' so a
corrupt value cannot hide the activity bar. The ActivityBarPosition type
moves to shared ui-chrome-types so the persisted contract can use it.
Keep the field pairing-local for web clients, like sidebarOpen: older hosts
parse ui.set with a strict schema and would reject the whole update, so the
browser strips it from host writes and pins its own value on ui.get. Desktop
persists it through IPC.
Fixes#40887
Co-authored-by: Neil <neil@stably.ai>
Dev-folder plugins are hashed at discovery with DEV_FOLDER_SKIPPED_DIRECTORIES
(e.g. .orca/), but the worker activation integrity check re-hashed the whole
tree. Once Orca wrote typings into .orca/types, the activation hash no longer
matched the reviewed hash and the dev worker refused to start. Pass the dev
flag through to the integrity check so both hashes skip the same directories.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
The scripted Codex fixture hard-coded /home/dev/.codex as the account
home on every platform. Startup now reads hook configuration from the
account home, so coordinator-worker tests stalled on macOS before the
scripted connection opened. Build the fake account home inside each
test's temporary fixture root and pass that root to every attach caller.
Package identity hashed files in a segment-wise depth-first walk order, so a
file like references/refs.md sorted after references/refs/image.webp. The
manifest validators require complete paths in code-unit order, so such
skills failed with skill-bundle-manifest-path-order. Sort the complete
paths by code unit in both the runtime identity and the build-time manifest
generator, and cover the sibling file/directory layout with a round trip.
Co-authored-by: yukurust <76849725+yshi112358@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
The dashboard pop-out only claimed zoom chords in before-input-event, so
Kitty-mode xterm encoded Cmd+V as CSI u and consumed it before the Edit
menu accelerator could fire, typing a stray "v" instead of pasting.
Claim the chord with the shared isMacAppPasteInput matcher and route it
through the existing ui:appMenuPaste owner, matching the main window.
Fixes#40862
Co-authored-by: Neil <neil@stably.ai>
OpenCode 2 charged the 64 MiB capture budget against raw session_message
rows, which are mostly tool input and metadata the transcript never keeps,
so a session with ~65 MiB of rows and a few hundred KB of text was dropped
whole. Count decoded transcript text instead, as OpenCode v1 does, and
copy truncated message text so a 256 KiB slice no longer pins its
oversized source string while the capture is held.
Fixes#28791
* feat(orchestration): deny a worker's permission prompt, and say when mail is held
A chat worker that stops at a permission prompt now escalates with the prompt
itself as structured data (approval id, state, worker, summary, allowed
actions). The coordinator can deny it with a reason through
`orchestration deny`; the worker carries on and gets the reason as mail.
Only a person can allow a prompt: the answer method decides "person" from
the transport, never from params. The stop report keys one escalation per
approval and sends one closing line when it is answered, and no longer tells
the coordinator that `orchestration send` answers a prompt.
`orchestration send` now warns when the delivery gate would hold the mail
right now (an open prompt, a blocked status, typed text), and says delivery
state is unknown for a worker on a paired server.
* fix(orchestration): only the desktop app counts as a person for worker approvals
A paired device can carry a remote CLI, so it is treated as an agent: it can deny with a reason but never allow.
* fix(orchestration): approval answers and held receipts follow the real gates
- A same-option answer counts as Orca's only when Orca recorded it; a retry returns the same
receipt with no second reason mail.
- An unreadable chat is not a closed prompt: the answer refuses, and the closer keeps watching.
- A closing line tells a reason only when it went to the worker as mail.
- The terminal held receipt prints the delivery gate's own refusal; the chat one prints what the
pointer's admission and queue gate would do (not attached, refused, or behind an open prompt).
* fix(orchestration): read the held receipt only after the mail is stored
An await before the insert let a worker settle meanwhile, so the mail could land on a settled
Dispatch after its follow-up scan. The closer also removes only the approval map it read.
* fix(orchestration): tell the coordinator not to block on a worker's permission prompt
The approval escalation now says the worker is waiting for permission, tells a chat
coordinator the user has been shown Allow/Deny (a terminal coordinator: a person must
answer it in Orca or the worker), asks it to carry on with other work and not message
the worker until the answer arrives, and offers deny only as the way out when the
prompt is holding up the task. The guide and CLI docs say the same.
* fix(orchestration): a paired coordinator without an Orca session id mails a deny reason from its Run
* feat(orchestration): answer a Claude terminal worker's permission prompt
A worker pane's PermissionRequest hook now waits for Orca's answer, so the coordinator can deny
it with a reason (the worker continues) and a person can allow it. One record per waiting hook,
keyed by Claude's prompt and tool call; it is answerable only while the hook waits and the dialog
is on screen, and anything else gets `{}` as before.
* test: annotate the fake screen instead of casting
* test: wait on the hang-up instead of sleeping
* fix(orchestration): claim a terminal answer only from what Claude shows
An answer is written only while a caught-up screen still shows the dialog
in the same process run, and claimed only once Claude shows it applied: the
hook's deny line for a deny, no other close for an allow. A Yes, a No or the
2:00 auto-block that wins the race is refused and named from the screen.
A hook that hangs up is not an answer: with the dialog still up the
coordinator is told a person must answer it in the worker's terminal.
A PermissionRequest entry the user made async stays async: it prints {}
first and never waits for a decision.
* fix(orchestration): name a terminal prompt's close from its tool_result
The screen could show an older prompt's close, so who answered is now read
from the tool_result Claude's transcript records for that tool call: Orca's
own deny text credits Orca, the user's No and the 2:00 safety-check block
name themselves, and a run names an allow. Hook events cannot say this: a
deny or a No fires no PostToolUse. The screen only says whether the dialog
is still up before a write, and a PostToolUse seen mid-answer is kept.
* fix(orchestration): read a prompt's tool_result without blocking main
The transcript read is async, reads only its tail, and skips any path that
is not a regular file, so a FIFO or device cannot stall the main process.
A closed prompt still awaiting its result gets one last read when the lead's
turn stops, so a result written late still names the close.
* feat(native-chat): answer workers' approvals from the coordinator chat
A worker's open permission prompt appears as a card at the end of its coordinator's chat, drawn
from the escalation payload as soon as it is stored. The person allows or denies it there; the
card's buttons answer the worker's own prompt over the desktop app's IPC, so only a person can
allow. Once answered, the card turns into a receipt saying who answered.
* fix(orchestration): read a terminal prompt's countdown when it is first escalated
* refactor(orchestration): give a terminal prompt's hold state its own module
* fix(native-chat): let a worker's approval card answer, and drop it once it lapses
The window's runtime calls never carried the orchestration contract
version, so the card's Allow and Deny were refused as an obsolete client.
The renderer ships with its main process, so desktop IPC states the current
contract. An open card whose agent's own countdown has passed, with no
closing message (the app restarted while it was open), is no longer shown.
* test: say why the desktop fence test's runtime stub is enough
* fix(orchestration): a chat worker's approval asks to allow its tool, like a terminal worker's
* fix(native-chat): pause the approval countdown while the window is hidden
* chore(i18n): protect the approval card's worker line copy
* fix(orchestration): close a terminal prompt's card as soon as Orca can't answer it
When the dialog leaves without an answer through Orca, the closing line is
published at once, so the coordinator's card becomes a receipt; a tool
result that arrives later adds a second line naming how it closed, without
waking the coordinator. On startup, open terminal prompts left by an earlier
run are closed the same way, since their holds lived in memory. A Claude
terminal card's reason is the warning Claude prints under the command.
* fix(orchestration): keep the dialog-warning patterns ASCII for the orcad bundle
* fix(native-chat): say when a deny reason reached the worker as a separate message
A coordinator's deny reason for a chat worker whose prompt takes no message is sent
as mail. The receipt showed it the same as a reason that went with the denial, so it
now labels it 'Reason, sent as a message'.
* chore(native-chat): follow main's moved window-activity and agent-session modules
* fix(orchestration): only Orca's own reports draw approval cards, and every card closes
- Cards and the startup sweep read approvals only from rows whose id is the stop report's own
stable id for that approval, through one shared parser; a worker's send cannot draw a card.
- A chat worker's card closes as soon as its own chat answers it (a journal watch replaces the
turn-edge check), when an answer finds the prompt already gone, and after a restart.
- A terminal coordinator is told nobody was shown the prompt and to tell the user; the
terminal-only close asks the same and goes out as an escalation.
- A chat coordinator's line names only the answers its card offers; a prompt with none is a
plain prompt with no card.
- A person's Deny on a chat worker mails no extra reason.
- A record a quit or budget end closed stays closed.
- One closed-approval builder; `waitingOn` becomes `awaitsReply`.
* fix(orchestration): a failing read cannot hang an answer, fail a stored send, or fail the database open
* refactor(orchestration): add the held-send line in send-delivery-hold, keeping send-methods under the size cap
* test(orchestration): read the worker's mail with a schema, not a cast
* fix(orchestration): an open approval stays visible and closes even behind many closed ones or a missing database
* feat(orchestration): records, import and settlement for workers a paired server owns (inert until B5)
* fix(orchestration): name the re-pair when a closed link refuses a send
* feat(orchestration): offline reads of workers a paired server owns (inert until B5)
worker-show from this Orca's record when the server can't be reached, labelled
with the server and when it last reported; remote rows in worker-list named by
server; unreachable failures said in the server's terms, apart from the
server's own unknown outcome.
* fix(orchestration): remote rows share the page limit, label re-made pairings, and say what the record's time means
* fix(orchestration): keep remote rows in every page's total, date the record by state only, and retry only by request ID
* chore(orchestration): annotate the remote count query's row type
* test(orchestration): check CLI views of remote workers at the CLI layer
* docs(orchestration): say remote rows get their own page limit
* feat(orchestration): run commands about a paired server's workers there, and switch new pairs to it
* feat(orchestration): offline show and server-named failures for forwarded commands
* fix(orchestration): forwarded start timeout, receipt Run and stop key in the caller's terms
* fix(orchestration): forwarded answers name this Orca's Run
* fix(orchestration): a remote worker's question is answered only by its Run's coordinator; tests for the forwarder
* fix(orchestration): a start answered after its Run was reset says so
* fix(orchestration): refuse a chat session terminal before asking any server; test the late start after a reset
* test(orchestration): lint
* fix(orchestration): review fixes for the forwarder: retry-of stays local, legacy retries stay legacy, unknown outcomes stay fenced, refused starts leave no Task
* chore(orchestration): no type assertions in the forwarder
* fix(orchestration): a start answered after a re-pair frees its Task
* fix(orchestration): worker-show of a worker whose pairing was re-made gives this Orca's record
* fix(orchestration): a retry with --on names the server's Task instead of resending its spec
* fix(orchestration): a read about a remote worker gives up within seconds on a sleeping server
worker-show then answers from this Orca's record, as it does for a server that is off. Changes keep their longer wait.
* fix(orchestration): a refused remote start keeps the Task it created, failed
A local start that fails after creating its Task leaves it failed; deleting it here left any dependent added while the start waited pointing at nothing.
* fix(orchestration): worker-show of a remote worker reads this Orca's record, never its server
Show answers at once whether the server is awake, asleep or off, and agrees with worker-list.
Its note says when the record is from and what the pull loop last heard from the server; a
prompt wait already arrives as the server's mail. worker-read stays forwarded with its 5 s cap.
* refactor(orchestration): drop the orphaned-start lookup; the server's queue item adopts a lost start
A start whose answer was lost stays reserved until the server's dispatch-insert item names its
Dispatch, which adopts it. The 30 s dispatchShow lookup and its two placement columns repeated that.
* fix(orchestration): a stop or abandon the server does not answer settles the Task here at once
As a local stop does, the Task goes blocked so it can be retried, and the stop stays owed with its
count. The first result stands: a later state from the server changes only the attempt's record.
* fix(orchestration): task-update on this Orca's own Task applies here, by the local rule
A Task placed on a paired server is this Orca's; its update goes through the ordinary owner, which
refuses it while the worker there holds it, exactly as for a local worker. Stop first: an
unanswered stop settles the Task here at once. Nothing is forwarded to the server.
* fix(orchestration): a link that can no longer answer fails the Tasks it held, with the reason
When a re-pair closes a link, or its server is removed from this Orca, each Task a worker there
still held fails here through the ordinary Task half ("The pairing with devB was re-made. Its
worker may still run there."), and its placements go. Before, the Task stayed dispatched for good.
* fix(orchestration): a paired Orca's reads on this server are no longer narrowed to its Run
* test(orchestration): a lost start is never looked up on its server
* fix(orchestration): review fixes for the remote Task settlements
- An abandon the server does not answer stops nothing, as a local abandon: it settles the Task here
and owes no stop, with abandon's own receipt.
- A link a re-pair or removal closes tells the Run's coordinator about each Task it failed, as a
local worker failure does, naming the server in the reason.
- An unreleased database drops the placement lookup columns and gains task_settled_here on open.
- A failure settling a removed server's Runs no longer ends the pull loop's bookkeeping.
* fix(orchestration): retries of a remote attempt follow the local rule, and owed stops go out on reconnect
A retry here may follow the Task's attempt on a paired server once it settled there or was
abandoned here, exactly as a local retry follows a local prior; an unproven stop, like a local
stop_unknown, leaves nothing to follow yet. When a server answers again, every stop and cancel
owed to it is due at once through the existing resend, so a retry there follows the proven stop.
* fix(orchestration): a re-pair settles held Tasks at once, lists the Run there, and refuses reuse of its Tasks
- the pull loop closes links of a changed pairing, so their held Tasks fail without a call through them
- worker-list --on lists a Run's workers by its server Run even after its link closed
- a start --on of a Task placed through a closed link is refused here, naming the server
- the server's restart recovery readies its Task, and this Orca follows as the local rule does
- a closed link's note gives why it closed and the server's recorded name
* fix(orchestration): review fixes for the re-pair settlements
- worker-list picks the Run's latest link a server Run answered for, so a refused start's new link hides nothing
- a start answered after a re-pair keeps its placement, so the Task's next start there is refused here
- worker-list --on errors read in this Orca's terms, as other forwarded reads do
* fix(orchestration): a re-pair fails a Task a stop left blocked, and a reset still fails a readied Task
- a closed link also fails a held Task an unanswered stop blocked, which nothing can prove now
- a server reset's removal fails the Task even after its recovery readied the server's Task
- a closed link keeps why it closed when a later queue item cannot be read
* fix(orchestration): a re-paired Run's worker-list says so plainly, with no new read path
- worker-list --on for a Run whose link a re-pair closed names the re-pair instead of runtime_error or an empty page
- a Task placed through an earlier pairing still starts on another server
* fix(orchestration): a re-made pairing's refusals keep their own error code
server_pairing_changed passes through RPC instead of becoming runtime_error.
* fix(orchestration): a re-pair fails a blocked Task only while its stop is owed
A Task a proven stop or an abandon blocked stays blocked; only an unanswered stop, which nothing can prove now, fails it.
* fix(orchestration): a refused start writes no link, and a re-paired Run's list tells a reset apart
- the refusal of a Task an earlier pairing placed runs before any link is written, so the Run's list still names the re-pair
- worker-list decides from the Run's newest link: closed says re-paired, a reset lists nothing, a link closed mid-call says re-paired
* test(orchestration): a paired Orca reads another Run's work on this server, and still cannot change it
* fix(agents): deliver workspace prompts to dsh-TUI 0.19, which runs as dsh-tui
dsh-TUI 0.19 loads DSH in-process, so no dsh process holds the PTY.
Follow-up delivery only accepted the configured expectedProcess, so the
new-workspace prompt never reached it. Share launched-agent-foreground's
rule (recognized agent or expectedProcess) with follow-up delivery.
* fix(agents): use the shared agent-foreground rule in every paste readiness fallback
* fix(agents): keep generic launcher names out of the agent-foreground delivery rule
* fix(native-chat): answer Claude/Codex folder-trust dialog from a chat card
* fix(native-chat): show a chat card for Claude/Codex startup menus
* fix(native-chat): keep startup-menu cards holding Send; drop hand-typed identify retries
Startup-menu cards now hold the composer like the folder-trust card, so collapsing one can't free a Send whose Return would pick the highlighted choice.
The hand-typed agent probe retries and agentless hold are left out; Orca-launched panes already know their agent, and hand-typed native Claude identification predates this fix.
* fix(native-chat): read the whole screen for a tall startup dialog's heading
* fix(native-chat): drop the unreachable cwd prompt from startup-menu reasons
* fix(native-chat): show startup-menu warning text and give its choices no default
A startup-menu card now carries the dialog's body (Claude's bypass, API key, MCP and import warnings) under its heading, and its choices render as equals on desktop and mobile so Orca never nudges a consent choice. Long mobile option labels wrap inside their button.
---------
Co-authored-by: Kooooojun <edisonhuang1122@gmail.com>
Kimi Code's --yolo is now Ask When Needed; --auto is its Never Ask mode.
Kimi refuses --yolo (or -y, --yes, --auto-approve) together with --auto,
so a Kimi approval flag the user put in Arguments keeps control.
Co-authored-by: rumoii <123233666+rumoii@users.noreply.github.com>
The workspace watch never follows a symlinked folder, so a tab opened
through one (target outside the root) got no change events. Watch each
such tab's folder directly; main checks for the link with an lstat walk
and already rewrites the folder watch's events to the link spelling.
* perf(emulator): stream iOS Simulator video as H.264
The iOS Simulator pane decoded serve-sim's MJPEG stream (~24 updates/s,
p95 latency 77 ms). serve-sim 0.1.47 already serves /stream.avcc, so iOS
sessions now decode it with WebCodecs (~59 updates/s, 26 ms).
- Main derives the AVCC URL from the session registry by device id; the
renderer never supplies a stream URL.
- A decode-queue backlog restarts the stream from a fresh keyframe; repeated
backlog falls back to JPEG.
- Any H.264 failure falls back to JPEG for that session, including a socket
silent longer than serve-sim's 5 fps idle floor allows. A late idle timer
after sleep gets a fresh window instead of failing.
* test(emulator): drop the wall-clock simulator video stall tests
They froze the event loop and raced real socket timers, which the repo's test
rules forbid; the JPEG fallback they guard is covered in the renderer test.
* fix(emulator): start the simulator video stall timer at the first byte
serve-sim writes nothing on /stream.avcc until capture starts, so a slow cold
start could trip the 3 s stall and pin the session to JPEG. The renderer's
first-frame timeout already covers the wait before the first byte.
* fix(emulator): re-arm the first-frame timeout when H.264 resyncs
A resync opens a new helper connection, and main's stall watch only starts at
its first byte, so a silent reconnect would freeze the canvas with no JPEG
fallback.
---------
Co-authored-by: Kien Le <122910950+kien-ship-it@users.noreply.github.com>
The catalog's Install link opened DeepSeek's site, which installs only
dsh. Orca launches the community @deepseek-harness-tui/dsh-tui, so users
either stayed undetected or guessed the dead unscoped dsh-tui package.
* fix(browser): forward Orca shortcuts from focused HTML document previews
Workspace-document preview guests never installed the guest shortcut
forwarder that browser pages and plugin frames use, so once a preview
took focus Ctrl+Tab and the other window shortcuts stopped reaching
Orca. Install it in attachWorkspaceDocGuestPolicies, bound to the
preview's own host, with browserPage: false so browser-page chords stay
with the document, and dispose it with the rest of the doc policy.
* test(browser): pin Ctrl+Tab forwarding from a focused HTML document preview
* fix(browser): activate a document preview's split when it is clicked
A press inside the preview never reaches the host DOM, so forwarded
shortcuts such as Close acted on whichever split was active before.
* refactor(browser): read a document preview's page id from its guest policy
---------
Co-authored-by: agustin2606 <agustinvarela2606@gmail.com>
A switch made from Orca Mobile or the CLI opened the 'restart running sessions?' dialog on the desktop, where the person switching can't see it. Under the 'Ask' setting these switches now restart the moved sessions the way 'Always restart' does: each waits for its turn to end and resumes its conversation on the new account.
An old mobile app lists a desktop-created structured chat it cannot render
with the title 'Update to view', which doesn't say whether the phone or the
desktop needs the update. Name the phone app, and document the symptom and
recovery steps in the mobile troubleshooting docs.
* fix(daemon): stop the macOS logout watch writing a login record every two minutes
The watch ran /usr/bin/login as its session-health probe, and each run adds an
entry to the macOS login history. Check DNS health first and only run the login
probe when the resolver already looks dead, which retirement requires anyway.
* fix(daemon): keep probing login after a rejection until PAM accepts again
Gate on the last login verdict instead of the rejection streak, so a sleep reset
of the streak cannot leave a rejected verdict cached while DNS looks healthy.
* test(daemon): keep coverage for not retiring once DNS recovers
* test(daemon): drop the duplicate retirement replay from the resolver gate test
* fix(agent-status): skipping a Codex async question clears it on SSH panes too
An SSH pane's Codex hooks are normalized by orcad on the host, so the
desktop's own hook server had no row to apply the skip keystroke to. The
renderer now sends a remote pane's skip to the owning runtime through a new
terminal.inferCodexQuestionSkip RPC, which applies it to the host's tracker.
* test(e2e): skipping a Codex async question clears a managed SSH terminal's row
The Source control empty state named the base by its fully qualified ref ('…no changes ahead of refs/remotes/origin/master'). Show it the way people know it ('origin/master') with a small shortRefLabel helper.
* fix(cursor): read the default marker in cursor-agent model rows
* feat(agent-launch): list a terminal-only agent's own models in the launch picker
* fix(agent-launch): cache Cursor listings and keep the seed for fallback lists
* fix(agent-launch): keep the host catalog for agents that have structured chats
* refactor(agent-launch): resolve the picker's discovery runtime once per render
* style(new-workspace): icon-only Create From tabs and shorter Create button
* style(new-workspace): let Tabs primitives own source-tab spacing
* chore(i18n): add Create button label to English catalog
* fix(session-history): index Codex rollouts archived as .jsonl.zst
Codex compresses rollouts idle for 7+ days to rollout-*.jsonl.zst. The
session scanner only discovered .jsonl files, so every Codex chat older
than about a week disappeared from Agent Session History. Discover .zst
rollouts, decode them through a shared zstd stream wrapper above
openTranscriptReadStream (native, WSL UNC, and SSH alike), never resume
a compressed archive from an offset, and drop a .jsonl.zst candidate
when its plain .jsonl twin is listed, matching Codex's own rule.
* fix(session-history): admit only rollout-named zst archives and close raw zstd streams early
Review follow-up on #40593: a filePredicate limits compressed discovery
to rollout-*.jsonl.zst so unrelated .zst files are never decompressed,
and zstdTranscriptStream links the raw and decoded streams with pipeline
so an early close of the decoded stream releases the raw stream's fd.
* fix(session-history): cover archived Codex rollouts by compressed size and collapse .zst twins in every listing
Archived rollouts keep the bounded resumable reader but never resume, and report their compressed stat size as the read cursor, so search coverage checks match. The .zst suffix is dropped from Codex alias keys with the plain file preferred, which also dedupes scoped walks and rollouts archived in only one home.
* fix(session-history): prefer the live rollout over an archive in another Codex home
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
* fix(native-chat): open and reveal folder links instead of doing nothing (#40675)
* fix(native-chat): reveal folders in their owning worktree and localize the no-route toast (#40675 review)
- Activate a folder's owning worktree before revealing it: the explorer only
reveals inside the worktree it shows, so a paired host folder in another
worktree stayed hidden.
- Reject a paired folder outside the worktree root (e.g. a chat scratch
folder): the explorer drops those reveals, so report the unavailable route
instead of returning silently.
- Add an `unavailable` FileOpenFailure verdict with its own localized toast,
replacing the English error string that other locales would show.
* fix(native-chat): report a folder the OS could not open (#40675 review)
`openFilePath` returning false or rejecting left a local folder click with no
feedback. The directory route now reports the unavailable path in both cases,
with a test covering a refused local folder open.
* fix(native-chat): reveal SSH folders in the explorer and report a failed Shift-open of a folder
Folders below an SSH workspace root still ended in a 'can't open' toast;
the workspace explorer reads through any host, so it shows them. A
Shift-open of a local folder that the OS refused returned silently.
The trailing-separator hint now also hides the download row.
* fix(native-chat): match the owner's host and explorer spelling when revealing a folder
A same-ID workspace on another host counted as already selected, a
superseded folder click could still toast after a newer one, and an
SSH reveal used the chat's separators instead of the explorer's.
* fix(file-explorer): reveal a target spelled with other separators, and skip duplicate folder rows and toasts
The explorer built a reveal's ancestors in its root's spelling but
looked the target up as given, so a forward-slash path under a Windows
root selected nothing. A local folder link no longer repeats its open
as 'Open with default app', and a blocked folder workspace no longer
toasts twice.
---------
Co-authored-by: Pr1p <zwq19980411@gmail.com>
* fix(speech): keep the old model when the new one can't be moved in
Deleting the old folder before the rename lost both copies when the rename
failed, e.g. a Windows antivirus lock.
* fix(speech): keep an interrupted swap's backup and let delete wait for it
Retry renames through Windows file locks, and keep .previous when it is the
only old copy left.
* fix(speech): remove the migration source's model backup on delete
* test(speech): assert the kept model, not the backup folder name
* refactor(speech): remove each model folder's leftovers in one loop on delete
* fix(speech): check model folders with async stat during the swap
* fix(azure-devops): recognize vs-ssh.visualstudio.com SSH remotes
Organizations on the older visualstudio.com URLs clone over SSH with
<org>@vs-ssh.visualstudio.com:v3/<org>/<project>/<repo>. The repository
parser only accepted ssh.dev.azure.com, so these remotes parsed to null
and the repo got no Azure DevOps pull request or status features.
Accept vs-ssh.visualstudio.com in both the SCP and ssh:// forms, and
resolve it to the same reference the org's https://<org>.visualstudio.com
remote already gets.
Fixes #ISSUE
* fix(azure-devops): validate vs-ssh org names and fix renderer PR links
A vs-ssh remote's org becomes the API hostname that receives the Azure
DevOps PAT, so reject anything but a plain org name. The renderer's
manual PR link parser also missed vs-ssh remotes and built a link on
vs-ssh.visualstudio.com; resolve it to the org's visualstudio.com repo.
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
* fix(orchestration): a worker report during an Orca restart is not rejected as a changed identity
* refactor(orchestration): share the startup bounded wait; skip long-poll checks
* chore(orchestration): drop casts in the restart identity wait
* fix(orchestration): only long-poll checks skip the restart identity wait
* fix(orchestration): ordinary mail never waits for the restart identity restore
* fix(bitbucket): connect access tokens and API tokens without account access
Bitbucket answers GET /2.0/user with 403 for a credential it accepts but
that has no account access: every repository, project or workspace access
token, and API tokens without read:user:bitbucket. Orca treated that 403 as
a rejected credential, so those tokens could never connect. Only 401 now
means rejected; 403 connects without an account name.
* test(bitbucket): type the 403 fetch stub without a cast
* fix(bitbucket): accept a /user 403 only when Bitbucket sent it