Repository navigation
Conversation
…ai#28655) * feat(native-chat): image messages wait in the queue like text A message with images now queues behind the running turn and the cards ahead of it, instead of skipping the queue. Cards show an image icon and count, an image-only card names its image, and editing a card's text keeps its images. The host publishes no card holding an image to a client that has not advertised agent-session.queued-image-cards.v1, since released clients edit by copying a card's text and deleting the card. * test(native-chat): an image follow-up queues like text * fix(native-chat): project queued images before phone frame limits * fix(native-chat): preserve image sends from older clients * Clarify direct text recovery at send admission * fix(native-chat): expose queued image names to keyboard users
…and fit the force-delete button to its notice (stablyai#29878) * fix(sidebar): let kept-branch toast bodies fill the toast width * fix(sidebar): close the force-delete menu when its toast is hidden in the stack * fix(sidebar): keep focus out of a hidden toast after its menu auto-closes When the toast stack hid a kept-branch or delete-failure toast, the menu closed but Radix returned focus to the chevron inside the now invisible toast, so Enter or ArrowDown reopened the menu floating over the app with the "Always ..." item focused. - Skip the close focus return while the toast is hidden. - Refuse to open the menu while its toast is hidden. - Treat toasts past Sonner's visible-toast limit (data-visible=false) as hidden too. * fix(toasts): stop a folded toast's hidden overflow from re-expanding the stack * fix(toasts): clip a folded toast to its card instead of disabling its content The pointer-events rule left the unstyled star-nag card, which Sonner never fades, visible below the stack but dead to the pointer. Clipping the folded toast removes the overhang for every toast type, visible or not, so nothing of a folded toast can sit outside the stack and re-expand it.
…drop the floating 'Agent is working' pill (stablyai#29972)
…ntity rekey (stablyai#30005) Main's Store.migrateWorktreeIdentity re-keys every stored layout field before it sends the rename event the window re-keys on, so the window's save only mirrors it. The new oracle checks main's migrated layout model equals the model of the window's post-rekey save and the model's identityRenamed transition; the first-work test pins migrate-before-notify.
…newest release defines it in (stablyai#30000)
…ver keeps running (stablyai#30006) A paired runtime (orca serve, managed SSH/WSL orcad) owns its terminals and keeps them after this client quits, so only SSH relay terminals, which a relay kills after its grace period, still raise the quit warning. Window close is unchanged. Fixes stablyai#29916
…stead of guessing this computer (stablyai#30009) * fix(renderer): resolveOwner keeps folder and project-group twins ambiguous; deprecate the runtime-owner aliases * test(store): folder and project-group twins in the twin suite; no-host folder delete refuses * fix review: a folder's own SSH connection names its owner despite twin project groups
…e stand-in (stablyai#30011) * test(e2e): open and close structured chat tabs through an isolated Claude stub * test(e2e): satisfy changed-code lint in the structured chat stub
…#30012) The hostScope annotation on terminal list, worktree list and worktree ps named --host local / --host ssh:<id> as the follow-up for an omitted host, but none of those commands accept --host. Those hosts are reached through the runtime that answered, so no flag selects them: report a null selector and say so in the human scope line. Paired servers keep --environment. Fixes stablyai#29901
…tablyai#30014) On a headless server (orca serve, orcad) files.open and files.openDiff answer with the bare renderer_unavailable token, which the CLI printed as-is. Translate it in the CLI into a clear message with next steps, keeping a stable renderer_unavailable code. The wire answer is unchanged because the mobile app keys its preview fallback on it. Fixes stablyai#29822
stablyai#30002) * chore(ci): ratchet renderer importers of the deprecated runtime-owner resolvers getRuntimeEnvironmentIdForWorktree and resolveRuntimeOwnerForWorktree read a worktree two hosts publish as not-a-runtime, which callers treat as local. The 62 renderer files importing them are grandfathered; the list may only shrink. * ci: register the deprecated runtime-owner ratchet step in the preflight phase map
…9089) * fix(native-chat): paste a copied file into Chat the way dropping it attaches it Copying an image file in Finder and pasting into Chat typed the file name and attached nothing: the paste only attached a bitmap from the clipboard. Copied files now go through the composer's drop route, on both the app-menu paste and the paste event. Fixes STA-10652 * refactor(native-chat): share the paste guards with the copied-files branch * test(native-chat): late paste results stay dropped when the image waits for the clipboard read * Keep copied attachments pending through preparation and composition * Update file drop fixture settlement results * Keep pending attachment capability current within its draft scope * fix(native-chat): reserve pending chips before checking dropped files A local file drop checked each file before adding it, with nothing in the composer meanwhile: Send during the check went without the file, which then landed in the next draft; unmounting mid-check lost it; and files queued behind an input-method composition were lost on unmount. Drops now reserve a pending chip per file before the check, so Send waits as it already does for server-upload drops. The prepared attachment travels through the existing composition queue as one operation, settles into its draft scope after unmount, releases its chips when refused or disabled, and reads the scope's current image capability when it applies. * test(native-chat): server-upload chip calls carry no options without paste * refactor(native-chat): move the composer's image chip list into its own hook Main's server-owned paste pushed the attachments hook past the file length limit. * fix(native-chat): a screenshot picture pastes as a picture on macOS, even beside its saved file macOS lists a screenshot tool's saved file beside its picture, so the paste read as a file copy and attached nothing once the file was gone. Only a Finder copy also names its files as text. * fix(native-chat): a macOS right-click paste lets the clipboard tell Finder files from a screenshot The paste event hides Finder's file names, so a path-backed picture reserves its chip at once and the native clipboard decides: named files go to the drop route, a screenshot's picture is saved from the clipboard. Both paste routes now share the clipboard-picture save. * test(native-chat): move the paste hook's test probe into its own fixtures file The paste tests outgrew the test file length limit. * test(native-chat): hand the paste probe's hook result out after render * test(native-chat): give the remote image paste probe the copied-files callback * fix(native-chat): a pending attachment chip shows a spinner and its name, not a stacked icon A local drop now waits as a pending chip, which drew the kind icon, the file name and a centered spinner on top of each other. Without a thumbnail the chip shows the spinner above the name; with one, the dimmed picture keeps a spinner strip along its bottom. * test(native-chat): a pending chip shows its name and spinner, no kind icon * fix(native-chat): a macOS file paste keeps its own chips until the clipboard decides A macOS paste of Finder files reserved one placeholder chip, asked the native clipboard whether it held files or a screenshot picture, and then started a separate attach for the files. Removing the placeholder did not cancel that attach, and leaving the chat before the answer lost the paste. The paste now reserves one chip per copied file before asking, and captures the drop route's intake (owner, destination, chips) at the same moment. Files continue those exact chips through the existing local check or server upload, so removal cancels by the original chip and an unmounted composer still finishes into its draft. A picture keeps the first chip and drops the rest. Ordinary drops and the picker keep their fresh-admission checks. * test(native-chat): a macOS file paste survives removal, unmount and disable through the real intake Drives the real pending cache, composer attachments, external intake and paste hook with a delayed clipboard answer: removed chips never attach (before or after the answer, through input-method composition), an unmount finishes both the local and paired-server routes into the original draft with the original chip IDs, and disabling the composer meanwhile does not bring the paste back.
…' visit recency (stablyai#30015) Converting an SSH host drops its relay-era rows, but recency stayed under ssh:<target>|<id> keys, which the next startup prune discards because no row matches them any more. Re-key that host's visits to runtime:<env>|<id> in the same update, keeping the newer visit on a collision.
…SH host moves again (stablyai#27285) (stablyai#30017) * fix(ssh): link a folder workspace the server kept from an earlier move instead of conflicting (stablyai#27285) * fix(ssh): resolve a server folder's host before linking it, and read folder lease owners * fix(ssh): name a linked folder workspace in the connect's left-behind warning
* feat(native-chat): choose which agents open as a chat Settings → Chat gets a Providers list. Each agent the host can open as a chat has a switch; off opens that agent in a terminal instead. Only choices the user makes are saved. Unchosen: Claude and Codex on, others on when their CLI is installed on this computer. The renderer's route and the host's launch-mode decision both read one rule, so the tab menu, shortcuts, CLI, orchestration and relayed phone launches agree. * fix: keep chat provider settings with the other chat settings types * test: route input carries this computer's detected agents * fix(chat): resolve provider choices from their owning computer * test(chat): use checked native inventory fixtures * Fix launch preparation lifetime and execution host startup * fix(chat): keep unchosen providers on without discovery * test(chat): type provider routing fixtures against store contracts * test(chat): align shared launch fixture with private settings reader * test(chat): give the structured-session RPC fixture the private settings reader The host now reads saved chat choices through requireStore().getSettings(); the shared RPC fixture only had getClientSettings, so the launch-mode reader saw no settings and create support refused Claude. The fixture now follows each test's client settings. * fix: preserve provider choice and cached native inventory
…rder, and SSH/WSL host state, checked against the window in dev and test (stablyai#30018) * feat(sidebar): main publishes desktop focus, pins, project and host order, and SSH/WSL host state, checked against the window in dev and test * fix(sidebar): read pins through the host-filtered metadata helper; name pins as workspaces
…ly) (stablyai#30019) * Record chat tab opens, closes and host-listed chats in main (dark, layout-owner build only) A chat tab the window opens, closes, or adds and removes from a host listing of this machine's chats now reaches main as openAgentSessionTab, closeTabs or setTabProps under the window's ids, so the window's save no longer teaches main a chat tab. openAgentSessionTab takes the window's place, creation time and new split group, and the same open again changes nothing. Switch-off builds are unchanged. * test(layout): a paired server's chat tabs send nothing to main (dark) * fix(layout): keep a windowless host's chat-tab saves as they were; send synced chat opens in tab order (dark) Only a window's openAgentSessionTab (main marks it drawn on layout.apply) takes the new rules: a repeat changes nothing, a taken id is refused, and a workspace with no group takes the window's. A windowless host's own saves mint a fresh group and keep a chat whose id another tab holds, as before. A host listing's new chats are recorded in tab order, so each open's anchor already reached main. * refactor(layout): one rule set for a chat tab open; the windowless caller names only a group it holds (dark) Drops the per-sender drawn flag. The windowless save passes its remembered active group only when the workspace still holds it, so it mints a fresh group as before. Refusing a taken chat tab id is gated on the build switch: shipped builds still save the duplicate id.
…tart or turn signed out (stablyai#28467) * feat(acp): a sign-in prompt on an ACP agent's stderr ends the start or turn signed out An agent that waits for a browser sign-in prints a link on stderr and blocks for minutes. A launch spec can now name that line (signInPrompt); the connection then closes with a typed sign-in failure through the existing process owner, so a start reads notSignedIn and a running turn fails signed out instead of settling unknown. The matched line, which carries the sign-in URL, never enters the retained stderr tail, errors or diagnostics. * Prevent sign-in URLs leaking from long stderr lines * fix(acp): a stderr line cut at the cap that is not a recognised prompt is dropped, so its URL never reaches the kept tail
…pting (stablyai#30025) * fix(ssh): a host that needs a password waits for the user at launch instead of prompting Restores the persisted 'last sign-in needed a typed credential' flag that the relay removal (stablyai#27214) stopped writing, and at launch marks those hosts as awaiting sign-in so background reconnects (startup restore, managed-server status checks and tunnels) refuse without dialing instead of opening the password dialog. The user's own Connect lifts it and prompts. The terminal toast shows the refusal as an SSH state, not a bug to report. Co-Authored-By: Claude <noreply@anthropic.com> * test(ssh): give the raw-connected fixture the cache query; annotate the harness-shaped registration Co-Authored-By: Claude <noreply@anthropic.com> * refactor(terminal): keep the sign-in branch out of the toast component Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
… against the window in dev and test (stablyai#30027) * feat(sidebar): main keeps one live set of paired-server rows, checked against the window in dev and test * fix(sidebar): settle review findings; main also publishes paired-server host facts
…tablyai#28455) * feat(acp): an agent can enforce the permission mode itself through a session config option An optional launch-spec field names the session config option and its ask/full values. Every new or reopened session gets the value for the chat's full-access posture before it is exposed, and a refusal fails the start. With the field present Orca no longer answers permission requests for the person. No agent sets it yet. * fix(acp): reject unconfirmed permission mode during acquisition * feat(acp): an agent enforcing the permission mode itself runs the chat's own mode The launch spec maps each chat permission mode to its session option value; a start sets the value for the mode the host launches with (ask when it names none), replacing the global Agent Permissions full-access read. A mid-chat change takes effect through the host's existing restart of a child launched with another mode before the next send. * Keep ACP session acquisition within the line limit * fix(acp): a chat's permission mode goes to the agent's mode-category option, whatever the agent names it
…#30008) * fix(mobile): the chat's Working line uses desktop's spinner (turning circle, hourglass under reduced motion) * fix(mobile): keep working animations off interaction queue
…tablyai#30029) Naming a chat runs a one-shot agent CLI request in the chat's folder, and the CLI saves it beside the user's chats. Session History listed it, and opening it from a phone resumed the naming request instead of the chat. Fixes stablyai#29973 Co-authored-by: Claude <noreply@anthropic.com>
stablyai#30028) On a host with no window, chat tabs live only in the runtime's session snapshot. A forced rebuild from the saved session (closing a saved editor tab, an expired SSH reattach) dropped them, and every terminal-only group merge removed them from the tab order. Refs stablyai#29968 Co-authored-by: Claude <noreply@anthropic.com>
…the window in dev and test (stablyai#30026) * feat(sidebar): main produces per-workspace PR facts, checked against the window in dev and test Co-Authored-By: Claude <noreply@anthropic.com> * refactor(sidebar): share the PR cache key candidates instead of splitting an import Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…on retap and revisit (stablyai#30033) * fix(mobile): prevent markdown and file tab reload and screen flicker on retap and revisit * fix(mobile): preserve newer saves and refresh document metadata * test(mobile): supply current document state in recorded reads --------- Co-authored-by: Neil <neil@stably.ai>
…top renames (stablyai#30037) A desktop connected to a remote Orca server kept its own copy of a tab's manual name, and ranked its saved-session title (a resumed Codex chat) above the live title the server publishes. So orca terminal rename on the server never showed on a resumed tab, and a desktop rename never reached the server. The server now publishes the tab's manual name as an optional customTitle on each terminal surface, and the desktop mirror adopts it. Desktop renames go to the server: terminal.rename by handle, plus session.tabs.setTabProps customTitle by tab id for panes that are asleep or starting. Older servers omit customTitle and strip the new param, so the desktop keeps its own name with them, as before. Fixes stablyai#29975
…ld only) (stablyai#30036) In a layout-owner build the window's chat-pane pick (chatLeafId) reached main only through its session save, so a frame could undo it and the save changed main's layout. The window now records it with main's existing setChatPane command. Codex restart and background-agent pane trees are already written by main; tests pin that. Co-authored-by: Claude <noreply@anthropic.com>
…ts CLAUDE_CONFIG_DIR (stablyai#29890) * fix(accounts): follow an Orca Claude account switch when the shell sets CLAUDE_CONFIG_DIR A user whose shell config or environment sets CLAUDE_CONFIG_DIR switched Claude accounts in Orca, but `claude` relaunched in an open terminal kept running the old account: the terminal's claude function treated any CLAUDE_CONFIG_DIR it did not inject as a deliberate per-terminal override. Host terminals now always carry the user's own folder (ORCA_CLAUDE_USER_CONFIG_DIR, from the login shell's env), also on System default and before that env arrives. The claude function (POSIX, fish, PowerShell) treats a CLAUDE_CONFIG_DIR equal to it, ignoring a trailing separator, as System default's folder and follows the selected account; any other value set in the terminal still wins. WSL panes carry no user folder, so they behave as before. The terminal daemon protocol moves to 49: hourly builds already run v48 daemons whose wrapper has the old function. v48 stays attachable. * fix(accounts): match the user's Claude folder on PowerShell whatever its separators Orca records the user's CLAUDE_CONFIG_DIR resolved (backslashes on Windows), so a pane value written with forward slashes read as a deliberate override and stopped following the account switch. Co-Authored-By: Claude <noreply@anthropic.com> * fix(claude): pass the user's own CLAUDE_CONFIG_DIR to terminals exactly as set Claude keys its login by the literal folder string, so a resolved spelling (a dropped trailing slash) could switch System default to another saved login, and Git Bash on Windows compared a backslash spelling against its rc's forward one. * refactor(claude): one reader decides whose CLAUDE_CONFIG_DIR it is; one base pane env The resolved reader now derives from the as-set one, every host pane env builds on one base patch, and the router tests share one shell probe. --------- Co-authored-by: Claude <noreply@anthropic.com>
…e desktop has no page (stablyai#29956) * fix(mobile): wall hosts that cannot serve the page instead of opening native screens * refactor(mobile): drop the native-route state and the shell fallback prop; unknown routes say unavailable * test(mobile): read the nullable page route refusal in its policy test
…k, layout-owner build only) (stablyai#30439) * fix(layout): a CLI split whose pane main closes before it mounts answers at once (dark, layout-owner build only) * test(layout): the closed-before-mount split fails because of the close
…ght seams from their defining modules (stablyai#30440) The three ipc modules re-exported symbols owned elsewhere. Importers and test mocks now name the defining module, and the re-export lines are gone (no barrels).
…ting would stamp (stablyai#30445) A tab restored before its worktree catalog loads gets a placeholder row. SSH placeholders had no host, and a server's nested-SSH placeholder carried only runtime:E, so an ssh: host selection found no matching owner and routed the terminal as a direct dial from this desktop. Stamp the SSH target, and the server proxying it, from the repo row; leave a repo id that lives on several hosts unstamped.
…s the whole page and clicks land under the cursor (stablyai#30437) * fix(browser): a remote viewer larger than the host's browser pane sees the whole page and clicks land under the cursor Fixes stablyai#30341 * test: note why the screencast double is cast * fix(browser): drop guest frames until the fitted size is applied; forget the cached CSS size when the frame size changes * fix(browser): keep a press's release and markup inside the letterboxed remote frame * fix(browser): resume live frames once fitted metrics land; remeasure the page after its frame size changes
…its own host's copy (stablyai#30447) applyCreatedWorktree merged a create into any same-id row, so a local create could inherit a server twin's stamp (or wipe it). Lineage refresh stamped a server's reply with the focused host and replaced every same-id row, overwriting the local twin. Both now match id and host, and the lineage reply is stamped with the transport it came from.
…e-SSH (stablyai#30441) * fix(open-in): open a managed server's workspace in VS Code over Remote-SSH (stablyai#30332) * fix(open-in): only open a server workspace over SSH when its files are on that host; validate the SSH link; let process-host quote code.cmd * test(open-in): expect the workspace ref in the source-control Open in payload * fix(open-in): pin an SSH-access server's editor host to the settings it was verified on
…nd cancel, on every Orca sign-in button (stablyai#30410) * fix(cloud-auth): show the browser sign-in wait and offer its link from Relay sign-in Clicking 'Sign in for Relay' handed the sign-in page to the OS browser and then showed nothing, so a browser that never came forward looked like a dead button, and the 5-minute wait ended silently. The Relay sign-in row now shows the wait with a Copy sign-in link button, and a wait that times out toasts. STA-10940 * fix(cloud-auth): show the sign-in wait on every Orca sign-in button The waiting text and Copy sign-in link now come from one shared notice used by Mobile Relay, Orca Account, Artifacts (settings, page and publish popover), Share Skills, the unexpected sign-out card and dev tools. The copyable link is dropped as soon as the browser answers, and a copy with no waiting link reports a failure instead of doing nothing. STA-10940 * refactor(cloud-auth): main owns the waiting sign-in link; renderer only mirrors it The notice now shows exactly while main holds a live link: main announces the link when the browser wait starts and clears it the moment the browser answers, so 'Waiting for sign-in in your browser' no longer outlives the wait during the token exchange. Only the newest attempt may publish its link, so an older attempt reporting late cannot replace or later wipe it. The renderer's separate pending flag and its resets are gone. STA-10940 * fix(cloud-auth): tolerate a sign-in link read that returns no promise The app-wide IPC tests stub every bridge method as returning nothing, and the one-time link read called .then on that result. STA-10940 * fix(cloud-auth): a torn-down link subscription ignores its late snapshot; restore auth bridge tests A window's one-time sign-in link read could land after its subscription was disposed and overwrite a newer value from the replacement subscription. The auth-status refresh tests the earlier rewrite dropped are back, alongside the link cases. STA-10940 * feat(cloud-auth): sign-in buttons show Signing in… with copy-link and cancel links Every Orca sign-in button greys out to 'Signing in…' with a spinner until the sign-in ends. While the browser has not answered, a line offers 'Copy sign-in link' and 'Cancel'; Cancel aborts the browser wait so a lost tab never locks the button. Main owns the in-flight sign-in (waiting on the browser, then finishing) and every window mirrors it. STA-10940
…g unpriced models (stablyai#30421) normalizeModelForPricing was an ordered chain of regexes in which a new point release fell through to its major: claude-sonnet-5-5 was billed as Sonnet 5 (cache reads at $0.20 instead of $0.10), and any future opus-5-x / fable-5-x would be too. claude-haiku-5-5 matched nothing and silently added $0 to a total that showed no caveat. The resolver now parses family + major + optional minor (family-first and legacy version-first IDs) and only accepts an exact MODEL_PRICING key, so an unknown version is unpriced rather than borrowing another model's rates. The deliberate opus-4.x -> 4.8 and sonnet-4.x -> 4.6 fallbacks go with it. Adds Sonnet 5.5 and Mythos 5/5.1 rows. Haiku 5.5 stays unpriced: it reprices a whole request above 100K prompt tokens, which daily totals cannot express. The Claude summary now carries hasUnpricedModels (as Codex has since stablyai#22073), and both panes share one unpricedCostLabel helper for the caveat. Fixes stablyai#30338
…tablyai#30446) * Check sign-in duplicates against the listed account identity A managed account folder's current Claude login can differ from the identity saved for it. The account list shows the current login, but the duplicate check compared the saved identity, so a sign-in could be missed or wrongly flagged. Duplicate detection now uses the same listed accounts as the account list, and the duplicate helper accepts account summaries. Tests cover a folder whose login email changed, and one where only the organization changed. * Tolerate invalid Claude account rows during sign-in
… Haiku 5.5 (stablyai#30427) * fix(usage): price Claude long-context requests per request, and price Haiku 5.5 Haiku 5.5 bills a whole request at higher rates once its prompt (input plus cache reads and writes) exceeds 100K tokens. Claude usage was only kept as daily totals, so that could not be priced and Haiku 5.5 stayed unpriced. The existing Sonnet 4.5/4 200K tier had the opposite problem: it was applied as a marginal threshold to each day's totals, so a day of short requests could be surcharged and a single long request was under-charged (the Claude side of STA-8117, fixed for Codex in stablyai#22360). Each turn is now classified when it is aggregated, against its own model's threshold, and daily and per-location rows carry the long-context subset as an optional `longContext` field. A streamed turn that grows across the threshold moves its whole share in the resume correction. estimateCostUsd takes one token object and bills that subset at the long-context rates and the rest at base, replacing the per-bucket tiering. Saved per-file projections carry a projection version; files from an older version are reparsed on the next scan, so history picks up the split without touching the signed cache schema. * fix(usage): keep the projection version out of the integrity hash Hashing it made older inline reports fail validation and show the 'could not be validated' error; the scanner's version check alone decides reparse.
stablyai#30450) * feat(sidebar): the owning host raises the workspace unread flag (dark) * fix(sidebar): phone session open clears and spares the flag; refresh views; blur rescan * fix(sidebar): throttle failed view retries, resend failed empty views, hold presence one refresh longer * test(sidebar): switch-on window writes neither the unread flag nor a stamp
stablyai#30456) * fix(native-chat): clicking Send or Stop keeps focus in the composer A click focused the Send/Stop button; when it disabled (empty draft after the turn, or while a Stop is in flight) Chromium dropped focus to <body>. A pointer press on it no longer moves focus, matching Enter. Adds an e2e regression with a turn-capable Claude stub. Fixes STA-10897. * Tighten comments
… PowerShell (stablyai#30424) * fix(windows): codex and claude get a prompt's double quotes in Windows PowerShell Windows PowerShell 5.1 (and pwsh before 7.3) does not escape an embedded `"` when it builds a native program's command line, so every quote in a launch prompt was dropped, and quotes could split the prompt into extra arguments. Orca's PowerShell codex and claude wrappers now escape their arguments at runtime for the PowerShell that is actually running, through one shared __OrcaNativeArgs function. pwsh 7.3+ already escapes, so it gets the text untouched. * fix(windows): escape agent args for .cmd shims under pwsh 7.3+ too pwsh 7.3+ defaults to the Windows argument mode, which still passes .cmd/.bat targets the Legacy way, so a codex or claude .cmd shim kept dropping quotes there. The function now takes the program it escapes for and names the modes that escape by themselves, and anchors the 5.1 trailing-backslash fix at the true end of the text (`$` also matched before a final newline). Tests now run the real codex wrapper with a quoted prompt, cover pwsh's Legacy mode and the newline case, and pin the claude wrapper's call. * fix(windows): strip comment lines from the PowerShell bootstrap payload The shared escaping function pushed the encoded bootstrap to 27,324 of the 28,000-character budget, leaving almost no room for a startup command to ride in -EncodedCommand, so short commands fell back to stdin (the path stablyai#7236 broke). Comment lines document the source but only spend that budget in the payload; dropping them frees 3,732 encoded characters, more headroom than main had. * fix(windows): quote agent args with "" where cmd.exe or Windows PowerShell reads them Escaping embedded quotes as \" let pwsh 7.3+'s .cmd quoting expose a prompt's `&` to cmd.exe, which then ran the rest as a command. Where cmd.exe reads the line, or Windows PowerShell counts quotes naively, the function now quotes the argument itself and writes each quote as "", as process-host's windows-command-line.ts already does. That also delivers text 5.1 used to strip, so its special cases go away. The codex and claude wrappers now come as one fragment with the function they call, the bootstrap test pins the startup-command budget instead of restating the strip, and the cwd-restore comment leaves the payload too. --------- Co-authored-by: Orca Worker <orca-worker@localhost>
…ds, pinned by an acceptance table (stablyai#30451) * refactor(renderer): one owner adapter for the deprecated-resolver folds, pinned by an acceptance table resolveOwnerWithLegacyFallback answers as resolveOwner for a named host and for rows that carry a host stamp, and keeps the deprecated answer (single focused runtime included) for missing and unstamped rows. A full-owner acceptance table pins all matrix cases and asserts the only changes from the deprecated resolver are the designed ones: twins and contested SSH hosts become ambiguous, and a stale hub stamp routes through the server that names the target. * refactor(renderer): the fold adapter shares resolveOwner's named-host rule Clean-code pass: one namedHostForOwnerRef for both resolvers, floating counts as host evidence, and the acceptance test drops non-null assertions.
…ion control holds in both layout builds (stablyai#30432) The control record named a pane no window or main holds. A layout-owner build keeps resume records on main's panes, so a record for no pane only exists when loaded from a profile. Relaunch instead of reload, seed that record into the stopped profile, and read the CLI tab's PTY from main's inventory, which both builds report.
…t guest (stablyai#30452) * fix(browser): switch client-hosted profiles with staged guest replacement Squashed from stablyai#30351 by @oliver-mee onto the current main. Fixes stablyai#30350 * fix(browser): fence staged profile guests, release switch grants, carry host profile metadata - A fence during automation retirement now revokes and stops the staged guest. - A failed or late-settling switch releases its execution-host grant so the page can be recreated. - Staging cleanup failures before handover stay visible to executor close. - createPage/restorePage carry host-owned profile metadata to profile-switch-v1 desktops, so recovery and restore can rebuild a switched page. * fix(browser): roll back a switch whose replacement died, and report a lost old guest * fix(browser): resolve client-hosted pages before the server-local target path when switching profiles * fix(browser): a staged profile-switch guest owns downloads it starts while loading * fix(browser): keep the original placement until a timed-out switch settles * fix(browser): rebind the original guest before releasing a rolled-back staged guest * test(browser): type the harness guest release mock * fix(browser): release the replaced generation's download transfers when a switch commits * fix(browser): admit file transfers from a staged profile-switch guest while its switch is pending * fix(browser): release only the replaced generation's download transfers after a switch * refactor(shared): import BrowserNetworkExecutionHost from its own module, no re-export * fix(browser): adopt a profile switch the client finished after the caller timed out --------- Co-authored-by: Oliver Mee <102673257+oliver-mee@users.noreply.github.com>
…owner resolver (stablyai#30458) Open-in owner, execution-host platform facts, doc-preview grants and the activation PTY inventory read the owner through resolveOwnerWithLegacyFallback. Open in now refuses a twin instead of launching it as this desktop's checkout; the others keep reading a twin as not server-owned. A row whose only repo row is a server proxying its SSH target routes through that server. The creation-action policy stays until browser creation folds with it. Deprecated importers 57 -> 53.
…efore startup continues (dark, layout-owner build only) (stablyai#30429) * refactor(orcad): move startOrcad's option and handle types into their own module Move-only: frees room in orcad-entry.ts for the layout-owner load repair. * fix(orcad): run main's duplicate-terminal pane repair at orcad startup (layout-owner build only) orcad builds its own runtime and never called the load-time repair, so an orcad host kept a terminal drawn in two panes. * test(orcad): type the hoisted test state without an assertion * fix(orcad): await the startup pane repair so it lands before reconcile and RPC * fix(startup): desktop awaits the duplicate-terminal repair before the window and RPC start (layout-owner build only)
…e holds (dark, layout-owner build only) (stablyai#30473) * fix(layout): editor file records keyed by path and owner, so two hosts' files at one path stay apart (layout-owner build only) Opening a runtime-environment file at a path a local file already held replaced the local record, the stored-session patch and unsaved drafts matched by path alone, a move took every owner's record of the path, and closing a bare-path tab removed both owners' records. * fix(mobile): a windowless host's editor tab under its owned id shows as active, and retiring it clears the active file (layout-owner build only) * fix(layout): a layout change's tab and pane holds end 15 s after it was sent when main never answers (layout-owner build only) * fix(layout): main's view reads and prunes keep an active file under its owned id (layout-owner build only)
…-page readers off the deprecated owner resolver (stablyai#30478) Thirteen read-routing callers (#4, #5, #10-#20 of the round-3 caller list) read the owner through runtimeEnvironmentIdWithLegacyFallbackUnlessTwin. A workspace two hosts publish is no longer searched on either host. The focus-read ratchet now counts the legacy-fallback adapter, which reads the focused runtime inside an object literal its discovery skipped; the five F1 entries that blind spot pruned come back. Deprecated importers 53 -> 40.
…h/connection/ and ssh/targets/ (stablyai#30479) * refactor(ssh): move the ssh-connection and ssh-target cluster into ssh/connection/ and ssh/targets/ Pure git mv plus import and path-literal rewrites. ssh-connection-utils stays put; the next PR splits it. Co-Authored-By: Claude <noreply@anthropic.com> * test(e2e): keep the release-checkout import at the v1.4.218 path Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
12.10.1 repairs a global-virtual-store slot an interrupted install left without dependency links (pnpm/pnpm#16642); 12.12 adds addMissingPeerTypes. The CI store-mode and terminal-perf gates follow the pin they were measured against, and mobile/ and config/audit-tools record the same pnpm.
… a host's own re-dials (stablyai#30487) * fix(relay): judge the reserve watch's 503 rule on non-drain 503s, not a host's own re-dials The watch counted every director 503, and on 2026-10-18 ~98% were host-rate-limited re-dials that grow with traffic, so it flipped production-gce-c7 back twice with no fault. It now uses the roll ladder's non-drain measure (request_count 503s less drain-return deferrals and host-rate-limited / host-in-flight re-dials from the director's runtime metrics) for both the background and the live samples. A judged minute no runtime-metrics line covers is unverifiable, not zero. Co-Authored-By: Claude <noreply@anthropic.com> * fix(relay): state the reserve watch's metrics coverage honestly and share the metrics read limit Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
* feat(cli): set the title of one terminal pane Adds `orca terminal set-pane-title --terminal <handle> --title <text>`; `--title ""` clears it. The runtime resolves the live handle to its saved leaf and asks the desktop window to name that pane through a new optional notifier hook (`ui:setPaneTitle`). Mounted panes apply it through the same local setter the GUI uses; parked panes get it in the saved layout their next mount reads. The tab's own name is never touched. Rebuilt on current main from stablyai#24755. Co-authored-by: stevelliu <stevelliu@tencent.com> * fix(renderer): a main-owned layout takes a CLI pane title before the window shows it * fix(renderer): a CLI pane title reaches a never-mounted tab with a rootless layout --------- Co-authored-by: stevelliu <stevelliu@tencent.com>
…stablyai#30436) * fix(native-chat): a Claude chat keeps a model its CLI stopped listing Claude Code 2.1.302 stopped listing opus[1m], which still runs, and chats on it moved to the list's default on the next send, effort remapped. The picker no longer derives a replacement from the list: the chat's own model shows as a selected-only entry, its effort read-only, and every send carries both. A real model_not_found reply still recovers: the options answer shows what the reset child runs, so the next send records it. A reopened chat's catalog read lists its own model so older clients that replace one keep it too. Tracked in STA-10947. * test(mobile): drop the send-options capability the options hook no longer reads * test: an unlisted model's saved effort shows read-only at rest, as live, for every agent * fix(native-chat): round-1 review fixes; a new chat's unlisted remembered model falls back as on main - The read-only value predicate keys on the effort row, so the phone's legacy host Permissions row opens as before. - The desktop read-only effort row honours a row kept from the previous model. - A live child with no listing of its own answers with the saved listing's ids, so the read-only effort reads the same live and at rest. - The read-only effort borrows listed rows' effort label and level names. - The host seeds a new Claude chat from a remembered default the saved listing no longer names on that listing's default, effort nearest, as main did; a chat's own saved or running model is never replaced. Tracked in STA-10947. * test: pin the new-chat seed fallback on its typed helper, with no casts * fix(native-chat): round-2: a carried effort moves with a fallen-back model; one guard - An at-rest create carrying an effort but no model, on a remembered model the saved listing no longer names, now moves that effort to the nearest level the fallback model offers, as main did. - A create whose own options name no model, and whose merged options carry none, reads no listing. - The seed fallback keeps one guard and no unreachable branch. - The read-only effort finds its level's name in any listed model's choices. Tracked in STA-10947. * fix(native-chat): a live options read with no record borrows no saved ids and never throws
…the build switch (dark) (stablyai#30461) * feat(sidebar): the desktop window lists main's sidebar inputs, with its own writes shown until main does (dark) Co-Authored-By: Claude <noreply@anthropic.com> * fix(sidebar): a newer write wins in the pending layer, created rows hold the stamped record, writes name their host (dark) Co-Authored-By: Claude <noreply@anthropic.com> * chore(sidebar): move the focus-read allowance with the window list model it moved into (dark) * perf(sidebar): main's sidebar feed publishes a change after a quiet spell at once, not 50 ms later (dark) * test(e2e): the desktop reads-main spec skips on a switch-off build and waits for a frame after collapse --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Upstream
Summary
ELI5 The phone remembers whether you hold or tap the mic to dictate, but it only asked the desktop once, sometimes before it was even connected. Now it asks again when the connection comes up or the app comes back. ## What Changed
refreshDictationModein `use-mobile-sessiNote
innocarpe/orcamainuntil the upstream PR is merged.