mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 09:07:40 +00:00
294fd2ac06cfff31e5a7271bcefab040ae31e0de
1299
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b16a71c7fb |
ci: reuse Windows hook builds and shorten test setup and shutdown (#29439)
* ci: remove Windows build and persistence test overhead * ci: collect unit phase diagnostics during PR checks * test(ci): seed hook reuse fixture from the canonical prebuild The hook reuse regression first built into a missing private --output, so it always reached Cargo (74s warm on Windows). Build through the default output instead, which reuses a warm canonical prebuild, then copy its executable and fingerprint into the private fixture root. * fix(lint): clear inherited max-lines and broad object tab parameter after main merge Combine the duplicate shared/execution-host imports in runtime-host-services (301 -> 300 lines) and type the overlap test's tab mapper with the RuntimeMobileSessionClientTab owner type instead of object. * fix(ci): align inherited runtime and workflow contracts * test: establish changed runtime probe signatures deterministically * test: await asynchronous daemon profile cleanup * test: shut down owned daemons before deleting profiles * test: clean up oracle daemons during final app close * test: recognize verified Linux zombie exit during daemon teardown * fix: preserve folder SSH ownership when project groups conflict |
||
|
|
b0178a5dbc |
fix(orcad): prove the held-6768 fallback in e2e and keep the managed marker out of terminals (#29569)
* test(e2e): prove the held-6768 case really held the port and orcad bound another Co-Authored-By: Claude <noreply@anthropic.com> * fix(pty): keep orcad's managed-launch marker out of user terminals A terminal on a managed host inherited ORCA_ORCAD_MANAGED_ACTIVATION_ROOT, so an orcad a user started there looked client-managed: --port stopped being strict and idle exit applied. Scrub it like the other per-launch identity variables. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
b89373c757 |
test(e2e): a paired phone lists and opens a managed SSH host's projects through the desktop (#29549)
Pins #29456 end to end: relay-era SSH projects convert to a managed server, a phone paired with the desktop lists them via mobileRelay.hosts.* under the SSH host's name and opens one through the relay, while the desktop's own list keeps the retained copies hidden. |
||
|
|
98457f6334 |
test: frame inline Kitty RGB uploads within protocol limits (#29519)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
e5b7c564a5 |
Make failed check details readable and easy to retry (#28702)
* Bound and sanitize CI failure excerpts with linear ANSI stripping * Fix excerpt regression checks and reduce bounded marker overhead * Require signal proof for benchmark timeouts and load consumer fixtures portably * Validate benchmark timeout framing and run required cases with a pinned CI baseline * Strip dense generic ANSI escapes with bounded forward scanning * Use the standard UTF8 encoder for byte-cap test oracles * Gate CI log performance suites behind a dedicated job The wall-clock performance suites run about 1k child workloads up to 63 MiB, so they were sharing runners with unit tests and could fail on noise. They now run only in their own `check_log_performance` job, opted in with `ORCA_CHECK_LOG_PERF=1`. - Remove the pinned-baseline checkout and `ORCA_CHECK_LOG_BASELINE_DIR`. The baseline comparison is now a manual step that reads the pinned ref from local Git history. - Run the current-implementation checks with `compareBaseline: false`, which skips baseline builds and audits. * Inline check-log fixture and drop dedicated perf CI job - Replace the captured failure-log JSON with a synthetic log built by `createCheckLogFixture()`, so no scraped job output or provenance metadata is kept in the repo. - Remove the `check_log_performance` CI job. The log performance suites now run only when `ORCA_CHECK_LOG_PERF=1` is set, as a manual benchmark. - Update the benchmark scripts and tests to use the new fixture helper and drop the `fixturePath` parameter. * feat(checks): add optional job log outcome * fix(checks): preserve host capture lifetimes and safe outcomes * fix(checks): retrieve and retry bounded failed-job logs * test(checks): cover queued snapshots and captured error safety * test(checks): verify sanitized host excerpts and paired failures * test(checks): identify measurements and preserve paired cleanup * Keep check details load failures safe and localized * Describe failed check logs as bounded excerpt context * Normalize check log excerpts once at renderer ingress * fix(checks): prioritize failure excerpts and retain reading position * fix(checks): show truthful log outcomes and explicit refresh guidance * fix(checks): fit failure context in narrow panes and skip generic headings * fix(checks): prioritize captured failure diagnostics over inline loggers * fix(checks): stop stack association at a new diagnostic * feat(checks): add optional job log outcome * fix(checks): preserve host capture lifetimes and safe outcomes * fix(checks): retrieve and retry bounded failed-job logs * test(checks): cover queued snapshots and captured error safety * test(checks): verify sanitized host excerpts and paired failures * test(checks): identify measurements and preserve paired cleanup * Use the generated check-log fixture in host retrieval tests * Keep check details load failures safe and localized * Describe failed check logs as bounded excerpt context * Normalize check log excerpts once at renderer ingress * Repair ingestion test fixture and benchmark names after dependency merge * fix(checks): prioritize failure excerpts and retain reading position * Use the replacement generated fixture for check-details presentation tests * fix(checks): show truthful log outcomes and explicit refresh guidance * fix(checks): fit failure context in narrow panes and skip generic headings * fix(checks): prioritize captured failure diagnostics over inline loggers * fix(checks): stop stack association at a new diagnostic * ci: rerun UI checks after restack * fix(checks): classify sidebar job failures consistently |
||
|
|
db22421ae7 |
fix(ssh): agents on a managed SSH host can drive the desktop Orca browser again, behind the per-host switch (#29384)
* fix(ssh): an opted-in desktop serves its browser to a managed SSH host's orca CLI again * fix(ssh): scope bridged pages through the renderer, render them as desktop pages, and route the e2e * fix(ssh): bridge refuses file URLs and clipboard reads, revokes on disconnect, closes desktop tabs * fix(ssh): judge bridged paste chords as the page sees them; accept long workspace ids * fix(ssh): bridged clipboard denial follows popups; revoked commands never leave the browser queue * fix(ssh): refuse option-like host values bound for agent-browser argv; report undeliverable results * fix(ssh): bound bridged error results and fall back when the host refuses one * fix(ssh): bridge only routed host tabs, and bound bridged page scripts by a deadline and revocation * fix(ssh): cap waiting bridged commands below the desktop socket's result capacity * fix(ssh): bridge revokes on routing changes, checks each page's route at run time, and cancels host-driven downloads * fix(ssh): name the bridge registry's owner type * fix(ssh): bridge refuses pages showing a local document, and never starts a command past orcad's deadline * fix(ssh): bridged commands may leave Chromium error pages, and stop starting before orcad's deadline * fix(ssh): ask for a fresh opt-in to host CLI control saved before it drove the desktop browser * test(ssh): type the bridge registry deadline test |
||
|
|
629db0a1f4 |
[CI] Reduce test imports, clock waits, and headless cleanup costs (#29312)
* [CI] Keep transport-only tests outside the app store graph * [CI] Advance the updater install clock in failure tests * [CI] Avoid descriptor formatting in replay clip counts * [CI] Advance native-chat test observation clocks * [CI] Restore observation timers after failed test setup * [CI] Clean up final headless daemons during public close * [CI] Keep serializer test oracle out of production smoke triggers * [CI] Keep three unit fixtures out of production smoke triggers * [CI] Bound frozen-clock close callbacks in tests * [CI] Avoid the app-store graph in feedback dialog tests * [CI] Keep hidden popup fixture compositor frames active * test(ci): reuse mobile runtime fixture for pairing listeners * test: restore native chat clocks before rig cleanup |
||
|
|
5b4cbfada8 |
fix(browser): closing a headless server's browser tab no longer crashes the server (#29480)
Detach the page's debugger before destroying its offscreen window, so a live screencast closes before its in-flight snapshot can call capturePage on the half-destroyed page (an Electron segfault). Also wait for the paired workspace's first terminal in the link-routing e2e so its late focus cannot hide the pane. |
||
|
|
0fac887dbc |
feat(terminal): show a paired server's terminal in this desktop on terminal switch (#28023)
* fix(terminal): log a failed pane reveal instead of rethrowing it The bridge already replies false when the reveal throws, so the rethrow only surfaced as an uncaught renderer error after the caller had its answer. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(terminal): refuse terminal.reveal from paired clients It moves this host's window. terminal.focus lets a paired client do that only by asking for host navigation, and the callers this method serves (the CLI and companion apps on the same machine) never arrive as paired clients. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(terminal): show a paired server's terminal in this desktop on terminal switch A paired `orca serve` host has no window, so `orca terminal switch --environment <name>` resolved the handle there, answered `navigated: false`, and the desktop stayed put (#24688). Add `terminal.reveal`, a desktop runtime method that names a pane by worktree, tab and leaf, as the owning host knows them, and runs the Agent Dashboard's click-to-focus sequence before raising the window. When a paired server cannot navigate, `terminal switch` asks the desktop on this machine to reveal the terminal instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(e2e): terminal switch on a paired server moves the desktop on this machine Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test: update terminal manifest count after main and assert the revealed pane renders Main added a terminal method since this branch was cut, so the characterization count is 39 with terminal.reveal. The e2e now proves the target pane is visible in the DOM, not only selected in the store. Co-authored-by: Velm14 <Velm14@users.noreply.github.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: Neil <neil@stably.ai> Co-authored-by: Velm14 <Velm14@users.noreply.github.com> |
||
|
|
adce59a584 |
fix(remote-terminal): a remote pane comes back on its own once its host answers again (#29444)
* fix(remote-runtime): probe sockets and reset backoff on wake, and keep late resubscribes revivable Rebuilt from #23359 on current main. On OS resume or network return every remote-runtime socket pings once and is replaced if it stays silent for 8 s, the shared-control retry ladder restarts from its short delays, and a resubscribe that fails or opens after the pane's recovery window latched is parked so resume/online can revive it. Co-authored-by: Meapri <104259736+Meapri@users.noreply.github.com> * fix(remote-terminal): revive a latched remote pane when its host answers again A pane whose ~3 min auto-recovery window ran out only came back on an OS online/resume event or a Reconnect click. A Tailscale or VPN route that returns fires neither, so the pane stayed dead over a working link even though the host shell was alive. The environment's shared control socket reaching ready again is now the revive signal: the pane advances its backoff or replays its attach, exactly as Reconnect does. Adds e2e repros for paired runtimes and managed SSH hosts: 30 s silent and reset outages, and a silent outage longer than the recovery window. * fix(remote-terminal): hold the control-ready reviver only while a pane is recovering * fix(remote-runtime): re-probe a wake check whose deadline fired late, and trim the SSH outage spec --------- Co-authored-by: Meapri <104259736+Meapri@users.noreply.github.com> |
||
|
|
37c00630d4 |
fix(remote-files): open large HTML, PDFs and images on a paired runtime (#29426)
* fix(remote-files): open HTML, PDFs and images too large for one reply on a paired runtime files.read stops at 512 KiB and files.readPreview at about 3 MB (one 4 MiB reply, after base64), so larger files on a paired runtime failed to open. Read them in chunks with the files.stat and files.readChunk methods hosts already have, and refuse a save the host's 1 MiB frame cap would answer by closing the connection. Fixes #29306 Fixes #26062 Co-authored-by: sotashimozono <shimozono-sota631@g.ecc.u-tokyo.ac.jp> * fix(remote-files): keep a UTF-8 BOM when paging a large remote text file * fix(remote-files): pin a paged read to one pairing and compare ctime * fix(remote-files): pin the pairing before a remote read's first request --------- Co-authored-by: sotashimozono <shimozono-sota631@g.ecc.u-tokyo.ac.jp> |
||
|
|
fc534c6a19 |
fix(remote-terminal): a headless host keeps a parked terminal at its viewer's size (#29349)
* fix(remote-terminal): a headless host keeps a parked terminal at its viewer's grid Parking a paired pane closes its stream, the PTY's last viewer. The floor then reclaimed the PTY to the host's geometry, which on a windowless orca serve/orcad host is the 120x40 spawn grid nobody sees. Every reveal then fetched a snapshot at 120x40 and reflowed it to the pane, and a TUI redrew twice. With no host pane to give the grid back to, the floor now keeps the last owner's grid; the parked owner's reserved seat resumes it without a resize. * test(remote-terminal): a phone or another viewer still takes a parked terminal's grid on a headless host * fix(remote-terminal): a phone leaving a parked headless terminal restores the parked grid * fix(remote-terminal): keep the parked desktop grid as the restore baseline even while a phone fits * test(remote-terminal): tie each PTY size probe to its own reply |
||
|
|
73393f7009 |
fix(terminal): a cold-parked terminal reveal paints once, at the pane's own size (#29331)
* fix(terminal): a cold-parked terminal reveal paints once, at the pane's own size A structural replay (park reveal, reattach, hidden-output restore) clears the pane, resizes xterm to the snapshot's grid, replays, and only then fits back to the pane. Every step was presented, so a reveal showed a blank pane, then the host's grid in the top-left, then the real fit. The screen is now withheld behind a copy of its last frame until the transaction and its fit finish, capped at 1 s so a deferred fit can never leave a live pane unpainted. Pane-level half of #22728, plus a hold cap and a paired-runtime reveal e2e. Co-authored-by: mmarabel <166927047+mmarabel@users.noreply.github.com> * fix(terminal): keep a WebGL screen shown when its frame cannot be copied, and keep decorations positioned Co-authored-by: mmarabel <166927047+mmarabel@users.noreply.github.com> --------- Co-authored-by: mmarabel <166927047+mmarabel@users.noreply.github.com> |
||
|
|
e65a1dd553 |
Keep idle Claude sessions selected during nested Codex work (#29386)
* Preserve idle foreground Claude session ownership through nested hooks * Discard obsolete hook probes and cancel queued restarts |
||
|
|
9c177fb944 |
test(runtime): remove duplicate completed-worker close sequence (#29411)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
90849ed0c6 |
Enable Claude plugin images and bounded terminal file transport (#28200)
* fix: render Kitty Unicode placeholder images with bounded ownership * Enable managed Claude plugin images and bounded host file transport * Preserve isolated Claude evidence and paired restart diagnostics * Resolve Windows workspace aliases before WSL image reads * Handle split remote terminal identities and improve WSL file-read diagnostics * Reuse native drive paths for WSL image files and preserve guest temporary roots * Apply native Windows path restrictions to mapped drive image sources * Preserve WSL participation evidence across image checks * Keep WSL drive directory containment case-sensitive after canonicalization * Negotiate managed Claude image support with the launching renderer * Make image repaint checks independent of display profile and shell output * Capture repaint diagnostics only after the pixel assertion fails * Allow floating terminal image reads from host temporary folders * Keep image stack independent of unrelated CI runner and mobile lint settings * Reuse worktree argument builder for terminal viewer context Remove duplicated mapping and keep the RPC method table within its existing line limit. |
||
|
|
26278b32ce |
Render Kitty images at Unicode placeholder cells (#26031)
* fix: render Kitty Unicode placeholder images with bounded ownership * Make image repaint checks independent of display profile and shell output * Capture repaint diagnostics only after the pixel assertion fails |
||
|
|
7306273d89 |
fix(ssh): switching back to a quiet remote terminal no longer refetches its snapshot (#29253)
* fix(ssh): switching back to a quiet remote terminal no longer refetches its snapshot Co-Authored-By: Claude <noreply@anthropic.com> * test(cross-version-wire): drop notice negotiates only between current peers Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
c023d35cd1 |
fix(browser): managed SSH terminal links open in the Orca Browser again (#29215)
* fix(browser): managed SSH terminal links open in the Orca Browser again A managed server reached over SSH has no browser backend of its own, so links from its panes were offered only the system browser. They now open in a desktop tab whose page egresses through the SSH host, the same route new browser tabs in that workspace already use. Fixes #29077, #27349 * test(e2e): keep the managed workspace host selected for the Cmd/Ctrl-click step * refactor(browser): keep owner-route checks private; split tab presentation instead Moving the owner predicates to their own module made their callers count as new focus reads. Keep them in workspace-browser-tab-open and move the title/error presentation helpers out to stay under the line limit. The SSH deployment check also reads the workspace's owner route instead of the focus-falling-back host lookup. * test(e2e): assert the managed SSH link page renders in the visible browser tab * fix(browser): keep a desktop-hosted link tab owned by its runtime workspace --------- Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: Neil <neil@stably.ai> |
||
|
|
33759f91f5 |
fix(ssh): give each machine sharing one home its own managed server (#29214)
* fix(ssh): give each machine sharing one home its own managed server state (#29059) * fix(ssh): key machine homes by machine-id, keep data roots short, recover empty claims --------- Co-authored-by: m4air <m4air@Mac.localdomain> |
||
|
|
88bd5db42e |
fix(windows): copy a file to the clipboard without a visible PowerShell window (#28781)
* Run clipboard file copy and TLS openssl through process-host * refactor(clipboard): inject runProcess, pass the Windows path as data, add an e2e - clipboard-file-copy builds the process spec itself, so the stdio policy sits next to the wl-copy/xclip knowledge it exists for; the IPC handler passes process-host's runProcess straight through and keeps no wrapper. - A helper's exit is read as data (clean exit or not) instead of being turned into a throw and caught again. - Windows runs a constant Set-Clipboard script and reads the path from the environment, so no path is ever parsed as PowerShell. - Drop the dead tls-certificate rewrite; nothing in the app imports it. - e2e: right-click Copy on Windows, then a real shell paste of the file. * ci(e2e): run the Windows explorer file-copy spec on the Windows runner Route it from the clipboard sources, keep it out of the Linux lanes, and run it in the existing Windows e2e job beside the other Windows-only specs. * refactor(clipboard): tighten the helper seam, tests and e2e after review - runClipboardHelper takes runProcess and a plain ProcessSpec. - One handler test pins the process-host wiring on every host; spec details stay in the unit tests, which now also pin the inherited environment. - e2e: native realpath so an 8.3 runner temp path still matches, paste via process-host, and no toast check that could never fail. - Route the renderer caller to the e2e too. --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
9e04ecb101 |
fix(omp): start OMP on cmd.exe when setup runs first (#29176)
* fix(omp): read the cmd fresh-config path by name so the guard survives a variable hand-over On cmd.exe, OMP's fresh-session guard referenced %ORCA_OMP_FRESH_CONFIG%, which cmd only expands while reading the typed line. When the line reaches cmd inside another variable (the setup gate's `<wait> && %ORCA_SEQUENCED_STARTUP_COMMAND%`), cmd expands once, the reference stays literal, and OMP refuses to start with "fresh OMP settings are unavailable". The guard now reads the variable by name with a one-pass for-variable, `for %! in (.) do @if exist "%~$ORCA_OMP_FRESH_CONFIG:!" ...`, so typed and handed-over lines behave the same. The older cmd prefix stays recognized for persisted lines and older hosts. A real-cmd test runs both deliveries in the Windows CI lane. * test(omp): pin the cmd guard's echo suppression and type the smoke's cmd line on stdin The real-cmd test now runs echo on, like a pane, and asserts the config path never reaches stdout, so dropping the guard's @ fails it. The manual Windows smoke typed the line into a batch file, where the guard's %! would need %%!; it now feeds cmd.exe on stdin like a pane does. The guard comment now states the real rule: only %! or %~...! text in the for body changes, and the quoter keeps prompts from forming it. |
||
|
|
da8de743eb |
feat(mobile): the phone filters and sorts with the desktop's shared Workspace options rules (#28986)
* fix(mobile): phone server rows follow the desktop's other-client and sleeping filters A phone created through a desktop now records whom it acted for, so the desktop's Hide other-client workspaces filter keeps the user's own phone workspaces (locally and on servers) and hides only other people's. The desktop relay marks each server row its sidebar would hide, and the rows its own browser or chat tabs keep awake; the phone applies both. * test(e2e): dedupe sidebar row ids in the visibility spec * fix(mobile): address review: owner naming, old-server relayed phones, scope trim * refactor: move the sidebar's project section grouping into shared The project sections the desktop sidebar draws under Group by Project are built from the project/setup projection, the per-host catalog fold, the endpoint host stamp, and the section labelling and ordering rules. Move the pure parts of each into src/shared (no behaviour change) so the paired phone can call the same code instead of guessing the grouping. * fix(mobile): group by Project with the desktop sidebar's own sections The phone grouped Project sections by repo display name, so it merged checkouts the desktop keeps apart (several local stablyai/orca checkouts, or a server's copy) and split what the desktop merges. The phone now reads each host's repo.list, project.list and projectHostSetup.list (the desktop's own and each server's through the relay), folds them with the renderer's shared catalog fold and projection merge, and builds sections with the desktop's shared grouping, labelling and ordering code. Keys, labels and Recent order equal the sidebar's; a host that predates the project lists gets the repo-derived projection, as the desktop does. Header colour and icon come from the section's anchor repo and rows from their own repo by id, as on the desktop. The repo filter lists every catalog repo by id per host instead of merging same-named repos. Group-by labels read Project and None. project.list and projectHostSetup.list are routed for paired phones (read-only, workspace permission). * refactor(mobile): record a phone's owner as creator and fold desktop tab activity into the host flag A phone now records its owner as the creator (this host for a directly paired phone, the relaying desktop for a delegated one), so the shared rule is unchanged and onBehalfOf is gone. The relay ORs the desktop's saved browser/chat tabs into hasHostSidebarActivity, so the phone's status dot follows too, and local worktree.ps counts the same signals. The old-server fallback is removed. * test(e2e): poll the phone and the sidebar together in the visibility spec * fix(mobile): one Project-section builder for desktop and phone, with the desktop's repo order Review fixes. The sidebar's buildOrderedGroups now calls the shared buildProjectSections for Group by Project (notice and pending repos are optional inputs), so desktop and phone run one function. The phone ranks manual header order by its folded catalog order, which is each host's repo.list order with the desktop's own repos first, as the renderer loads them; only the desktop's cross-host manualRepoOrder (pairing-local) is unknown to it. The projection selector is now a memo over the shared resolver. A transient project-list failure keeps that host's last catalog; only forbidden or method_not_found falls back to the repo-derived projection. Catalog rows are checked on every member grouping reads, and the parity test answers the renderer's real catalog fetch, includes a server's own project rows, and fixes Manual and Recent orders that differ. * fix(mobile): use the repo-derived catalog until a host's project lists first answer * fix(mobile): the desktop serves its sidebar's Project catalog instead of the phone fetching it The phone fetched repo.list, project.list and projectHostSetup.list from the desktop and every relay-ready server each minute and folded them itself, so rows from offline or older servers fell back to repo sections and keys moved on cold start. The desktop renderer now publishes the inputs its own Project headers use (state.repos in sidebar order, the projection selector's projects and setups, projectOrderBy) on the runtime window graph it already sends to main, only when they change. Main keeps the last one and answers it on a new paired-desktop read, mobileRelay.projectSections. The phone reads it with its repo metadata and groups with the shared builder; a desktop that predates the read (forbidden or method_not_found) leaves the phone grouping rows by repo from the desktop's repo.list, and a transient failure keeps the last catalog. The payload carries only grouping and label fields, no hooks, credentials or uploaded icons. The phone's own catalog fetching and its project.list/projectHostSetup.list routes are removed. * fix(mobile): keep uploaded repo icons on the phone, and isolate the snapshot tests * test(e2e): the desktop window serves its sidebar's Project catalog to the phone * chore(i18n): regenerate the runtime English catalog (drift already on main) * fix(mobile): read the Project catalog as its own request, outside the recorded repo-metadata flow The extra read inside the repo-metadata refresh stalled its recorded RPC sequence. It now runs beside it with its own throttle. The repo-metadata goldens are re-recorded for the intended state change: the name-keyed colour, icon and id maps became desktopRepos. * refactor(sidebar): one shared Workspace options filter and sort evaluator The sidebar, the jump palette and the options badge each applied the Workspace options filters with their own copy of the rules. They now call one pure evaluator in src/shared/workspace-view, which reads each row through a small fact reader so the phone can call it next with the facts its host serves. The sort comparator moves there too, with each surface supplying its own Agent activity rank. No behaviour change: a parity test runs the old sidebar chain and the new evaluator over every toggle combination, and the old comparator against the new one for each sort mode. * wip: workspace view descriptors * refactor(sidebar): address review of the shared Workspace options evaluator One predicate builder instead of a per-row scope argument; one exemption-narrowing function taking the hide flag; consumers import the shared predicates directly; Agent activity ties fall to the label in the shared comparator. The activation filter lift reuses the shared predicates. The parity test now covers other-client rows, live agent attention classes and the sort-label map. * fix(mobile): fetch the Project catalog at once when the screen moves to another host The refresh window is now kept per client, so a host screen reused for another desktop doesn't wait out the previous host's 60s window before showing its Project headers. * wip: desktop option items from shared choices * refactor(sidebar): the Workspace options menu renders from one shared option list src/shared/workspace-view/workspace-view-options.ts lists every Workspace options control (Hosts, Projects, Group by, Sort by, Project order, Card layout, Show properties or Card display, and each filter) with its section, its English copy, its choices and when it shows. The desktop menu walks that list and renders each option through a table keyed on the option key, so a new option fails to compile until the desktop has a control for it; the phone sheet will do the same. The choice lists (sort modes, project order, card layout, agent activity layout, card properties) are derived from the shared ids, and a test checks the desktop's English copy matches the shared copy. The unused classic branch of the card property list is removed. No visible change. * wip: row facts * refactor(sidebar): address review of the shared Workspace options list The show rules get their own tests with fixed expectations (the cases the old filter-section test covered, plus the rest), and the menu test checks each option's own control rather than any matching text. Card display rows toggle one property each, with the folder-path copy in shared. The unused Status and Tasks copy left by the removed classic card list is deleted from the catalogs. Filter rows write through the store directly; files are named for what they hold. * feat(runtime): worktree.ps carries the Workspace options row facts Each worktree.ps row now says whether it is the project's default-branch workspace, created by an automation, created by the CLI, or on a detached HEAD, answered by the same shared predicates the desktop sidebar filters with. The phone has none of these facts today, so its copies of the filters either guess (default branch) or are missing. Additive and inert: optional fields that nothing reads yet. An older host omits them; readers must treat absence as 'not that kind', so the row stays visible. Server rows relayed through the desktop pass them through unchanged. * feat(mobile): the desktop's own phone reads and writes its other-client filter ui.get and ui.set strip the pairing-local UI fields for every paired client. That rule exists for clients with their own host catalog (a desktop paired to a server, a web client). A phone has none: it shows its desktop's view, so 'Hide other-client workspaces' must be one shared value. For the host's own phone (clientKind mobile, no relaying parent) ui.get now always answers the field and ui.set persists it; delegated phones, paired desktops and web clients keep the stripping rule. The phone's view-settings schema reads the rest of the Workspace options values it does not read yet (the automation, CLI and detached-HEAD filters, project order, card properties, agent activity layout), each salvaged to absent so an older desktop keeps the phone's local value. * feat(runtime): address review of the worktree.ps row facts Name the fact defaultBranch, and say what absence means for it: a reader keeps its own guess, because 'hide default branch' must not start hiding or showing rows an older host never described. Folder workspace rows get the facts too, so every row from a newer host carries them. The desktopOtherClient comment now says it is a verdict, not a fact. The test covers the rows where the host disagrees with the phone's current guess. * wip: phone uses the shared evaluator * feat(mobile): address review of the phone's other-client filter mirror One isHostOwnPhone predicate decides both who shares the filter value (ui.get/ui.set) and who gets the other-client row marks, so the two cannot drift. The pairing-local field list notes the exception. Tests cover a paired desktop still being stripped, and a phone write that leaves the field out not touching the host value. * feat(mobile): the phone filters and sorts with the desktop's shared Workspace options rules The phone's own filter chain and comparator are replaced by the shared evaluator, reading the facts the host stamps on each row. Phone filter state takes the desktop's setting names and carries every filter; the badge and Clear filters match the desktop's. The desktop's other-client marks become facts the phone filters with the shared value. A parity test runs the same workspaces through the desktop's reading and the phone's (facts stamped as the host stamps them) over every filter combination, folder projects included. * fix(mobile): host scope in shared filters, patch-key writes, live view push Folds the phone's host filter into the shared filters so Clear and the badge agree, writes back only the touched filter keys, and pushes workspaceViewChanged so an open phone list re-reads desktop Workspace options. * fix(mobile): Clear sends only changed filters; skip a view re-read older than a local edit An older host's strict ui.set refuses a key it lacks, so Clear names only what differs. A ui.get that started before a local edit no longer overwrites it; the edit's own change event re-reads. The change publisher's field list now lives with it and derives the filter fields. * fix(workspace-options): all hosts and clear reach the desktop; one filter key list drives every surface Host visibility: the legacy host scope fallback moves to shared code; the phone reads it, and the host resets the scope whenever a client writes the host list, so All hosts and Clear stick. An older desktop that keeps the other-client filter to itself has its marks treated as hide. Badge counts, is-anything-filtered, Clear and reveal derive from the shared filter keys on the desktop sidebar and the kanban filter menu. The phone uses the desktop's group and sort values, holds its view in one state value, and reads its UI fields from one shared list. * feat(workspace-options): Status and PR grouping read the shared tables The phone groups by status with the desktop's status helpers and default catalog (its own copy had the defaults in reverse order) and by PR with a shared lane table, so its labels now read In review / In progress as the desktop's do. The desktop's PR lane decision ends in the same shared state-to-lane step. * test(sidebar): folder rows survive restrictive filters; create grace ignores non-finite times * fix(mobile): write the host scope with the host list, and wait for the first read before forcing the other-client filter An older desktop narrows back to its legacy single-host scope when the phone writes only a null host list, so the phone now also writes the scope for a null or one-host list. The other-client fallback waits for the first ui.get so a new desktop's marks don't hide rows before its filter value arrives. Inline the clear-filters key list and note the PR state asymmetry. * test(mobile): re-record view-settings goldens for the unknown other-client state * fix(sidebar): reuse the palette's default host instead of reading the focus setting again * fix(sidebar): read the host options once in Workspace options and pass them to the Hosts item * fix: parse the ui.get reply into a named type, fix the row memo test's filters, prune the focus-read baseline * refactor(sidebar): one switch-to-kind table, and fold the leftover helper files back - The four kind switches come from WORKSPACE_KIND_SWITCH in workspace-kinds; the shared evaluator and main's phone-push check both apply it, and the filter type derives its switch fields from it. - git-identity.ts folds back into git-identity-display.ts, as on main. - SidebarFilterState moves into sidebar-filter-actions.ts; visible-worktree-kinds.ts is gone. - buildWorkspaceRowPredicate is module-private. |
||
|
|
7b96a10ade |
Unify lineage child indentation across worktree card styles (#29044)
- Nested lineage children now inherit the parent card's group and content offsets through the shared child wrapper, instead of adding their own depth-based padding. - The legacy card style renders lineage children from the card surface, the same place as the experimental style, so both styles share one layout path. - Removes `getLineageNestedRowGeometry`, which double-counted the parent's inset for experimental cards and used a different path for legacy cards. - Titles of nested workspaces no longer drift right with each lineage level, which left them misaligned in grouped sidebars. |
||
|
|
efd7e50e0a |
fix(ssh): start a managed server that stopped, on every connect path (#28996)
A connect that found its own build already active launched nothing, so a server killed or stopped by a reboot failed on its stale record (#27284). A stopped server whose recorded port another runtime took failed the tunnel's identity check before any serving check could start it (#28013). Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: yuzhichang <153784+yuzhichang@users.noreply.github.com> |
||
|
|
635d3853f1 |
fix(agent.launch): avoid blank shells when launching new workspaces (#28451)
* fix: avoid blank shells beside new workspace chats * Carry promised agent chat through worktree creation * Use live agent launch inventory for new workspace surfaces * Type live agent launch owner from runtime contract * Assert one recovery shell after failed agent launch * Keep worktree activation adapters out of creation flow * Restore ordinary workspace setup handoff after launch correction * Cover the phone's agent.launch workspace create in the first-surface flow test |
||
|
|
cbc357f547 |
fix(browser): agent typing into a cross-site frame no longer borrows your keyboard (#29000)
* fix(browser): agent typing into a cross-site frame no longer borrows the user's focus Keys and text for a focused cross-site iframe went through the focus-borrowing fallback, because widget input reaches only the guest's own renderer. They now go to that frame's own CDP target session, found by following the page's focus through frame elements, which reaches the frame without touching the user's focus. The proxy keeps those Orca-owned sessions' events from the agent's client. * fix(browser): retry frame focus emulation after a failed enable * fix(browser): retry a failed frame focus-emulation enable before sending input |
||
|
|
e0c6ae43ac | test: guard remote input model from default RPC manifest (#29012) | ||
|
|
13a1e9b3fc |
test: consolidate structured session close suites (#28970)
* test: consolidate structured session close suites * test: join session close work before fixture teardown * test: capture held retirement before close ownership clears |
||
|
|
446cedc0e9 |
fix(notifications): hidden workspaces stop notifying unless you opt in (#28870)
* refactor(sidebar): one Filters-switch predicate, kind predicates in shared
The sidebar's Filters switches were applied as five separate filters plus a
sleeping sweep inside computeVisibleWorktrees. They now go through one
isHiddenBySidebarSwitch predicate, and the workspace-kind predicates
(default branch, automation, CLI, detached HEAD) move to
shared/worktree/workspace-kinds so main can apply the same rules. The git
identity display moves to shared with them. No behaviour change.
* feat(notifications): hidden workspaces send no notifications unless opted in
A workspace hidden by a switch in the sidebar's Filters menu (sleeping,
default branch, automation, CLI, other-client, detached HEAD) now raises
no unread marker, banner, sound, tray dot or phone push. A new setting,
Settings > Notifications > "Notify about hidden workspaces", defaults off
and restores today's behaviour when on.
The renderer gate sits first in resolveAgentAttention, which every
terminal completion, bell and structured-chat edge passes through before
the unread write and the notification request; the bell's own early
marker write checks the same predicate. For local structured chat, main
pushes phones itself, so that push applies the kind switches main can
evaluate from persisted UI and workspace records. Anything unknown,
unhydrated, or a hidden parent the sidebar still shows notifies.
* fix(notifications): hidden-workspace review fixes
- Main's phone push now honours "Hide other-client workspaces" for this
host's worktrees and folder workspaces, through a shared
isCreatedByAnotherClient that the sidebar's no-environment branch uses too.
- The renderer mute fails open until terminals reconnect: before then Hide
sleeping reads every restored workspace as asleep.
- The settings row stays usable when notifications are off (it also governs
unread dots), uses Title Case, and its copy names the Hide switches.
- The mute check moves to attention/, and the switch list behind its fast
path is a full Record so a new switch cannot be skipped.
- A notification field the settings file predates is no longer a repair,
so upgrades do not rewrite every profile.
* refactor(notifications): simplify missing-field repair check
* refactor(notifications): ask the sidebar pipeline whether a workspace is hidden
- The renderer mute check now runs computeVisibleWorktreeIds with the
project and host filters lifted instead of re-walking lineage by hand,
so lineage parents and same-id rows on other hosts follow the sidebar
exactly. The pure pipeline moves to compute-visible-worktrees.ts so the
store's attention slice can call it without an import cycle.
- Drops the switch-list shortcuts in favour of sidebarHasActiveFilters
(renderer) and none (main), and the folder one-caller wrapper.
- Main reads notifyHiddenWorkspaces once, in deliver, next to its other
eligibility checks; isStructuredAttentionWorkspaceHidden only answers
whether Filters hide the workspace, and isWorkspaceHidden is required.
- Reverts the settings-repair generalisation; a one-time rewrite on
upgrade is fine.
* test(notifications): wire the hidden-workspace check into e2e fixtures, and an e2e for the flow
The structured-attention e2e unit fixtures built the main phone-push
delivery without the now-required isWorkspaceHidden, so deliver threw and
no prompt reached the relay; they now pass () => false and carry the
notifyHiddenWorkspaces field. A new Playwright spec rings a real BEL in the
seeded primary checkout with Settings open and checks the unread dot and
the main-process notification request: present while visible, absent under
Hide default branch, and back with Notify About Hidden Workspaces on.
* test(e2e): type the hidden-workspace dispatch log as a declared global
* fix(notifications): exempt a hidden lineage parent only while a child is shown
* perf(notifications): answer the mute check per row before the full sidebar pass
A row the Filters switches show is visible, and a hidden row that no
lineage record names as a parent cannot be shown above a child, so only a
hidden lineage parent needs computeVisibleWorktreeIds. At 1,000 workspaces
a mute check drops from ~0.2-0.3 ms to ~6 us.
* Revert "perf(notifications): answer the mute check per row before the full sidebar pass"
This reverts commit
|
||
|
|
bcaed523cd | ci: contain persistent transforms and trim model overhead (#28948) | ||
|
|
d371e2d8b6 | ci: reduce runner occupancy in release and contract jobs (#28930) | ||
|
|
6837a4c180 |
fix(ssh): a relay-era desktop can join the server another desktop on the same login runs (#28886)
* fix(ssh): a relay-era desktop can join the server another desktop on the same login runs A desktop that still had relay-era projects on a host whose managed server another Orca version ran could never connect: its migration skipped the running-version adoption, so it deferred on a terminal count only a paired server can give. Once the versions matched it failed instead because the server already held the same repository path, added by the other desktop. The migration now pairs with the running server like a fresh desktop does, before any upload. Projects the server already holds at the same host path are linked to the server's project instead of imported twice: the journal is re-cut without them, under the same migration id, only after the server proves it holds nothing of the earlier manifest. A conflict the server will keep refusing now says what conflicts and how to get past it. * fix(ssh): never link a project a bridged relay terminal still runs in The bridge reattaches a relay pane only into its own tab, which a linked project never sends to the server, so linking would leave that terminal running out of sight. Refuse the link instead, naming the project and how to end the terminals. * test(ssh): run the link test on Node's SQLite runtime and read the host's activation record * test(ssh): establish desktop B's profile before seeding its relay-era state * test(ssh): connect desktop B's host explicitly in the shared-login spec * fix(ssh): say what a linked project left behind, and never blame it for an unowned relay terminal A project this desktop moved that the host's server already held is linked to the server's copy, so its tabs and automations from this desktop stay behind. The connect now carries those linked projects and the SSH host card says so, with the automation count, instead of dropping them silently. A bridged relay terminal of unknown or removed project still blocks a link, but its guidance no longer names the linked project as where it runs. Both terminal messages now offer removing the project from this desktop as the way out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
79589c07c1 |
feat(layout): publish each pane's live terminal title on the layout stream (#28928)
The layout stream (layout.subscribe, still unused) now carries the title each pane's terminal shows now, as an optional liveTitle on the pane. It is laid over the stream's cached projection with its own trigger, so a title change reads no Store data and projects no partition; changes in one task coalesce in the existing microtask flush. The trigger is the per-PTY fan-out that already skips spinner-only title frames, so an agent's spinner sends no frames. The latency spec gains a title-flood phase. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7cf09809f6 |
fix(mobile): group by Project with the desktop sidebar's own code (#28850)
* fix(mobile): phone server rows follow the desktop's other-client and sleeping filters A phone created through a desktop now records whom it acted for, so the desktop's Hide other-client workspaces filter keeps the user's own phone workspaces (locally and on servers) and hides only other people's. The desktop relay marks each server row its sidebar would hide, and the rows its own browser or chat tabs keep awake; the phone applies both. * test(e2e): dedupe sidebar row ids in the visibility spec * fix(mobile): address review: owner naming, old-server relayed phones, scope trim * refactor: move the sidebar's project section grouping into shared The project sections the desktop sidebar draws under Group by Project are built from the project/setup projection, the per-host catalog fold, the endpoint host stamp, and the section labelling and ordering rules. Move the pure parts of each into src/shared (no behaviour change) so the paired phone can call the same code instead of guessing the grouping. * fix(mobile): group by Project with the desktop sidebar's own sections The phone grouped Project sections by repo display name, so it merged checkouts the desktop keeps apart (several local stablyai/orca checkouts, or a server's copy) and split what the desktop merges. The phone now reads each host's repo.list, project.list and projectHostSetup.list (the desktop's own and each server's through the relay), folds them with the renderer's shared catalog fold and projection merge, and builds sections with the desktop's shared grouping, labelling and ordering code. Keys, labels and Recent order equal the sidebar's; a host that predates the project lists gets the repo-derived projection, as the desktop does. Header colour and icon come from the section's anchor repo and rows from their own repo by id, as on the desktop. The repo filter lists every catalog repo by id per host instead of merging same-named repos. Group-by labels read Project and None. project.list and projectHostSetup.list are routed for paired phones (read-only, workspace permission). * refactor(mobile): record a phone's owner as creator and fold desktop tab activity into the host flag A phone now records its owner as the creator (this host for a directly paired phone, the relaying desktop for a delegated one), so the shared rule is unchanged and onBehalfOf is gone. The relay ORs the desktop's saved browser/chat tabs into hasHostSidebarActivity, so the phone's status dot follows too, and local worktree.ps counts the same signals. The old-server fallback is removed. * test(e2e): poll the phone and the sidebar together in the visibility spec * fix(mobile): one Project-section builder for desktop and phone, with the desktop's repo order Review fixes. The sidebar's buildOrderedGroups now calls the shared buildProjectSections for Group by Project (notice and pending repos are optional inputs), so desktop and phone run one function. The phone ranks manual header order by its folded catalog order, which is each host's repo.list order with the desktop's own repos first, as the renderer loads them; only the desktop's cross-host manualRepoOrder (pairing-local) is unknown to it. The projection selector is now a memo over the shared resolver. A transient project-list failure keeps that host's last catalog; only forbidden or method_not_found falls back to the repo-derived projection. Catalog rows are checked on every member grouping reads, and the parity test answers the renderer's real catalog fetch, includes a server's own project rows, and fixes Manual and Recent orders that differ. * fix(mobile): use the repo-derived catalog until a host's project lists first answer * fix(mobile): the desktop serves its sidebar's Project catalog instead of the phone fetching it The phone fetched repo.list, project.list and projectHostSetup.list from the desktop and every relay-ready server each minute and folded them itself, so rows from offline or older servers fell back to repo sections and keys moved on cold start. The desktop renderer now publishes the inputs its own Project headers use (state.repos in sidebar order, the projection selector's projects and setups, projectOrderBy) on the runtime window graph it already sends to main, only when they change. Main keeps the last one and answers it on a new paired-desktop read, mobileRelay.projectSections. The phone reads it with its repo metadata and groups with the shared builder; a desktop that predates the read (forbidden or method_not_found) leaves the phone grouping rows by repo from the desktop's repo.list, and a transient failure keeps the last catalog. The payload carries only grouping and label fields, no hooks, credentials or uploaded icons. The phone's own catalog fetching and its project.list/projectHostSetup.list routes are removed. * fix(mobile): keep uploaded repo icons on the phone, and isolate the snapshot tests * test(e2e): the desktop window serves its sidebar's Project catalog to the phone * chore(i18n): regenerate the runtime English catalog (drift already on main) * fix(mobile): read the Project catalog as its own request, outside the recorded repo-metadata flow The extra read inside the repo-metadata refresh stalled its recorded RPC sequence. It now runs beside it with its own throttle. The repo-metadata goldens are re-recorded for the intended state change: the name-keyed colour, icon and id maps became desktopRepos. * fix(mobile): fetch the Project catalog at once when the screen moves to another host The refresh window is now kept per client, so a host screen reused for another desktop doesn't wait out the previous host's 60s window before showing its Project headers. |
||
|
|
3b11b7ac94 |
fix(mobile): phone server rows follow the desktop's other-client and sleeping filters (#28819)
* fix(mobile): phone server rows follow the desktop's other-client and sleeping filters A phone created through a desktop now records whom it acted for, so the desktop's Hide other-client workspaces filter keeps the user's own phone workspaces (locally and on servers) and hides only other people's. The desktop relay marks each server row its sidebar would hide, and the rows its own browser or chat tabs keep awake; the phone applies both. * test(e2e): dedupe sidebar row ids in the visibility spec * fix(mobile): address review: owner naming, old-server relayed phones, scope trim * refactor(mobile): record a phone's owner as creator and fold desktop tab activity into the host flag A phone now records its owner as the creator (this host for a directly paired phone, the relaying desktop for a delegated one), so the shared rule is unchanged and onBehalfOf is gone. The relay ORs the desktop's saved browser/chat tabs into hasHostSidebarActivity, so the phone's status dot follows too, and local worktree.ps counts the same signals. The old-server fallback is removed. * test(e2e): poll the phone and the sidebar together in the visibility spec |
||
|
|
1f50bd305f | Reduce unrelated setup in attention and mailbox fixtures (#28897) | ||
|
|
39815a086f |
Reduce CI import, frame-capture, teardown, and shard costs (#28879)
* Avoid unused module imports and trim cosmetic test coverage * Capture hidden popup frames and attach CDP before guest creation * Overlap relay test projects within the existing worker budget * Consolidate native preparation and add an opt-in transform cache comparison * Release inherited debugger sockets during final E2E teardown * Refresh unit scheduling weights from all five qualified ARM shards * Avoid retaining unasserted RPC call history in the delivery model * Use the supported unconditional background wait syntax * Overlap unconditional output upload with native preparation * Verify relay integration stays enabled for ordinary unit callers |
||
|
|
8a6cc6c138 |
fix(terminal): bring each pane back after a terminal service restart when it is shown (#28880)
* fix(terminal): bring each pane back after a terminal service restart when it is shown After Settings -> "Restart terminal service", every pane that was open kept its dead process: typing did nothing and agents never resumed until Orca relaunched. A restart-replaced exit now arms the pane: the visible pane spawns its replacement at once, any other pane when it is next shown, through the same fresh spawn and cold-restore agent resume the hibernation wake uses, so old output stays above the new prompt. The exit keeps the agent status the resume reads, and clears the dead binding so the replacement binds as a first spawn. Local spawns wait for an in-flight restart so they reach the new daemon. Claude-Session: p2-headless * fix(terminal): resume from the live recovery record; skip a pane another flow rebound A restart exit is a process death to main's agent-status store, which clears the pane's row before the window sees the exit, so keeping the window's copy changed nothing. The resume reads the live recovery record every agent turn already writes, as a relaunch after a crash does. The replacement also stands down when the pane's stored binding already names another process. Claude-Session: p2-headless * fix(terminal): send every restart exit down one path A finished-turn agent pane took the hibernation wake, which gives up when its record changes before the pane is shown. Every restart exit now arms the replacement directly. Claude-Session: p2-headless |
||
|
|
6607c54984 |
perf(ci): cut redundant tests and reuse expensive setup (#28669)
* perf(ci): reduce test overhead and reuse expensive build work * test(ci): keep worker startup outside failure-case deadlines * test: isolate push fixture advisory locks * test(ci): preserve fixed drain retry allowance * Align CI contracts with current triggers and guide content * Stabilize consolidated reveal scenarios and retain behavioral CI contracts * Fix upstream lint blockers while retaining behavior and assertions * Classify global Jira preferences in the WSL migration inventory * Align Jira test fixtures with startup and build safety checks * Include package-test routing dependency in CI checkouts and fixtures * Keep native stream classes intact in transcript dependency tests |
||
|
|
cc7d03d19c |
fix(daemon): keep every pane in main's layout through a terminal service restart (#28852)
Restarting the terminal service ends each session with a synthetic -1 exit. Main read those as ordinary deaths and retired every terminal surface from the saved layout, while the window kept drawing them. Phones and the CLI lost the tabs, and the next launch restored a split as a single pane. The restart now labels those exits as replaced, and main records them in its existing intentional-stop register, the one terminal restarts already use. The runtime keeps the surface and the window receives the same replaced label. Claude-Session: p2-headless |
||
|
|
23103e511a |
perf(layout): re-project only the written partition in the layout stream (#28845)
The layout stream (layout.subscribe, still unused) re-loaded every session partition and ran the load's save-and-diff report after each write. A save now names the partition it wrote, the stream re-loads only that partition without the report, and the renderer layout client no longer re-subscribes on a timer. Adds a latency spec variant with a subscriber attached. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
b024043feb |
refactor(tabs): delete unused copy-tab and merge-group store actions (#28836)
* refactor(tabs): delete unused copy-tab and merge-group store actions copyUnifiedTabToGroup and mergeGroupIntoSibling had no callers outside the store and its tests. Tests that used the copy action as a setup step now create the duplicate tab directly, the same call the action made. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore(tabs): follow the split-ratio file rename in the layout-writer baseline Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8f83f6b076 |
feat(wsl-mover): pause a moving project's terminals through Sleep and prove they exited (D1b-5d) (#28820)
* feat(wsl-mover): pause a moving project's terminals through Sleep and prove they exited (D1b-5d) * fix(wsl-mover): gate again under the fence, swap journal phases atomically, keep sessions frozen through commit (D1b-5d) * test(wsl-mover): the fence e2e walks the journal one phase at a time, as a move writes it (D1b-5d) |
||
|
|
b0308f24ef |
feat(wsl-mover): refuse edits to a project a WSL move is taking (D1b-5c-2) (#28761)
* feat(wsl-mover): refuse edits to a project a WSL move is taking, and drop its background bookkeeping quietly (D1b-5c-2) * fix(wsl-mover): hide only local rows of a moved project; the host's own row keeps its id (D1b-5c-2) * fix(wsl-mover): refuse a user's unread toggle, fence branch deletes, host setups and issue commands; settings unfreeze once the host owns a repo (D1b-5c-2) * test(wsl-mover): the fence e2e refuses edits to moving projects and drops their bookkeeping quietly (D1b-5c-2) * refactor(wsl-mover): name the update type the fence inspects (D1b-5c-2) * test(wsl-mover): run the fence tests that open a real store in the Node runtime (D1b-5c-2) * fix(wsl-mover): a host setup's own repo stays frozen once the host owns it; e2e pins the quiet drop (D1b-5c-2) |
||
|
|
dfafde6a7f |
test(cross-version): pin the ephemeral-key and source-fence downgrade tests to v1.4.224 (#28803)
v1.4.225 ships both capabilities, so the newest release no longer models an old host. Pin each to the last release without its capability, as the other downgrade tests in the suite already do. |
||
|
|
b85597cbfa |
fix(serve): restore a remote server's browser tabs after it restarts (#28166)
* feat(serve): keep browser tabs across an orca serve restart A host with no window now saves the browser tabs it opens in the same shape a desktop window saves its own, and restores them the same way: listed at once with their last address, each page started when a client first opens or drives it. A closed tab is forgotten; a page that ends with the process is not a close. * test(e2e): the server's published strip now holds its saved browser tab * fix(serve): save browser addresses cheaply, open once, restore by page id Review fixes: a page's address is written onto its saved records without reloading the layout, and only on committed navigations; reopening a saved page writes nothing; a command naming only the page finds the workspace that saved it; a refused save no longer throws from a page event or a close. The browser-tab map is renamed to say it lists saved tabs too. * fix(serve): list, switch and close saved browser tabs from commands that name no page or worktree * fix(serve): a tab list does not start saved pages; only a command acting on a page does * fix(serve): a pageless command starts the browser tab the layout shows, not the first saved one A host now records the browser tab a window would show: the one it just opened, and the one a tab switch picks. With nothing running, a command that names no page starts that tab; when the layout shows none it starts nothing and reports no browser tab open. * fix(serve): report the saved active browser tab as current Claude-Session: p2-headless * chore(ratchet): count the serve browser-tab save as a main-process layout writer Claude-Session: p2-headless * fix(serve): use the window's active browser tab rule, one scope, one active row Claude-Session: p2-headless * fix(browser): pick the active tab among tabs this host can start A desktop document page or a remote page recorded as active no longer leaves a pageless command with no tab. Adds a test for the first-saved-worktree scope. Claude-Session: p2-headless * refactor(browser): restore saved serve tabs through the page wake point Saved serve browser tabs now start where a window would mount them: the two existing wake helpers ask one host hook before messaging a window. The offscreen backend reports opened and moved pages, so the command layer no longer threads save, list, select or close hooks. No worktree named and no page running reports no tab, as a window does. Claude-Session: p2-headless * fix(browser): only page creation opens a saved serve tab A navigation now only updates an existing saved tab, so a late load after a close cannot re-add it; a restored page sends no open, so its saved title stays. Claude-Session: p2-headless * refactor(browser): drop the restore mark the open/navigate split made redundant Claude-Session: p2-headless * refactor(browser): save serve tabs from the create command, list unstarted ones as tab rows The create command saves the tab (it holds the group), so the backend reports only navigations. Unstarted saved tabs are tab-info rows the existing listings take as-is, the restore dedupe map goes (a created page registers before createTab returns), and one lookup gives a page's unified tab id. Claude-Session: p2-headless * fix(browser): opening a serve browser tab no longer records it as active Which tab shows is a view's choice; after a restart the active tab is the one a window recorded, else the first. Claude-Session: p2-headless * fix(browser): give the composed browser command owners the saved-tab host member Completes the forward merge of main's browser command split (#27576). Claude-Session: p2-headless |
||
|
|
3e25fe70f6 |
fix(unread): a pane is read when it is on screen; closing a waiting tab clears its dot (#28637)
* test(unread): characterize today's workspace and pane unread transitions Pins, against the real store, what every unread trigger does today: the workspace flag per host row, the three tab/pane marker maps, persistence calls and payloads, lastActivityAt and sortEpoch bumps, the Dock count and the floating launcher dot. Events are replayed through one driver file so a later rewiring of who writes the state changes only the driver, never these expectations. * refactor(unread): one workspace-attention module owns every unread transition Every write to the workspace unread flag and the tab/pane/completion markers now goes through src/renderer/src/store/slices/workspace-attention: store operations named by the triggering event (bell, agent attention, pane input, viewed-agent auto-ack, manual mark read/unread) and pure transitions folded into other slices' set() calls (activation, tab activation, close, sleep, hibernate, retire, rekey, reconcile, mirror removal, purge, acknowledge). Behaviour, storage, readers, persistence and wire format are unchanged; the characterization suites pass without edits to their expectations. * refactor(unread): review fixes for the workspace-attention module - Ratchets: moved terminal-tab-attention baseline entries to terminal-tab-appearance; split the characterization setup/observables into an exempt fixture so the driver holds only events. - Removed the test-only writer seam; mocked-store tests assert the event they fire. - The slice owns the experimental pane gate for completions too; groupAttentionEnabled is gone from the attention request and write. - Collapsed marker removals to removeTabsAttention / removePanesAttention / removeCompletionAttention / removeTabMarkers / movePaneAttention; tab activation uses omitRecordKeys. - Mark read/unread is passed in like other store actions; readers of the workspace dot go through isWorkspaceUnread. * feat(unread): on screen means read; the workspace flag follows its markers While Orca's window is visible and focused, the tabs on screen (active tab of the active workspace, plus an open floating panel) are read: every tab, pane and completion marker of each. One scan (the auto-ack hook, now startViewedAttentionScan) replaces the keydown, pointerdown, tab activation, group focus, workspace activation and auto-ack marker clears. After a read, close, sleep, hibernate, retire or purge that removed a marker, a workspace's flag is cleared once no tab or completion marker remains on a live tab; a marker-less flag (Mark as unread, restart, another client) is read when its workspace comes on screen. Mark as read removes every marker in the workspace. Reads and removals dismiss the affected panes' OS notifications in one IPC call. * fix(unread): a bell or completion already on screen leaves no marker or flag write Marking now asks the scan's own on-screen rule (isTabOnScreen: the window is visible and focused and the tab is a scan target), so an on-screen bell no longer persists the flag true then false. A completion in any split pane of the tab on screen is viewed, matching the read. A superseded turn's completion-marker removal settles the flag and dismisses like other removals. * fix(unread): read the screen across hosts, groups and non-agent views; mark only for an absent user - Arriving at a workspace in its own view settles its flag even when it shows an editor, browser or nothing; Settings and other views read nothing. - A bell or completion on screen skips marking only when the user is confirmed present under the scan's own presence gate (input, or main reporting the desktop active within the shared away threshold); otherwise it marks and the gated scan reads it when the user returns. - The active workspace's host is part of the screen, so switching same-id folder rows between hosts is an arrival on the new host. - Removal settles lower every same-id folder row and persist each host. - Opening and closing the floating panel both rescan. - Every visible tab group's active tab is on screen, not only the focused one. - One pane-key parser, one marker-tab enumeration, one removal wrapper (settleAttentionRemovedBy), one remove-and-dismiss; the hook is now useReadOnScreenAttention over on-screen-attention-scan.ts, and terminal keystrokes reach presence through a capture-phase window keydown. * fix(unread): presence only from renderer input; host-exact folder flags; subjectless completions follow the screen - Main's 'not away' answers only the scan that asked; presence is stamped only by trusted input (wheel included), so it can't outlive the threshold. - isWorkspaceViewed uses the on-screen rule (workspace view showing, focused window, user present), so a subjectless completion marks under Settings or while away. - Folder flag writes resolve the row's host like updateFolderWorkspace does (project-group fallback), so the row flipped and the owner persisted match. - A runtime host purge dismisses but doesn't settle flags of surviving rows. - DESKTOP_AWAY_SECONDS is the shared threshold's neutral name. * test(unread): folder flag persists name the row's host * test(unread): drop casts from the folder persistence seeds * fix(unread): point the reliability gate and e2e fixture at the renamed on-screen hook * refactor(unread): drop reshapes the follow-up deletes; keep the flag functions module-internal Reverts the reconcile/mirror/activation/focus/group call sites and the isWorkspaceUnread selector to main, removes removeTabMarkers, removeCompletionAttention and the activation read helpers, and drives tests through public attention actions. * test(unread): read the Dock badge flag down by putting its tab on screen * fix(unread): keep the on-input read action removed after merging main |
||
|
|
93baa828be |
refactor(unread): one workspace-attention module owns every unread transition (#28538)
* test(unread): characterize today's workspace and pane unread transitions Pins, against the real store, what every unread trigger does today: the workspace flag per host row, the three tab/pane marker maps, persistence calls and payloads, lastActivityAt and sortEpoch bumps, the Dock count and the floating launcher dot. Events are replayed through one driver file so a later rewiring of who writes the state changes only the driver, never these expectations. * refactor(unread): one workspace-attention module owns every unread transition Every write to the workspace unread flag and the tab/pane/completion markers now goes through src/renderer/src/store/slices/workspace-attention: store operations named by the triggering event (bell, agent attention, pane input, viewed-agent auto-ack, manual mark read/unread) and pure transitions folded into other slices' set() calls (activation, tab activation, close, sleep, hibernate, retire, rekey, reconcile, mirror removal, purge, acknowledge). Behaviour, storage, readers, persistence and wire format are unchanged; the characterization suites pass without edits to their expectations. * refactor(unread): review fixes for the workspace-attention module - Ratchets: moved terminal-tab-attention baseline entries to terminal-tab-appearance; split the characterization setup/observables into an exempt fixture so the driver holds only events. - Removed the test-only writer seam; mocked-store tests assert the event they fire. - The slice owns the experimental pane gate for completions too; groupAttentionEnabled is gone from the attention request and write. - Collapsed marker removals to removeTabsAttention / removePanesAttention / removeCompletionAttention / removeTabMarkers / movePaneAttention; tab activation uses omitRecordKeys. - Mark read/unread is passed in like other store actions; readers of the workspace dot go through isWorkspaceUnread. * refactor(unread): drop reshapes the follow-up deletes; keep the flag functions module-internal Reverts the reconcile/mirror/activation/focus/group call sites and the isWorkspaceUnread selector to main, removes removeTabMarkers, removeCompletionAttention and the activation read helpers, and drives tests through public attention actions. |
||
|
|
dc146c09e2 |
fix(ssh): the CLI, phone and paired clients no longer list a converted host's retained rows (#28754)
* fix(ssh): the runtime lists a converted host's retained rows as hidden, as the desktop does * fix(ssh): never name a converted host as uncovered in runtime worktree listings * fix(ssh): a scoped worktree listing never names a hidden host either |