Repository navigation
Sync upstream 1.4.214 - #114
Merged
Merged
Conversation
…another machine or boot (stablyai#29952) On a shared home, a peer lock's PID is evidence only on the machine that issued it. Cache retention judged the instance lock and daemon PID records by PID alone, so a second machine evicted the slot another machine's live serve or daemon runs from.
…efault flip (stablyai#29949) * fix(ssh): keep existing hosts' orca CLI control switch off after the on-by-default flip Builds before the flip saved an explicit off as an absent value, so absent=on silently turned on hosts the user had turned off. On the first load after this upgrade, pin every saved host's absent switch to an explicit false and record a one-shot marker in settings so hosts added later keep the new default. * test(ssh): check the saved profile without a type assertion * fix(ssh): say the CLI control switch is on by default for new hosts at the call site too
…ts, not only the desktop (stablyai#29913) useWorkspaceServer keyed the server's status read on the desktop's connection state, so a server restart or update under a connected desktop never re-read what it supports. It now passes the server's computed state. Co-authored-by: Claude <noreply@anthropic.com>
…ath twin's shells, tabs and edits (stablyai#29954) * fix(projects): removing one host's project keeps its same-path twin's shells, tabs and edits Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): close the removed host's browsers, chats and late tabs under a twin id Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): attribute a twin's terminals by every PTY id it keeps, SSH included Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): kill a removed local/SSH twin's shells directly and keep its files out of reopen history Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): prune the removed twin's closed editors from the reopen stack Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): recheck twin survivors after the host call and keep reopen order in step Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): close a removed twin's simulators and prune its closed browsers Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): attribute an unstamped twin browser by its pages' host Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): plan a twin's terminal teardown so PTYs other tabs bind survive Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): treat a null browser host as local and close stale stamped editor tabs Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): a host stamp yields to a PTY naming another host; sweep tabless sleeping records Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): cancel a twin's pending launches, clear its PTY records, prune its local editors Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): an ownerless remote pane blocks a stamp; keep the focused surface on background twin removal Co-Authored-By: Claude <noreply@anthropic.com> * chore(projects): leave closeFile's active-surface choice to closeFile Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): keep the selection fields consistent after twin teardown Co-Authored-By: Claude <noreply@anthropic.com> * fix(editor): closing a background workspace's file keeps the focused surface Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): a file's own host outranks its tab stamp in twin attribution Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): kill only a twin tab's live PTYs and honor a browser's own host stamp Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): skip twin files the removal refresh already closed Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): kill a batch's live PTYs whichever tab the planner chose; background file close keeps focus Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): resolve a removed SSH copy's paired-runtime alias in twin attribution Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): stop the removed host's pane in a tab another host's pane keeps Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): judge a still-present twin surface on its latest evidence Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): apply the removed copy's runtime alias to launches and history; layout-only hints prove nothing Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): repair a selection naming the removed copy's runtime alias Co-Authored-By: Claude <noreply@anthropic.com> * fix(projects): leave single-host selection to the bulk purge; test background file close Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
… as stale (stablyai#29957) The preparation lock reason named only the owner's pid, so a host sharing the repo's disk (an NFS home) read another machine's in-progress preparation as abandoned and discarded it. The reason now carries the writer's machine identity (optional, appended after the fields older builds read); a different or unknown machine is unverifiable, and a reason without one is judged by pid only on a local disk.
…pen terminals (stablyai#29958) * fix(orcad): replace a retired terminal daemon when a client returns during idle shutdown * fix(daemon): drop idle-retired legacy generations when replacing the daemon * fix(orcad): treat a lost or late daemon retirement reply as committed * fix(orcad): settle a lost retirement reply with the daemon itself before replacing it * fix(orcad): bind the replacement to the retired daemon and honor the router fence * test(daemon): type the pending census * fix(daemon): skip the owner check only for a proven-dead endpoint
…say when a conversation isn't found (stablyai#29105)
… still starting (stablyai#29911) The + agent menu waited 5 s for the new tab's terminal and otherwise showed "Couldn't launch X — the terminal did not start." Any slow spawn (Windows, a cold or busy terminal host, a queued spawn) passed through that state and got the false toast before the agent came up. The pane's own spawn already reports a real failure in the pane, so the guess is removed.
…er (stablyai#29946) * fix(sidebar): order sidebar text the same on every device Sidebar names, project labels, project-group names and folder workspace names were ordered with localeCompare, whose result depends on the ICU data bundled with Electron, the phone WebView or Node. Order them with one comparator in src/shared/sidebar-list/text-order.ts instead: case-folded and NFC-normalized, digit runs by value, the rest by code point, and equal text broken by host-qualified id. Co-Authored-By: Claude <noreply@anthropic.com> * perf(sidebar): fold each sort label once per sort; reuse the phone row identity helper Co-Authored-By: Claude <noreply@anthropic.com> * fix(sidebar): ignore accents when ordering sidebar names Accents and case now only break exact ties, so "Éclair" sorts beside "eclair". Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…tablyai#29124) * fix(native-chat): identify the owner when resume create is refused * test(native-chat): consolidate transcript refusal cases * test(native-chat): keep ownership coverage at the launch boundary * test(native-chat): update adoption fixture for early ownership admission * test(native-chat): align resume admission assertions with host ownership * test(native-chat): keep RPC coverage focused on ownership proof * test(native-chat): assert blank request presence before optional source * fix(native-chat): admit the actual CLI source during chat creation * fix(native-chat): satisfy source admission lint checks * test(native-chat): provide the waiting hook prompt * test(native-chat): isolate source admission fixtures from host homes * test(native-chat): canonicalize adoption fixture directories * test(native-chat): preserve early ownership admission in source stack * fix(native-chat): preserve resume refusal behavior and honest transcript feedback * fix(native-chat): retain import read evidence in typed result * fix(native-chat): preserve admitted source and prepared execution home * fix(chat): retain source evidence for dispatched adoption * fix(chat): keep source capture within module limits * test(chat): allow host evidence in create routing * fix(native-chat): admit an unsaved transcript under a linked account folder A missing transcript stayed unresolved while its account root resolved through symlinks, so containment failed and a not-yet-saved conversation showed a load error instead of the unsaved notice. * refactor(native-chat): move the newest-item import window into its own module Keeps journal-legacy-import.ts under the line limit after the source identity observer landed on top of the streaming import. * fix(native-chat): restore the refusal error import lost in the main merge * fix(native-chat): admit Pi transcripts against the root Session History walks A PI_CODING_AGENT_DIR that already ends in sessions, or any custom folder, made admission expect <dir>/sessions while the lookup searched <dir>, so a found conversation was refused. * refactor(native-chat): admit and look up CLI transcripts in one store per account Each agent's import described where an account keeps its conversations twice, once for the path check and once for the lookup, and the two could disagree (the linked-folder and Pi custom-root refusals). The import now names one conversation store per account; the create path resolves it once and both the hook-path check and the fallback lookup judge that same store. OpenCode's store is its exact database.
…e like a sidebar delete (stablyai#23593) * fix(workspace-cleanup): let select-all include the workspace you are in Deleting the current workspace is allowed like any other, so select-all now includes it; a live agent stays excluded. Cleanup removal now hands focus to a surviving sibling after the batch, as the sidebar's batch delete does. Linear: STA-4686 * test(workspace-cleanup): cover focus handoff after the dialog closes and after Delete anyway * fix(workspace-cleanup): move focus off a deleted active workspace as soon as its row is gone * fix(workspace-cleanup): don't reopen a workspace the user left while a cleanup batch runs The per-row focus handoff fired whenever no workspace was selected, so closing the successor's last tab mid-batch re-activated it (and spawned a new terminal) on the next row. Move focus only when the workspace the batch left the user on is actually gone and nothing else took focus. * refactor(workspace-cleanup): move focus off the active workspace when a cleanup delete starts Switch to the successor once, right after the batch rows are marked deleting, instead of repairing an empty selection after each row settles. The active row is no longer active when it is removed, so the store never clears the selection and no later handoff is needed. * fix(workspace-cleanup): never hand focus to a workspace in the same cleanup batch The scan qualifies local rows as host `local`, so their delete state lives under a host-qualified key, while a sidebar row with no stored host only matches an unqualified key. The successor picker therefore saw batch rows as not deleting and could focus one about to be removed, leaving an empty screen once it went. Exclude the batch's own ids directly. * test(workspace-cleanup): use scan-shaped hosts in the active-workspace focus tests Candidates now carry the `local` host the scan publishes, which is what exposed the picker gap. The other-host case also stamps the viewed row with its host so it resolves; before, the lookup missed and the test passed with the host check removed. * feat(workspace-cleanup): confirm before a cleanup delete stops a running agent A cleanup delete (bulk, single row, or "Delete anyway") that includes a workspace with a running agent now shows a step naming those workspaces before anything is queued. The check reads live agent state at click time, attributed like the sidebar so structured chats count too, and re-asks if another agent starts while the step is open. The approved candidate records which agents the user agreed to stop; the per-row preflight that runs right before each delete refuses a row whose agent started after confirmation. With the step in place, live-agent rows join select-all like the active workspace. * refactor(workspace-cleanup): name the agent-stop same-action check * fix(workspace-cleanup): drop an open agent-stop step when the dialog reopens mid-batch * style(workspace-cleanup): match the agent-stop step's heading to the delete step * test(workspace-cleanup): type the cache-hydration mocks in the reopen test * style(workspace-cleanup): let the agent-stop step's heading use the dialog's own typography The changed-lines design-system gate rejects restyling DialogTitle and DialogDescription; the delete step's overrides predate that gate. * fix(worktree-delete): key delete state by the identity the sidebar card reads A cleanup delete names local rows with the 'local' host, so their queued and deleting state landed under 'local|<id>' while a card stored without a host reads the bare id and never showed it. Every delete-state write now derives its key from the store's own worktree record. * refactor(workspace-cleanup): reuse the sidebar delete's focus hand-off Drops the move-focus-before-delete path. Each confirmed row prepares the same prepareActiveWorktreeFocusAfterDelete committer the sidebar delete uses and runs it when that row's own removal succeeds, so the user stays on the workspace while it is queued, lands on the most recently visited surviving sibling once it is gone, and stays put if its delete fails. * refactor(workspace-cleanup): reuse the close-terminal stop-agent wording The stop step's single-agent title is the existing "Stop this agent?" string, and its description follows the close-terminal prompt's wording. * test(worktree-delete): cover a local-qualified removal failure on an unhosted card * docs(workspace-cleanup): describe the after-delete focus hand-off in the bulk-select note * fix(workspace-cleanup): name one agent in the stop step's button and keep one agent term per locale * fix(terminal): keep starting terminals in a workspace that is only queued for deletion A cleanup batch now marks its local rows with the same delete state the sidebar card reads, so the terminal spawn guard sees them. The guard exists because removal just killed the workspace's terminals; a queued row still has them and can fail its own delete and stay, so a new terminal opened there (often the current workspace) stayed blank. * refactor(terminal): name the teardown-started check the spawn guards share * chore(workspace-cleanup): keep one agent term in ko/zh and refresh a spawn-guard comment * fix(workspace-cleanup): refresh consent and focus per removal * fix(workspace-cleanup): invalidate detected host evidence * fix(workspace-cleanup): admit removal at transport send * test(workspace-cleanup): expect the send-time admission callback and a published chat tab
…ames (stablyai#29966) Records the post-stablyai#29946 text order for workspace rows (Name, Recent and project-name sort), project group names and folder workspace names, ungrouped and grouped by project, so a future ordering change shows up as a golden diff.
…t reported, not the capped status store (stablyai#29905) * fix(native-chat): decide owed helper work from what the provider reported, not the capped store Idle cleanup, replacing an outgrown agent, /clear, /compact, rewind, command handover and the teardown resume marker decided whether a chat still had helpers running by reading the agent-status store. That store is a bounded display projection: it refuses records when it is full or for per-record reasons, and a refused helper is still running. The host now keeps an uncapped per-session set of the child work its provider reported running and has not reported over, fed from every child-work edge before the store sees it. Every owed-work decision reads that set. An entry leaves on the child's own end (a late end of an earlier run leaves the current run open, as the store's run verdict does), on a Stop the store settled, or on the session's end. The strip's "incomplete" note and Stop all's unlisted route are now derived: open work that no live current-run record answers to. This replaces the refused-for-room side list, so every refusal reason is covered and nothing needs separate bookkeeping. * test(native-chat): the real-store test sink reads recorded helper handles, as production's does * fix(native-chat): keep helper run identity through delayed events and Stop * fix(native-chat): name the host helper lifetime token * test(native-chat): explain the Stop adapter fixture boundary * fix(native-chat): derive helper coverage from running store records * docs(native-chat): clarify running helper coverage * test(native-chat): use an explicit helper end event * Scope background Stop to captured child work * Exercise refused helper Stop race through status store
…#29224) * fix(mobile): remove the dead space around the chat composer The Tools toggle floats over the transcript and shows only when the chat has tool calls; the composer is one row (attach, message, mic, send) until focused or drafted; Stop takes Send's slot while there is nothing to send; the bridge lane's working dots move to the transcript's tail. * fix(mobile): name the composer's content facts for their role * fix(mobile): preserve composer controls and picker focus * fix(mobile): typecheck working indicator test lookup * test(mobile): find the floating Tools pill when checking a chat switch keeps it expanded
…, for Settings and chat (stablyai#29049) * feat(acp): one install row shows and drives a managed runtime install, for Settings and chat The row reads the shared host state: Install, byte progress with Cancel, extract and verify lines, Retry after a failure or cancel, and in Settings Reinstall or Update once installed. A failed status read says it could not check, never that nothing is installed. Strings in all six locales. * fix(settings): the install row says when a copy is damaged, when a PATH copy is used, and when the host needs unzip - A damaged copy reads "This copy of {agent} is damaged." with Install, which repairs it. - A copy found on this host outside Orca's reads "Uses the copy of {agent} found on this host." with no Install, since a launch would never run the download. - A host without the program to unpack the archive says so, with no Install. * fix(settings): say why a host running its own copy is offered no download * fix(settings): the install row says Cancelling only where Cancel was clicked, offers Orca's copy beside one found on the host, and keeps its status line after a failed install The host no longer publishes a cancelling phase or a missing unzip, so the row drops both: the row whose Cancel is still out says Cancelling and holds its button until the host's cancel settles. A copy found on PATH or in an install folder still gets Install of Orca's copy in Settings (the chat keeps its composer). An older installed release reads Installed. with Update. A failed first install keeps Not installed. beside the failure and Retry. The status line is a polite live region. * fix(settings): the install row says it is retrying a failed status check, and names the step after the download * fix(settings): a Cancel that fails for no stated reason says the cancel failed, not the install
… the saved layout (stablyai#29961)
…ect groups (stablyai#29962) Relinking projects the server already held still re-imported this desktop's retained copy of their project groups, so a group renamed on the server while it was managed failed the reconnect with orcad_migration_project_group_id_conflict. A relinked move now leaves to the server every group its projects sit in (read from repo.list's projectGroupId) and those groups' ancestors unless a moving row needs one, journals those ids, and keeps them out of the exported rows while still reading them for folder-workspace host ownership. Later delta moves subtract them as they do moved groups.
…self (stablyai#29964) * fix(runtime): the host stops a removed project's terminals itself Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): a runtime-stamped project still stops the shells that run here Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): refresh the PTY inventory and sweep again after a project's removal Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): bound the project inventory refresh and recheck the WSL move fence Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): fence a project's removal sweep by its SSH connection and wait out in-flight spawns Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): bound the project stop's lease wait by the removal deadline Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): refuse spawns into a removed project and skip a stop a same-id sibling shares Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): bound each project stop by the removal deadline Co-Authored-By: Claude <noreply@anthropic.com> * fix(runtime): pass the removal deadline to the lease so a timed-out waiter is dequeued Co-Authored-By: Claude <noreply@anthropic.com> * test(runtime): type the project-removal fixtures instead of casting Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…s again (stablyai#29984) Partially reverts stablyai#27540 and the plain-http part of stablyai#27552, which broke web pairing on upgrade for 1.4.227 users who open Orca at a LAN or Tailscale address: - The host no longer refuses a first pairing from a plain-http page on another machine (insecure_origin, ORCA_ALLOW_INSECURE_WEB_PAIRING). - Such a page keeps its pairing code in local storage and signs in with it, as in 1.4.227, so reloads, new tabs and bookmarks stay paired; no notice. - Session-only browser keys (pairing.device-key-ephemeral.v1, the idle sweep) stay for browsers without Ed25519. - A web client whose credentials are refused shows the host's reason instead of an empty workspace and "Session restore failed".
…-owner build only) (stablyai#29988) * fix(browser): keep slept workspace browser tabs off the reopen-closed list Sleeping a workspace closed its browser tabs as if the user had closed them, so Reopen Closed Tab could bring back a tab that was only slept. Sleep now closes them with a 'sleep' reason that skips the reopen stack while still releasing host pages, doc grants and webviews as before. * feat(layout): send a browser tab's window timestamps with its open (dark) A layout-owner build's openBrowserTab carried no createdAt, so main stamped the tab-bar entry and the browser record with its own apply time and the window's next save diverged on createdAt for both. The window now sends both times, as createTerminalTab does; only switch-on builds send them. * Revert "fix(browser): keep slept workspace browser tabs off the reopen-closed list" This reverts commit 6798c3c. * test: drop the slept-tab close test that went with the held sleep fix
… (dark, layout-owner build only) (stablyai#29967) * feat(layout): main-made terminal tabs drawn with main's facts; resume records reach main record-only (dark) In layout-owner builds only: - A terminal tab main made itself (drag-out, CLI or host terminal, live-surface adoption) is drawn with main's createdAt and creation fields from the frames, and the window sends no create for it. - An editor tab main records takes the time the window drew it. - Every change of the window's agent resume records (live and quit captures, dropped records) reaches main through record-only sleep and wake commands, which stop or start nothing. - A terminal row's remount generation is declared the window's. * fix(layout): real wake reaches main before the record drop; drag-out keeps a frame-drawn tab (dark) In layout-owner builds only: - A resumed pane's wake is sent before the window drops its record, so main's wake still finds the pane sleeping. - A drag-out whose new tab main's frame already drew shows the pane in that tab instead of throwing "Terminal tab already exists". - A main-made tab keeps the window's shell, cwd, host-runtime and launch agent where main's copy names none (a runtime create records a shell only when its launch named one). - No record-only wake for a tab the window closed; main dropped its records with the tab. - Tests for the resume-record follower. * fix(layout): a dragged-out chat pane's new tab opens in chat view in main (dark) Main's movePaneToNewTab now gives the new tab viewMode 'chat' when the moved pane is its source tab's chat pane, as the window's own drag-out does. In a layout-owner build the window adopts the row main's frame drew, so without this the tab opened in terminal view. * fix(layout): a bound pane with a resume record starts as a no-op; resume records only for held tabs (dark) - startPane checks the pane's live terminal before its resume record: a running agent's live or quit record does not make its pane asleep. A pane with no terminal and a record is still refused. - The window sends record-only sleeps, like record-only wakes, only for tabs it still holds; a capture from a stale agent status no longer names a tab main already closed.
…ark, layout-owner build only) (stablyai#29987) * Agree with main on a workspace's first group and the tab order, and stop writing a preview flag main never stores (dark, layout-owner build only) Switch-on builds only; switch-off behaviour is unchanged. Group ids: a window save made before main's frame with a workspace's first tab carries none of that workspace's tab-bar records, so the Loader rebuilt the tab in the group it names for the workspace while main had minted a random one: every workspace's first save replaced main's group. Main now names a workspace's first group as the window's root group and the Loader do (`workspaceRootGroupId`), or takes the sender's when the window drew the tab in a group main lacks (the window keeps its emptied group); the window's `ensureGroup` names it the same way. The detector reads a lone group with no stored tree as that group's leaf, as main's own save writes it. Empty groups: the window never saves a group it holds empty, so a save cannot bring back one main closed (locked by a test). Tab order: a reorder the window makes itself (an anchored CLI or agent create, a reopened tab's old slot) is recorded in main as `moveTab` steps at the store boundary; callers that already asked main pass `layoutOwnerHandled`. The reopened-editor record this replaces is deleted. A paired client's move (`ui:moveSessionTab`) goes to main first through the tab-bar drop path. Preview: activating a tab removed its preview flag by writing `isPreview: false` on every tab; main stores no flag, so every activation changed the tab in main's model. The window now drops the flag instead. * Record a reopened tab's place in main every time, leave a move into a tab's own group alone, and keep a preserved preview untouched (dark, layout-owner build only) Review fixes, switch-on only: - A reopened tab's place is recorded as one moveTab whenever its old position is known, as the deleted editor-only record did, now for every kind; the reorder it may make is not recorded twice. - A move into the tab's own group (a paired client can send one) goes to today's no-op instead of a moveTab that reordered the tab. - Activation that preserves a preview returns the tab unchanged. Tests: switch-off first group stays minted; tabOrderMoves refuses a duplicate order. * Send a paired client's tab reorder to main as its whole order (dark, layout-owner build only) A client reorder names the group's full order, but it went to main as one moveTab of the named tab, so [a,b,c] -> [b,a,c] naming c moved nothing anywhere. It now takes the store's reorder path, whose record turns the whole order into main's moves (tabOrderMoves), the one rule for every window-side reorder. Moves and splits still go main-first.
…on suite (stablyai#29991) Seeds local+ssh, local+runtime and folder twins (one id on two hosts) with live shells, a dormant tab, dirty docs, drafts, sleeping-agent records and module-level stores, then runs a hand-declared action table (remove, folder delete, purge, kill, sleep, select) on one twin and asserts the other twin is untouched. Today's leaks are listed cell by cell and asserted to still leak, so a fix turns them red until the entry is removed.
…all in place of its composer (stablyai#29051) * feat(native-chat): a chat whose host has no program to run shows Install in place of its composer The chat's one input slot is chosen in one place: a final read refusal, then an owned prompt card, then Install while the host has nothing runnable (its install included), then the composer. Until the first status answer the slot stays empty instead of flashing either. Send and slash commands are refused while Install holds the slot, so nothing hidden reaches the host. The draft stays in its store and is there when the composer returns. A failed status read leaves the composer; the host remains the final refusal. * fix(native-chat): keep the composer slot reserved until the host's agent list says, and say nothing about sending while Install shows - While the host's capabilities or agent list are still loading for a chat's agent, the slot stays quiet instead of flashing the composer. - While the install row holds the composer's place, a failed start's notice ("Send your message to try again", Retry) is left out: nothing starts until the install lands. - The chat install card's title is semibold like the other cards in that slot. * fix(native-chat): keep the chat session view within its line limit after the install slot * fix(native-chat): the composer stays while the host's first install answer is out, its sends held, so no agent's chat loses its input box * fix(native-chat): the install slot holds Send through the composer's existing held-send reason instead of a flag of its own * fix(native-chat): the install slot hands the chat its held-Send reason, keeping the chat session view under its line limit
…ainst the window in dev and test (stablyai#29980) * feat(sidebar): main produces per-workspace activity facts in shadow mode * perf(sidebar): agent pings keep last-read surfaces; shadow counts comparisons * fix(sidebar): settle review findings in the activity-facts producer and shadow check * fix(sidebar): refresh on inventory verdict clears; resync agents only when tabs move * fix(sidebar): scope the shadow comparison by each row's owner, not the focused host * refactor(sidebar): name the shadow scope after what it keeps * fix(sidebar): classify sidebarInputs as host-owned in the operation ownership census
…rs from their owning modules (stablyai#30375) Removes the re-export lines in worktree-logic, worktree-base-directory-poller, filesystem-watcher and runtime-environment-transport-routing. Test mocks that supplied a re-exported name now mock the module that defines it, so they still reach the code under test.
…ill sends resume records (dark, layout-owner build only) (stablyai#30380) * chore(layout): the drift check's ignore comment names every main-only kind (dark, layout-owner build only) * fix(layout): a quit stage retried after a failed one still sends the resume records (dark, layout-owner build only) * feat(layout): the window's local layout stream reopens after a loss, and its snapshot redraws every workspace (dark, layout-owner build only)
…i#30257) Orca started jcode's background server itself as a terminal opened, ahead of the jcode client. On daemon-backed terminals that launch had no PATH and silently failed; where it did start, the server ran jcode's tools and hooks outside the shell's environment, without the client's launch flags, and outside jcode's own startup lock. jcode's client already waits for its server to signal ready, so it is now the only thing that starts it.
…ow (stablyai#29140) * feat(settings): remove a downloaded agent runtime from its Settings row When the host offers managed-runtime.remove.v1 and an Orca-installed copy is there with nothing running, the Settings install row shows a trash button ("Remove downloaded runtime") that asks first: "Remove {agent} from this host? Running {agent} chats stop. Chat history is kept." While the host removes it the row says "Removing…"; a refused removal shows the host's reason and keeps the button. Chats never show it. * fix(settings): offer Remove for a damaged copy too, and say which host the downloaded runtime leaves The row offers Remove whenever the host says Orca's copy is there (canRemove), damaged included; an older host without it keeps today's rule. The confirmation now reads "Remove the downloaded {agent} runtime from {host}? Running {agent} chats there stop. Chat history is kept.", naming the paired host, or this computer. * fix(settings): Remove follows the host's canRemove alone * fix(settings): the Remove dialog says the sign-in is kept too * fix(settings): show the downloaded runtime's install state as the provider's status line The Antigravity row in Settings > Chat > Providers drew its install state as a bordered box nested inside the row. It now reads like the other rows: one grey status line under the name, with its actions as inline links joined by ' · ' (Installed · Remove, Not installed · Install · size, a thin progress bar with Cancel while downloading, Reinstall · Remove for a damaged copy, Try again after a failure). A healthy install no longer offers Reinstall. The Remove confirmation now says running chats stop and their history is kept. * fix(settings): make Antigravity's first Install a primary button beside the switch Not installed now shows a high-contrast Install button at the row's right end in Settings > Chat > Providers and Settings > AI Provider Accounts > Antigravity; the status line keeps the sentences (Not installed · 112 MB download.). Every other action stays a link in the line.
…stablyai#29070) * fix(mobile): put the session tabs in the top bar on a landscape phone A sideways phone is about 390pt tall and the session header spent two rows on it. On a landscape phone the tab strip now shares the top bar with the back button, title and panel icons. Portrait and tablet layouts are unchanged. * fix(mobile): give session tabs side borders and a filled active tab In the landscape top bar the tabs sat between the title and the panel icons with nothing marking where one tab ended. Each tab now has a 1pt border on its sides, running the full height of the bar, and the active tab gets the raised fill, as the desktop tab strip draws them. The same strip is used in portrait, so both orientations match. * fix(mobile): reset tab strip measurements on view attachment * style(mobile): format tab strip ref dependencies * fix(mobile): keep two header rows in landscape windows too narrow for top-bar tabs A short, narrow window (a ~390x350 web window) is wider than tall, so it counted as a landscape phone and moved the tabs into a top bar that has no width left for them. Top-bar tabs now also need at least 568pt of width, the narrowest landscape phone. * fix(mobile): give the landscape top-bar tab strip a fixed left edge so scrolled tabs never read as part of the title * fix(mobile): 12pt between the session title and the landscape tab strip
…ate off (stablyai#30387) A due update check makes agy start --bg-updater, whose own console child opens a visible window on Windows and takes focus, so stepping away from Orca for 15+ minutes and coming back flashed a terminal (stablyai#27390). Set AGY_CLI_DISABLE_AUTO_UPDATE=true on both probes; a background quota read should not update the user's CLI anyway. Only 'true' is honoured (agy 1.4.2). Co-authored-by: Orca Worker <orca-worker@localhost>
…dow-wide layout hold goes (dark, layout-owner build only) (stablyai#30384) * chore(layout): the drift check's ignore comment names every main-only kind (dark, layout-owner build only) * fix(layout): a quit stage retried after a failed one still sends the resume records (dark, layout-owner build only) * feat(layout): the window's local layout stream reopens after a loss, and its snapshot redraws every workspace (dark, layout-owner build only) * fix(layout): a command whose target main's copy lacks is a logged refusal, not the window's own change (dark, layout-owner build only) * feat(layout): frames keep each tab the window drew, closed or moved as drawn until main answers; the global frame hold goes (dark, layout-owner build only) A refused draw-first terminal create is closed (its terminal stopped) at the refusal. The activation create no longer draws main's tab itself while the stream is down: the reopened stream's snapshot does. * fix(layout): a tab move or drag-out the frame already drew is not placed again by the window (dark, layout-owner build only) Also holds the group sizes the window drew until main saves them. * test(layout): with frames flowing, a pin promotes a preview tab once and tab-change bookkeeping runs once (dark, layout-owner build only) Also states that the held-tab overlay builds frame slices only. * test(layout): read the rename's title without a cast * chore(layout): the drift check's header lists the same ignored records as its inline comment
* Require a full hover delay before each tab preview Tab previews opened almost immediately after a previous preview had been shown, so sweeping across the tab strip caused a flurry of popups. Raise the tab tooltip delay to 800 ms and drop the warm-start chain: the shared open-state context, the 300 ms skip delay, and the slide animation that carried position between cards. Every tab now waits its full dwell time, and keyboard focus still shows the preview immediately. * Test that tab hover cards wait a full dwell on every hover The tab hover card no longer slides instantly between neighboring tabs. Each hover now waits for the full delay before showing a preview. The e2e test still expected instant sliding, so it was rewritten to match. - Remove the frame-recording helpers and the slide and reversal assertions. - Check that no card appears before the dwell, and that the card appears after it. - Check that leaving a tab cancels a pending preview, and that time spent on other tabs does not count toward the dwell. - Check that re-entering the same tab requires a fresh dwell.
…d order under the pointer (dark) (stablyai#30284) * feat(sidebar): sort stamps reconcile stored tiers at startup against live hook rows and terminals (dark) * test(sidebar): a restart clears an unbacked local tier and keeps an SSH host's * fix(sidebar): run the sort tier reconcile once hook rows and PTYs settle, seeding hydrated rows * fix(sidebar): clear a stored tier only on proof its terminals died; a rest seed adds no clear * chore(sidebar): merge origin/main; locality helper moved to shared * feat(sidebar): sort Recent and Smart by host stamps behind the sidebar-inputs switch With ORCA_SIDEBAR_INPUTS=main, the window, main and the phone order Recent by lastActivityAt and Smart by smartTier then smartAt (Needs you, Done, Working, then the rest by Recent). The window holds its displayed order while the pointer is over the list or a drag runs. Switch off: today's sort path. Co-Authored-By: Claude <noreply@anthropic.com> * chore: restore files the merge commit's formatter rewrote Co-Authored-By: Claude <noreply@anthropic.com> * fix(sidebar): stamp-order review fixes behind the sidebar-inputs switch The window writes no Recent stamps with the switch on (terminal start and exit, unread marks, comment edits), the hover hold covers only Recent and Smart and ends with a drag, main follows only explicit metadata saves, and the phone picks its sort from the unfiltered rows. Co-Authored-By: Claude <noreply@anthropic.com> * test(sidebar): folder writers and a Manual drag under the stamp switch Co-Authored-By: Claude <noreply@anthropic.com> * test(sidebar): name the stamp type in the ps summaries test Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…tablyai#30137) Two merged changes left lines past the formatter's 100-column width in structured-session-create-support.ts, structured-agent-session-create-adoption.ts and transcript-opencode-sqlite-query.ts. Any branch that merges main gets them reformatted by the pre-commit hook, which pushes two of them past the 300-line limit and fails CI. Format them, and keep them under the limit by moving the bounded row readers and the resume adopt payload into the modules that own them. No behavior change.
…before the first message (stablyai#28424)
…ing Recent (dark) (stablyai#30397) * fix(cleanup): count visits as last activity once terminals stop stamping Recent (dark) With ORCA_SIDEBAR_INPUTS=main, terminal start and exit no longer write lastActivityAt, so a workspace used only through plain shells could look idle to workspace cleanup and old in the jump palette. Both now read the later of the Recent stamp and the last visit. Switch off: unchanged. Co-Authored-By: Claude <noreply@anthropic.com> * fix(cleanup): stamp the workspace you leave; space table reads visits too (dark) Co-Authored-By: Claude <noreply@anthropic.com> * fix(cleanup): every reveal stamps the workspace you leave, host-aware (dark) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…i#29903) * fix(terminal): a file dropped on a pane makes that pane active Dropping a file on an inactive pane's title strip pasted the path but left the other pane selected, because the drop only focused the terminal. Activate the pane instead (which also focuses it). Tracked in STA-9893. * test(e2e): give the title-strip drop the source owner real drags carry * test(e2e): preserve pane selection when checking title-strip drops --------- Co-authored-by: Orca Worker <orca-worker@localhost>
… or saved order (dark) (stablyai#30401) * refactor(sidebar): the stamp-sorted window list runs no settle, latch or saved order (dark) With ORCA_SIDEBAR_INPUTS=main the window's sort hook is a pure read of the rows' stamps: no settled-epoch store listener, no Smart latch, no saved Smart order writes, no class telemetry over the old attention map. Switch off: the existing hook, unchanged. Co-Authored-By: Claude <noreply@anthropic.com> * test(sidebar): stamp sort hook reads no live sources; stronger switch-on tests Co-Authored-By: Claude <noreply@anthropic.com> * test(sidebar): clear the order-save mock between tests Co-Authored-By: Claude <noreply@anthropic.com> * fix(sidebar): stamp sort reads a shared empty-sources constant, not a renderer layout literal The layout-writer ratchet counts layout field keys written in the renderer; the empty sources object now lives beside SmartSortSources in shared code. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…s own (dark) (stablyai#30404) * refactor(sidebar): the stamp-sorted window list runs no settle, latch or saved order (dark) With ORCA_SIDEBAR_INPUTS=main the window's sort hook is a pure read of the rows' stamps: no settled-epoch store listener, no Smart latch, no saved Smart order writes, no class telemetry over the old attention map. Switch off: the existing hook, unchanged. Co-Authored-By: Claude <noreply@anthropic.com> * test(sidebar): stamp sort hook reads no live sources; stronger switch-on tests Co-Authored-By: Claude <noreply@anthropic.com> * test(sidebar): clear the order-save mock between tests Co-Authored-By: Claude <noreply@anthropic.com> * wip: main keeps sleeping retention only * fix(sidebar): stamp sort reads a shared empty-sources constant, not a renderer layout literal The layout-writer ratchet counts layout field keys written in the renderer; the empty sources object now lives beside SmartSortSources in shared code. Co-Authored-By: Claude <noreply@anthropic.com> * refactor(sidebar): main keeps sleeping retention only; no order of its own (dark) Clients sort by the owning host's stamps, so main's temporal owner loses its settle window, Smart latch, create grace and catalog-listing classifier, and the shadow check stops comparing order. Retention, its clock and its shadow comparison stay. Co-Authored-By: Claude <noreply@anthropic.com> * fix(sidebar): every retention listing shares one sequence; publish after the first Co-Authored-By: Claude <noreply@anthropic.com> * test(sidebar): the first listing bumps the retention revision Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
…line skills (stablyai#30359) * refactor(native-chat): move the slash picker builder and upload chunking to shared Mobile builds the same skill and command list as desktop. * feat(mobile): redesign the chat composer with file attachments and inline skills * fix(mobile): the composer field owns its input style The page's font-size census cannot follow a style passed in as a prop.
…vals, name icon buttons (stablyai#30142)
…main has no pane for closes in the window (dark, layout-owner build only) (stablyai#30391) * fix(layout): a workspace only main held shows main's tab on the window's first visit (dark, layout-owner build only) * fix(layout): a live terminal no pane shows goes through main, which names the tab it holds; a pane close main has no pane for closes here (dark, layout-owner build only) * test: no type assertions in the CLI-first tests * refactor: the switch-off build keeps today's live-terminal mint as it was * review: frame sync under the line limit; the first-visit test names exactly main's tabs * fix(layout): adopt takes the recorded pane only while it is unbound * fix(layout): a refused live-terminal adoption is declined, not counted as shown
…ld orphans are reclaimed (stablyai#30148) * fix(macos): the TCC prompt watcher's log stream dies with Orca log stream only writes when its predicate matches (about never), so it never gets SIGPIPE when Orca dies without running stop() (crash, SIGKILL, e2e teardown, force-quit dev builds) and lived on under launchd. One dev machine had 126 orphans holding 566 MB and ~40% CPU. A /bin/sh wrapper now holds a never-written stdin pipe from Orca and kills log stream on EOF. * fix(macos): reclaim TCC log streams that older builds orphaned The wrapper stops new leaks, but users upgrading still have every log stream an earlier crash or force-quit left under launchd. Ten seconds after launch, once per process, Orca terminates launchd-parented processes running exactly the watcher's old command line. A live watcher's log stream is parented by its wrapper, so it never matches. * test(macos): document the fake log stream cast * fix(macos): arm log stream wrapper trap before fork; verify orphan executable * fix(macos): re-read orphan identity before SIGTERM; disable inherited errexit in wrapper
…30425) * feat(sidebar): Smart Done means finished and unread (dark) Owner decision Q1: with ORCA_SIDEBAR_INPUTS=main, a Done row holds its tier only while the workspace unread flag is set, so opening the workspace or sending the next prompt ends it. Reuses the existing flag; no new state or timer. Co-Authored-By: Claude <noreply@anthropic.com> * test(sidebar): reading a workspace drops its Done row in the live list Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
* Settle Codex review turns from their session completion * Preserve interruption relay metadata when settling Codex reviews * Keep the Codex turn id across status writers and settle through the existing host verdict path The turn id that matches a rollout turn end was dropped by every lead writer that did not pass it, so a failed turn after a child update never settled. Drop the synthetic Stop label: the unlabelled poll update already carries the host's main-agent verdict, including a failure, to current desktops. A remote desktop now takes the host's settled verdict for a late hook, and a rollout settle retires hook-only children like Stop does. * Retire Codex children through the poll and start a fresh turn on any non-compaction session start A rollout-settled turn deleted the child roster, so the local reconcile re-seeded the child from the last row as running and the pane stayed Working. Clear it instead, only from the poll (a child hook settling the root must not drop that live child), and let a remote desktop clear its roster when the host reports a done turn with no children. A resumed or forked session no longer inherits the previous turn id. Also drops accidental pnpm-lock churn. * Replay a Codex rollout turn end as the root Stop it stands in for Codex fires no Stop for internal subagents such as /review, so the rollout's task_complete was settling the main agent through a second path that every other status writer (local and remote reconcile, child hooks, polls) had to learn about. The transcript poll now replays that end as an ordinary root Stop through hook normalization, and a root hook for an already ended turn is classified as that Stop. A failed end carries its failure outcome and is published unlabelled like a cancellation, since desktops derive a labelled Stop's outcome as success. The separate settle path, the remote host-verdict adoption and the child-hook rollout reads are gone. * Keep an ended Codex turn retired across compaction, and keep WSL polls alive A compaction SessionStart queued before the next prompt carried the previous, already ended turn id, so the poll replayed its Stop: a Done flash and a second "finished" notification. A compaction now keeps the turn only while it is still running and its rollout end is unrecorded. The WSL guest rescheduled its transcript poll with the update instead of the stored row, so the poll stopped after its first update and a later turn end never replayed there. A Stop also clears the child roster instead of deleting it, so a reconcile cannot re-seed retired children from the previous row. * Restate an ended Codex turn's hook in provider dispatch Keeps the shared hook normalizer within its size limit after main's merge; the Codex dispatch returns the event it normalized, which the envelope uses for the published name and prompt classification. * Type the rollout record helper in the Codex turn-end test * Accept Codex's turn_complete name and keep only replayed Stops labelled The rollout reader also records turn_complete, the name the existing interruption reader already accepts. A poll row that is not a replay no longer restates the last hook's event name, so only a replayed Stop can carry the Stop label. * Drop a delayed Codex hook for an ended turn the lead has moved past A late root hook for an older finished turn was restated as Stop and marked the newer running turn Done; passing it through would instead rewind the lead's turn id so the poll replays the old end.
# Conflicts: # src/cli/bundled-skill-guides.ts # src/main/ipc/register-core-handlers/register-core-handlers.test.ts # src/main/ipc/repos-local-add-and-project-setup.test.ts # src/main/startup/main-process-i18n-menu.ts # src/main/startup/main-window-agent-status.ts # src/preload/api/app-api.ts # src/renderer/src/components/editor/EditorPanelHeader.tsx # src/renderer/src/components/settings/NativeChatExperimentalSetting.tsx # src/renderer/src/components/sidebar/MarkdownImageLightbox.tsx # src/renderer/src/components/sidebar/compute-visible-worktrees.ts # src/renderer/src/components/sidebar/use-worktree-card-controller.ts # src/renderer/src/components/tab-bar/TabBarQuickCommandsButton.tsx # src/renderer/src/components/terminal-pane/TerminalContextMenu.tsx # src/renderer/src/i18n/locales/en.json # src/renderer/src/main.tsx # src/renderer/src/store/slices/editor/actions/git-status-actions.ts # src/shared/global-settings-types.ts # src/shared/worktree/meta-types.ts # src/shared/worktree/types.ts
Upstream moved github-cache-key.ts to src/shared/github/ and composed GlobalSettings from a new GlobalSettingsBase; the fork's settings base now extends it so global-settings-types.ts keeps upstream's shape.
…tup split Upstream dropped the watcher type re-exports from parcel-watcher-process.ts (stablyai#30369) and the setupScriptLaunchMode setting (stablyai#29819: setup always gets its own tab), so the language-server watcher imports the owning modules and the fork's background-terminal launcher no longer splits setup into a pane.
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.
1.4.214 → 1.4.214 (
1b1d09cfb5..4298ba998d, 695 upstream commits, nineteen conflicts)package.jsonstill says 1.4.214, so the branch name repeats an eighth time. The earlier sync'spull request for this branch is merged, so a new one is opened on the same branch name.
bundled-skill-guides.ts,en.json: took upstream's and regenerated(
generate:bundled-skill-guides,sync:localization-catalog,sync:localization-runtime-catalog). The RPC catalog was already current.compute-visible-worktrees.ts— upstream moved the sidebar's filter, lineage and sort into theshared
selectVisibleSidebarWorktrees(shared/sidebar-list/visible-worktrees.ts). Took it andapply fork feat(comments): pick an emoji with :name wherever @mentions work #9's temporary-checkout filter to the rows before they go in, so the shared selector
stays upstream's.
use-worktree-card-controller.ts— upstream reads card properties fromfoundation.cardDetails(getWorktreeCardDetails). Took it; fork Sync upstream 1.4.214 #7/feat(notes): sent notes stay and agents reply to them in place #8'sshowLinearTitleandshowPrAuthorstill readfoundation.cardProps, so the shared details type stays upstream's.global-settings-types.ts— upstream composesGlobalSettingsfrom a newGlobalSettingsBase.The fork's
ForkBaseSettings(fork-source-control-settings.ts) now extends that instead ofNativeChatGlobalSettings(fork fix commit), so the only fork line left there is the import.main-window-agent-status.ts— upstream moved the first-work branch rename out of the hooklistener (fix(serve): Hermes settles and first-work rename runs on a headless host stablyai/orca#29429). Took the removal; fork fix(editor): diff jumps keep their line, blame in diffs, hovers not clipped #31's
observeAgentTurncall stays.MarkdownImageLightbox.tsx— upstream's single-image dialog became a pan-and-zoomPanZoomImageDialog(feat(native-chat): pan and zoom chat image previews like mermaid diagrams stablyai/orca#30154). Kept the fork'sMediaLightboxgallery whole (fix(source-control): the file type filter is kept per worktree #15), as last sync.TerminalContextMenu.tsx— upstream's Copy Context item becameAgentSessionContextCopyMenuItem;took it and kept fork feat(right-sidebar): preview deployment button and a roomier header #18's
AgentViewSubmenu.NativeChatExperimentalSetting.tsx— upstream droppedNativeChatSupportedAgents; kept only thefork's
ClaudeWebDefaultViewSettingimport.register-core-handlers.test.ts— kept the fork'skeybindingsargument to the dashboard popoutbeside upstream's new
registerWorkspaceSpaceWindowHandlersexpectation.repos-local-add-and-project-setup.test.ts— kept the fork's Python venv and port labels cases;took upstream's now-async visibility case.
main-process-i18n-menu.ts,app-api.ts,EditorPanelHeader.tsx(AgentNotesPillbeside upstream's renamedEditorPanelActionsMenu),main.tsx(fork's release-repo override beside upstream's sidebar shadow comparison),git-status-actions.ts,meta-types.ts,types.ts,TabBarQuickCommandsButton.tsx.store/slices/github-cache-key.tstoshared/github/github-cache-key.ts(feat(sidebar): main produces per-workspace PR facts, checked against the window in dev and test stablyai/orca#30026); five fork files imported the old path (fork fixcommit). The missing-import scan caught it; limit it to files that differ from
upstream/main, orupstream's own test fixtures bury the result.
workspace-port-labels.ts,PortLabelsCommandSection.tsx,portLabelsCommandon repos) is fork work not yet listed in What this fork owns.parcel-watcher-process.tsno longer re-exports its types (refactor(ipc): import ipc helpers from their owning modules, not re-export shims stablyai/orca#30369), so the language-serverwatcher imports them from
parcel-watcher-process-protocol.ts/-subscription.ts; andsetupScriptLaunchModeis gone (Run automated workspace setup in a dedicated Setup tab stablyai/orca#29819, setup always runs in its own Setup tab), so the fork'slaunch-worktree-background-terminals.tscopy dropped its split-pane setup path to match.