Commit Graph
11162 Commits
Author SHA1 Message Date
ef563bccf4 fix(ssh): stop stale saved state from blocking an SSH host's move to a managed server (#29003)
* fix(ssh): stop stale saved state from blocking an SSH host's move to a managed server

Leftover records nobody can see or close (empty host tab rows beside the
desktop's older copy, phone tab selections naming missing tabs, agent "seen"
markers, client-hosted pages, isolated-profile browser tabs) now move or stay
behind in the retained profile instead of refusing the move. What still
refuses is live or unsaved work, and the refusal now names each item and how
to clear it.

Fixes #27281
Fixes #28946

Co-authored-by: akushonkamen <akushonkamen@163.com>

* fix(ssh): build the export copy without editing saved layout fields in place

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: akushonkamen <akushonkamen@163.com>
2026-10-15 01:23:39 -07:00
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>
2026-10-15 01:23:34 -07:00
Neil 44735c605e Check automation and persisted terminal surface types (#28373) 2026-10-15 01:21:57 -07:00
Brennan Benson 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
2026-10-15 01:21:24 -07:00
Jinjing 8e35055448 Increase chat transcript bottom padding so reply controls clear the comp (#29046)
The last reply's controls hang 20px below their row (-mb-5), but the transcript only reserved 16px of bottom padding, so they crowded the composer. Raise the bottom padding from pb-4 to pb-10 so the controls have room.
2026-10-15 01:10:48 -07:00
Brennan Benson e5bdc23f99 fix(native-chat): recognize missing history before chat creation (#28261)
* fix(native-chat): recognize missing transcripts refused before create

* Classify vanished transcript during precommit import

* test: expect uncertainty context on resumed chat launches

* test: keep only the tests that pin user-visible behavior
2026-10-15 00:52:16 -07:00
Neil caa4155e61 Check terminal pane recovery types (#28372) 2026-10-15 00:43:10 -07:00
Jinwoo Hong 78bb358c72 fix(linux): run each terminal in its own systemd scope so one out-of-memory kill no longer closes every terminal (#28871)
* refactor(daemon): rename the PTY process ceiling modules to terminal scopes

Pure move ahead of making per-terminal scopes the Linux default.

* fix(linux): run each terminal in its own systemd scope

The daemon and every terminal shared one systemd scope, so one kernel OOM
kill stopped the whole scope, systemd-oomd killed every terminal at once,
and all terminals shared one TasksMax. When the daemon runs in the fresh
scope its launcher made, each terminal now gets its own transient scope
under a slice bound to the daemon's scope, as the opt-in process ceiling
already did. OOMPolicy=continue is used where a probe scope accepts it,
the ceiling becomes TasksMax per terminal, and oomd is asked to avoid the
daemon's scope. The slice's binding replaces the death watch's slice
argument and the exit-time slice stop.

* test(linux): cover per-terminal scopes in the daemon scope Docker harness

Runs on systemd 249, 252 and 257: an OOM kill in one terminal leaves the
daemon and the other terminals running, the process ceiling applies per
terminal, and stopping the daemon scope or SIGKILLing the daemon reaps the
slice and every terminal. The baseline reports today's whole-daemon kill.

* chore: prune the sync-spawn baseline after removing the exit-time slice stop

* fix(linux): read the terminal scope wrappers as no foreground process yet

systemd-run and env own a new terminal until the shell execs, which took up
to ~270 ms per terminal when 50 started at once on Ubuntu 24.04. Reported as
the foreground, they read as running work and could pass the four-poll
child-process readiness gates before the shell existed.

* fix(linux): simplify terminal scope state and keep scopes without pids delegation

One nullable runtime replaces the unread ceiling state; losing the slice
logs once and later terminals stay in the daemon scope. The probe no longer
fails when pids.max is absent, so only the ceiling turns off there. The
resolution is one on/off value, the launch id comes from the daemon scope
alone, and the ManagedOOMPreference request no longer blocks startup. The
foreground filter matches Orca's exact wrapper paths, so a user-run
systemd-run stays visible.

* refactor(linux): name the terminal slice from the daemon scope and start the oomd hint at init

The slice and scope names now come from the daemon scope's own unit name, so
nothing parses its prefix back out. The ManagedOOMPreference request moves
out of the resolver into initializeTerminalScopes, where a spawn error can
no longer land in the resolver's catch after the slice exists.

* test(linux): run the terminal scope wrapper foreground test off Windows only

* test(linux): tolerate an already unloaded scope after the baseline OOM stop

* fix(linux): read Orca's scope wrapper as the shell, and bound startup systemd calls

node-pty names the wrapper path both while it execs the shell and as its
spawn file once the foreground group's leader has exited (true | claude,
seq | less). Hiding it skipped the agent scan; reporting the shell instead
matches what the unwrapped spawn reports. Each startup systemd call now
times out after 1.5 s, so a wedged user manager turns terminal scopes off
inside the launcher's 10 s wait instead of failing the launch.

* fix(linux): mark a timed-out terminal scope setup in the daemon log

A busy user manager and one that refused both reported slice_unavailable.
The log-only off detail now carries timedOut: true for the first; the
reported ceiling reason and the wire are unchanged.
2026-10-15 03:34:22 -04:00
Neil 08257b94aa test: avoid unused imports while preserving export contracts
Preserve test behavior and public export coverage while removing unnecessary module loading from orchestration and pure-function suites.
2026-10-15 00:29:33 -07:00
Jinwoo HongandClaude Opus 5.5 2885bc3e92 refactor(ssh): keep SSH terminal bindings on disconnect, reconnect and wake (one rule, main's) (#29036)
* refactor(ssh): stop the window clearing SSH terminal bindings on disconnect, connect and wake

The window dropped every SSH tab's terminal binding when an SSH host disconnected,
reconnected or the computer woke. Main's rule is the opposite: only a host-confirmed
stop withdraws a binding, because losing contact is not evidence the remote shell
exited. Startup already moves restored SSH bindings out of the tab, so the clear had
nothing left to act on. Delete it, its scope resolver and the wake listener.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ssh): reduce the direct-SSH scope to the worktree ids its one caller reads

Removing the binding clear left terminalWorkspaceKeys and the folder evidence path
with no reader; gitRepos, lineageWorkspaceKeys and the owner counts had none
already. SSH target cleanup only reads the worktree ids, so return just those.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:26:08 -04:00
Jinjing 62c6e99144 fix(native-chat): Use short effort label in the model pill (#29029)
The model pill in the native chat header showed the full effort name, such as "Medium", which crowded the pill. It now uses the same compact label as the effort segments, such as "Med", so the pill fits.
2026-10-15 00:21:10 -07:00
Neil cc690cfe4b feat(jira): add bounded site-specific favourite filter catalogue (#29028) 2026-10-15 00:07:43 -07:00
Neil 5931104e16 Check orchestration terminal authority types (#28371) 2026-10-15 00:02:24 -07:00
Jinjing 25908865b0 Bump Electron to 43.7.8 to fix find-in-page looping (#28909)
* Bump Electron to 43.7.8 to fix find-in-page looping

Find-in-page could loop when the host page contained iframes beside a
webview, so searches in the guest did not finish or wrap correctly.
Electron 43.7.8 includes the upstream fix (electron/electron#54199).

- Pin electron to 43.7.8 in package.json, pnpm-lock.yaml, and the
  Node runtime pin.
- Raise the runtime floor in electron-runtime-floor.test.ts to 43.7.8.
- Add an Electron regression test that runs a find traversal in a
  background window with host iframes before, after, and around a
  webview, checking forward and backward matches wrap correctly.

* rm junk file
2026-10-15 00:02:12 -07:00
Jinwoo HongandClaude Opus 5.5 41a78bb9bd test(layout): list the window-parity differences that are not bugs separately (#29014)
* test(layout): list the window-parity differences that are not bugs separately

The parity test listed five differences between the window's startup view of a stored
session and of the shared Loader's rewrite of it. Three are not bugs: the row terminal
rewrite (the pane binding wins on mount), legacy surface tombstones (the window is the
outlier) and label over title (only phones and the CLI show the row title). They move
to ACCEPTED_DIFFERENCES with a reason each; KNOWN_DIFFERENCES keeps only the ghost tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(layout): pin the values of accepted window-parity differences

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:00:40 -04:00
Jinwoo HongandClaude Opus 5.5 f6d5086c7d feat(persistence): one-time profile backup before startup rewrites saved data (#29016)
* feat(persistence): one-time profile backup before boot-time saved-data migrations

Adds ensureProfileStatePreMigrationBackup: a validated copy of the profile database,
written next to it as profile-state.db.pre-migration.db, taken once before the first
boot-time rewrite of saved layouts and never replaced afterwards. It returns 'failed'
instead of throwing so the caller skips the migration when the copy cannot be written
(e.g. disk full). Nothing calls it yet; the startup layout migration will.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(persistence): name the lock that keeps one owner per profile

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 02:42:52 -04:00
Brennan Benson d9de1fad1d Native chat: desktop and mobile read the host's working answer; plain refusal for a stopped agent's prompt (3/5, rebuild of #26867) (#28104)
* feat(native-chat): record which agent run wrote each journal item

Each journal item row, subagent roster entry and background-task entry now
records ownerFence: the lease fence of the agent run whose output produced it.
Optional, persisted, no row version bump and no migration. The journal's
itemFence() returns it, so the turn-verdict rules and per-run provider activity
read the producing run rather than the writer's fence.

* feat(native-chat): one current-work projection for every host reader; record death first

The host decides what work is current in one place
(structured-agent-session-current-work.ts) from the lease, the exit this host
saw, the runtimes it replaced, its live child and each item's provenance.
Every host reader (queue, Stop, prompt answers, commands, status feed, idle
sweep, teardown snapshot, history pages and frames, orchestration mailbox)
reads it, so a dead agent's leftovers stop reading Working or holding the queue
even when their cleanup write failed. The journal's activeTurnId()/liveTurnScope()
become the raw runningTurn().

On exit the host records the child's end first and signals generationEnded,
which republishes frames, the status feed and settlement waits and wakes the
queue drain with no journal row. Pages and frames carry optional working and
actionablePromptIds fields.

* feat(native-chat): clients read the host's working answer; refuse answers to a stopped agent plainly

Desktop and mobile prefer the host's working and actionablePromptIds fields
when present (merged across batches like latestTurn) and fall back to today's
row derivation against an older host. A prompt an ended agent raised stops
looking active; answering it is refused before any provider sees it, with
"<Agent> has stopped, so your answer was not sent. Send a message to continue."
Cancelling it only dismisses it in the journal: it no longer triggers the
chat's Stop, pauses the queue or withdraws queued cards.

* refactor(native-chat): keep structuredAgentSessionHandsOver file-local until a caller needs it

Nothing outside the projection calls it in this part; Part 5 exports it for the start-failure row.

* test(native-chat): fewer provenance tests: fold reopen and unstated-owner checks into the main case

Drops the epoch-replacement case (Part 2 rewind test reads the same values through the same rebuild) and the corrupt-value case (no version writes one).

* test(native-chat): drop current-work mirrors: the viewKey unit case and the still-live rewind case

The flow cases keep every outcome: dead leftovers read as nothing, Stop has nothing to stop, a waiting card drains, a live owner publishes as before, and a rewind never promotes dead work.

* test(native-chat): fewer client tests: one flow per client, one fallback each

Keeps desktop and phone Working from the host (with the older-host fallback), the reducer merge contract, the ended question Cancel that only dismisses, the agent-named refusal and the resolution receipt. Drops per-helper prompt tests, the transcript-placement test, the stop-note client reduction, the Steer cards that match main, and per-reason refusal rows.

* test(native-chat): an unstamped roster entry from an older build reads as its row provenance

Moved here from Part 4 so it sits beside stampJournalEntryProvenance.

* test(native-chat): build the older-build roster row inline, after main removed its body helper

Main #27947 writes one row per subagent and deleted journal-subagent-group-body; a roster row from an older build is still what this case reads.

* refactor(native-chat): provenance is per item only; drop per-entry stamping

Main's #27947 writes one saved row per subagent, and each background task already has its own row,
so an item's own ownerFence names the run of every entry a producer still writes. Per-entry stamps
inside a row mattered only for the shared roster rows saved before #27947, and no run writes into
those any more, so the row's own provenance settles them correctly. Removes the entry stamping,
the optional ownerFence on roster entries and background tasks, and their tests.

* fix(native-chat): an item's provenance is set when it is created; revisions keep it

A newer run's provider can revise an item an older run created: Pi's start and an ACP
session/load both report context usage onto the newest saved turn. Restamping that turn with
the newer run let the newer run's exit settle the older run's unverifiable turn as interrupted.
Only creation states an owner now, as main's itemFences rule did.

* test(native-chat): keep the provenance test below the production lines it covers

* fix(native-chat): an ended agent's card Cancel commits with its receipt, through dismissPrompt

The ended-generation dismissal wrote the cancelled resolution without the Cancel's operation
receipt and without the dismissal's failure handling, so a receipt write failing after it would
answer "outcome unknown" over a card already closed. It now goes through dismissPrompt, which
carries the uncommitted receipt in the same append and answers dismissalNotSaved on failure; a
null `answer` skips the adapter, since no live provider holds an ended generation's card (Pi's
adapter refuses a fence with no live session outright).
2026-10-14 23:41:52 -07:00
Neil 9ebdc68294 Check agent execution namespace types (#28370) 2026-10-14 23:35:35 -07:00
Brennan Benson 215bdbd6b0 fix(browser): settle client-hosted download toasts after their page closes (#28913)
* fix(browser): settle client-hosted download toasts after their page closes

The download progress toast for a page this desktop hosts for a remote
workspace was driven by a listener inside that page's pane. Switching
pages or closing the tab unmounted the listener mid-download, so the
finish never reached the toast and its spinner (no close button, no
timeout) stayed for the session. An interrupted download had the same
result because Chromium sends no finish for it.

Own the toasts from one app-level listener that claims a download when
it starts, and end the spinner on an interrupt.

* test(browser): type the store stub without an assertion

* fix(browser): wait for download finish before settling notice
2026-10-14 23:35:16 -07:00
Brennan Benson d771cf3cf9 fix(browser): end downloads that are waiting for a manual resume Orca never offers (#28936)
* fix(browser): end downloads that are waiting for a manual resume Orca never offers

* test(browser): drop type assertions from the manual-resume download test

* test(browser): focus manual-resume interruption regression
2026-10-14 23:35:07 -07:00
Jinwoo HongandClaude Opus 5.5 8d09041634 refactor(agent-launch): launching into a paired-server workspace stops closing local agent tabs (#29015)
* refactor(agent-launch): a paired-workspace launch stops closing local agent tabs

The prune existed because a local tab in a paired workspace once could not be closed (its close went
only to the host). Today a local id closes locally and the host close no-ops, and every present-day
launch into a paired workspace creates its tab through the host, under a host-surface id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(agent-launch): say how a local tab in a paired workspace closes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 02:34:57 -04:00
Jinjing 89d0ed1fd2 Update release channel and chat input translations (#29027)
Align the release channel strings in es, fr, ja, ko, and zh with the
English source, which now says "version" where the translations said
"build". Reword the warnings, the downgrade note, and the install hint so
they state the actual risk. Also reword the chat input placeholder, which
used "mention" for `@` file references.
2026-10-14 23:33:22 -07:00
Neil 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
2026-10-14 23:30:13 -07:00
Neil c3b9212906 Check mobile session close ownership types (#28369) 2026-10-14 23:15:08 -07:00
Neil 2c468f9aa1 Stop Jira list loops after saved-filter load failures (#29011) 2026-10-14 23:13:57 -07:00
Neil 10c2650546 Check mobile session projection and lifecycle types (#28368) 2026-10-14 22:58:44 -07:00
Neil d0c8bee2e8 refactor(runtime): check session host queries and terminal focus (#28367) 2026-10-14 22:42:18 -07:00
Neil acd415a414 test: consolidate orchestration mailbox suites (#29002)
* test: consolidate orchestration mailbox suites

* test: update mailbox reliability gate paths

* test: preserve mailbox reliability history
2026-10-15 05:33:37 +00:00
Jinwoo HongandClaude Opus 5.5 05c9c3b343 Drop the pre-tab-bar session format; orphan recovery writes tab-bar entries (#28990)
* fix(layout): drop the pre-tab-bar session migration; orphan adoption writes tab-bar entries

The window and main's Loader now both ignore sessions saved before the tab bar (pre-#371).
Orphan adoption, the one present-day writer that saved terminal rows without tab-bar
entries, now writes them through the shared serializer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: drop the pre-tab-bar case from terminal tab id hydration

It exercised only the deleted converter; the tab-bar case above covers the live rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 01:31:40 -04:00
Neil 0ec009a877 refactor(runtime): check workspace host, file and persistence boundaries (#27945) 2026-10-14 22:23:57 -07:00
Jinwoo Hong 21ba1c399d fix(skills): force git messages to English so skill updates work in translated locales (#28994)
skills@1.7.2 tries `git clone --branch <sha>` first for a commit ref and falls
back to fetching the commit only when git's error text is English. Under a
Korean or German git, every pinned install and update failed. Set LC_ALL=C
for the in-app updater and `orca skills install|update`.
2026-10-15 01:04:05 -04:00
Neil 8cfa1bbed3 test: consolidate contract suites and trim duplicate cases (#28988)
Group isolated contract suites behind explicit entrypoints to reduce repeated Vitest startup, consolidate RPC coverage without changing cases, and remove duplicate script assertions and child processes.
2026-10-14 21:50:26 -07:00
Neil 209ef94208 refactor: check terminal queries and preserve early view operations (#27915) 2026-10-14 21:16:48 -07:00
Neil 117d36254c test: defer runtime setup for skipped CLI probes (#28976) 2026-10-14 21:09:50 -07:00
Jinwoo HongandClaude Opus 5.5 c464348078 fix(layout): keep a tab in the group its tab-bar entry names when loading the layout (#28941)
The window's owner rule moves to src/shared so the window and main's Loader use one copy.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 00:03:30 -04:00
Neil 41b6f68c95 refactor: check PTY inventory and lifecycle dispatch (#27825) 2026-10-14 20:56:24 -07:00
Neil f5d5c5c404 test: share setup across related leaf suites (#28956) 2026-10-14 20:34:07 -07:00
Neil 1d60a21cbd test: consolidate automations page suites (#28953) 2026-10-14 20:33:42 -07:00
Neil d717798055 refactor(runtime): check terminal stop and workspace admission (#27782) 2026-10-14 20:28:35 -07:00
Jinwoo Hong 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 889eced7ff.

* docs(notifications): note the measured cost of the mute check's sidebar pass
2026-10-14 23:27:48 -04:00
Jinwoo HongandClaude Opus 5.5 157893905b refactor(tabs): create split tabs in the same update as their split (#28939)
Opening a vault session on a pane edge (local workspace) and "Open Preview
to the Side" used to publish an empty split group, then create the tab in
it. createTab, createUnifiedTab and createBrowserTab now take a `split`
target and add the group and the tab in one store update.

- insertSplitGroup is shared by createEmptySplitGroup, createUnifiedTabInSplit
  and the new split option.
- Delete useTabGroupCreationCommands.createSplitGroup: no caller since the
  split toolbar button was removed (#6372).
- The paired-runtime vault launch keeps its empty placeholder group: the host
  creates the tab after a round trip.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 23:23:35 -04:00
Brennan Benson 3bfb1149da Native chat: one current-work projection for every host reader, death recorded first (2/5, rebuild of #26867) (#28103)
* feat(native-chat): record which agent run wrote each journal item

Each journal item row, subagent roster entry and background-task entry now
records ownerFence: the lease fence of the agent run whose output produced it.
Optional, persisted, no row version bump and no migration. The journal's
itemFence() returns it, so the turn-verdict rules and per-run provider activity
read the producing run rather than the writer's fence.

* feat(native-chat): one current-work projection for every host reader; record death first

The host decides what work is current in one place
(structured-agent-session-current-work.ts) from the lease, the exit this host
saw, the runtimes it replaced, its live child and each item's provenance.
Every host reader (queue, Stop, prompt answers, commands, status feed, idle
sweep, teardown snapshot, history pages and frames, orchestration mailbox)
reads it, so a dead agent's leftovers stop reading Working or holding the queue
even when their cleanup write failed. The journal's activeTurnId()/liveTurnScope()
become the raw runningTurn().

On exit the host records the child's end first and signals generationEnded,
which republishes frames, the status feed and settlement waits and wakes the
queue drain with no journal row. Pages and frames carry optional working and
actionablePromptIds fields.

* refactor(native-chat): keep structuredAgentSessionHandsOver file-local until a caller needs it

Nothing outside the projection calls it in this part; Part 5 exports it for the start-failure row.

* test(native-chat): fewer provenance tests: fold reopen and unstated-owner checks into the main case

Drops the epoch-replacement case (Part 2 rewind test reads the same values through the same rebuild) and the corrupt-value case (no version writes one).

* test(native-chat): drop current-work mirrors: the viewKey unit case and the still-live rewind case

The flow cases keep every outcome: dead leftovers read as nothing, Stop has nothing to stop, a waiting card drains, a live owner publishes as before, and a rewind never promotes dead work.

* test(native-chat): an unstamped roster entry from an older build reads as its row provenance

Moved here from Part 4 so it sits beside stampJournalEntryProvenance.

* test(native-chat): build the older-build roster row inline, after main removed its body helper

Main #27947 writes one row per subagent and deleted journal-subagent-group-body; a roster row from an older build is still what this case reads.

* refactor(native-chat): provenance is per item only; drop per-entry stamping

Main's #27947 writes one saved row per subagent, and each background task already has its own row,
so an item's own ownerFence names the run of every entry a producer still writes. Per-entry stamps
inside a row mattered only for the shared roster rows saved before #27947, and no run writes into
those any more, so the row's own provenance settles them correctly. Removes the entry stamping,
the optional ownerFence on roster entries and background tasks, and their tests.

* fix(native-chat): an item's provenance is set when it is created; revisions keep it

A newer run's provider can revise an item an older run created: Pi's start and an ACP
session/load both report context usage onto the newest saved turn. Restamping that turn with
the newer run let the newer run's exit settle the older run's unverifiable turn as interrupted.
Only creation states an owner now, as main's itemFences rule did.

* test(native-chat): keep the provenance test below the production lines it covers
2026-10-14 20:19:23 -07:00
Neil 6448b2fda9 refactor(runtime): check workspace startup on original prototypes (#27767) 2026-10-14 20:12:16 -07:00
Neil 69042febb2 test: reduce coordinator mail polling overhead (#28945) 2026-10-14 20:08:40 -07:00
Neil ee5efad8d8 refactor(runtime): check terminal input and mail delivery (#27746) 2026-10-14 19:49:48 -07:00
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>
2026-10-14 19:48:25 -07:00
Jinwoo HongandClaude Opus 5.5 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>
2026-10-14 22:47:19 -04:00
Neil 1c31c5b45c test: overlap independent real pty idle checks (#28932) 2026-10-14 19:42:17 -07:00
Neil 74ad2309d6 test: remove duplicate execution and reduce fixture startup (#28926)
* test: remove duplicate unit cases

* test: use native hashes in Linux drain fixtures
2026-10-14 19:31:46 -07:00
Neil f5c50642de refactor(runtime): check terminal creation and splitting (#27708) 2026-10-14 19:29:25 -07:00