* fix(files): never write through a dangling symlink
A path that doesn't exist yet was authorized by walking up to the nearest
existing folder. A dangling symlink fails realpath with ENOENT, so the walk
stepped over it and approved the link's own path; the write then followed
the link and created its target outside the allowed folders. The walk now
continues from the link's target, and returns that real destination.
* refactor(native-chat): rename the chat visuals folder to the chat scratch folder
The per-chat folder agents write into is the chat's scratch space, not only
a visuals folder. Its root becomes <state>/chat-scratch/<hash> (the hash is
unchanged) and the agent variable becomes ORCA_CHAT_SCRATCH_DIR. The old
ORCA_CHAT_VISUALS_DIR is never set and is still stripped from what every
agent child inherits, Pi included. The visuals skill names the new variable
and says the folder is temporary.
* test(native-chat): keep the delivery test to the rename
The launch parity snapshot already pins that every agent drops the
pre-rename variable.
* feat(native-chat): chat scratch folders expire after 30 days unused
A chat's scratch folder was removed only when its record was gone or its
local workspace was proven deleted, so the folder of a long-idle chat
lived forever.
The sweep now expires a chat's folder once its newest journal row and
the newest entry anywhere in the folder (complete, no-follow scan) are
older than 30 days, unless the host holds a running agent, a delivery or
an open dispatch for the chat. The final recheck and a rename to
<hash>.expired run in the chat's session lane and then a per-folder lock
that Orca scratch saves (desktop IPC and host RPC) also take; the delete
runs outside both. A save that settles after the age scan marks that
expiry stale. Leftover .expired folders and the pre-rename
native-chat-visuals root are removed.
The workspace-removed rule and its catalog verdict are deleted.
* fix(files): refuse any dangling symlink in the missing-path walk
Following a dangling link by hand resolved relative targets against the
lexical parent, not the link's real folder: through a folder link the walk
could loop forever or authorize the wrong file. Refuse instead: realpath
can't say where a dangling link leads, but a write would follow it.
* test(files): drop the loop case that duplicated the dangling-link refusal
* refactor(native-chat): trim the scratch expiry and test the real live-work veto
- Remove the other-profile catalog options (running profile id, never-written
profiles) that only the deleted workspace verdict used; history cleanup's
reader is unchanged.
- The sweep keeps its original remove-and-warn block; an unused chat's
folder is parked by one function. Drop the unused `now` option and the
candidate identity check.
- The live-agent case runs against the host's real runWhileExecutionIdle.
* style(native-chat): keep the session host within its line limit after the main sync
* fix(native-chat): every scratch save and every overlapping sweep share the folder lock
Binary (base64) runtime saves now take the scratch folder lock like text saves, and each folder
keeps a set of expiry candidates so one sweep finishing no longer hides a save from another.
* 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
* feat(native-chat): copy chat selections when Copy on Select is on
The terminal's Copy on Select setting now also copies text selected in a
native chat transcript, at the point the Add to chat offer already treats
a selection as finished. It writes the same text right-click Copy does,
skips the composer and other fields, and leaves the setting key as is.
* fix(i18n): translate the Copy on Select description and search keywords
Settings and Settings search showed English to es, fr, ja, ko and zh users
after the description moved to new keys. Extend the old terminal-only
translations to cover chat, and translate the new highlight and chat search
keywords.
* fix(native-chat): send typing after a click to the chat's composer
The default Claude/Codex chat never wired the root typing redirect, so a
click in the transcript, on a toggle or link, on the chat's own tab, or on
blank app chrome left typed keys with nowhere to go. The chat-view-over-TUI
had the redirect but treated every button and link as a key owner.
Both views now share one hook that runs the reveal focus, focuses the chat
on blank clicks, routes keys typed inside the chat (but not in overlays it
portals out), and, while it is the only chat visible in the focused group,
routes keys typed with focus on the page body. Buttons and links pass
letters but keep Space and Enter. Re-activating an already visible chat tab
re-runs the composer claim, as a terminal tab refocuses xterm.
* fix(native-chat): refocus the composer when its active tab is activated again
Re-activating an already visible chat tab re-ran the ordinary reveal
claim, which stops as soon as focus is anywhere inside the pane. With the
transcript or a code-block Copy button focused, the tab shortcut left focus
there and Space kept scrolling or pressing the button. The activation now
moves focus to the composer from inside the pane too, unless a text field
such as the find input holds it; an ordinary reveal still keeps the user's
focus.
* feat(wsl-mover): shell history moves with the project to the WSL host (D1b-6c-1)
* fix(wsl-mover): moved WSL history lands under the host's login shell (D1b-6c-1)
* fix(wsl-mover): history follows the shell a pane would actually run, fallback included (D1b-6c-1)
* fix(wsl-mover): history installs follow the real pane shell, wait for live shells, and mark what they installed (D1b-6c-1)
* fix(wsl-mover): history installs wait until live shells can be checked (D1b-6c-1)
* fix(agent-launch): find a repo's project the way the window does
The host now also takes a project named after the repo as that repo's project, as the window
does, so both pick the same project row and runtime even when a repo was moved out of the
project named after it.
* refactor(agent-launch): share one repo-to-project match with the window
The host's agent-launch lookup and the window's launch preflight now call one projectMatchesRepo
instead of each writing the match out. No behaviour change on either side.
The drag preview's set-and-restore of the active tab per group now goes
through previewDragActiveTab, restoreDragActivationSnapshot and
restoreSourceGroupActiveTabAfterDrop instead of setState from a component.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Worktree removal, purge, rename, activation wake and SSH target cleanup now
build their tab/group/pane layout changes with named transitions in
tabs/worktree-layout-lifecycle.ts, folded into the same single store update.
Project removal drops its layout writes: purgeWorktreeTerminalState, run just
before in the same call, already cleared every one of them.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(terminal): park and quit capture keeps the stored pane layout
The capture that runs on quit, sleep and park rebuilt the whole pane tree
from the DOM. The tab's stored layout already follows every pane change, so
the capture now writes only what it alone knows onto that layout: the
scrollback buffers, the pruned scrollback refs, and the live PTY bindings
with the focus repair that goes with them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(terminal): keep a stored leaf's scrollback and binding while its pane is unmounted
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- ko Worktree Jump Palette: render "actions" as 동작 so it is distinct from
the tasks entry (작업) in the same list.
- zh DevTools cookie instruction: clarify the filter phrase to
`任意包含 remains 的请求`, keeping the literal `remains` request name.
Scan 2026-10-14: fill target-locale coverage for PRs merged since the
2026-10-13 scan (#28486). Adds the missing keys (es 98, fr/ja/ko/zh 125
each), updates the two changed WorktreeJumpPalette strings, and fixes
pre-existing mistranslations: the ZCode missing-TUI notice (English in
all five locales), fr settings search keywords (procuration/indigene),
zh workspace-cleanup browse MT, 6 zh keys that still used Latin "Agent",
and the zh AccountsPane credential-help cluster (leftover English and a
mangled __Host-console_session token).
Leaves the 11 pinned provider-credit-balance keys plus the 3 pinned Chat
UI keys as English fallback by design. Records the scan in
config/update-translation.txt.
* fix(ssh): the SSH password dialog no longer closes itself and comes back
A host that drops an unanswered login no longer replaces the open prompt
with a new one, a background dial no longer replaces a connection whose
reconnect is asking the user, one Cancel closes every open prompt for that
host, and a paired client's automatic connect stays automatic.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(ssh): a typed password its reconnect has yet to use is not replaced by a background dial
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Claude <noreply@anthropic.com>
* 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
* 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
Ten create sites now mint the new tab's id (or browser page id), pass it to
the create action, and key every follow-up (select, focus, tab order, group
focus, remote page handle) off that id instead of the returned record.
Creates stay synchronous, so the follow-ups still run immediately.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A workspace with no groups got a random root group id from the window. It
now gets the name-based id the shared loader already mints for that
workspace's group, so main can derive the same id without the window.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(wsl-mover): a moved pane reopens in its last folder on the WSL host (D1b-6b)
* fix(wsl-mover): consume a restore hint only when its pane spawns, scope it to its worktree, retry failed installs (D1b-6b)
* feat(orcad-migration): a capability-gated blob channel beside scrollback, for the WSL mover's new data (D1b-6a)
* fix(orcad-migration): the commit names its blob set, prune clears leaked blobs, reserved names refused (D1b-6a)
* 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
* fix(terminal): keep a hibernating pane's resume record through its stop
The agent dies before its shell, so the shell's command-finished mark read
as the agent exiting and deleted the record the hibernation had just written.
* fix(automations): sleep a finished run's terminal instead of closing it
Closing it left the run's own workspace empty, so opening it later showed a
blank chat or shell instead of the run's conversation.
Fixes#28645
* feat(chat): Resume in New CLI for OpenCode and OMP chats
OpenCode's and OMP's CLIs have no copy flag, but their chat protocol copies a
conversation (ACP session/fork). For a fork of one of their chats, the chat's
host now has a short-lived agent, launched exactly as the chat's own, copy the
conversation; the terminal then opens the copy with a plain resume. The chat
keeps its own conversation, so the CLI is never a second writer on it.
The copy travels on the existing aiVault.prepareSessionResume fork request as
an optional forkedSessionId; a host that predates it answers without one, and
the client asks for an Orca update instead of resuming the original.
* fix(chat): open an OpenCode 2.x chat's CLI copy with opencode, not opencode2
The copy kept the row's agent, so Resume in New CLI ran `opencode2 --standalone --session <copy>`,
which OpenCode 2.x doesn't install. The chat's host now answers the copy with the agent whose CLI
opens it: the chat's own.
* fix(chat): type the copied conversation's agent as a history agent
* fix: preserve independent chat copies through CLI launch
* test: keep only the tests that pin user-visible behavior
* fix(chat): validate OpenCode copies on their execution host
* test(chat): expect copied OMP forks after main integration
* Run safe worktree cleanup on dev and add interactive pnpm reclaim
* Rename storage cleanup command to reclaim-space
* Keep real stream constructors in transcript dependency tests
* Detach cleanup output and align historical cache previews
* fix(terminal): reject a requested tab id that is already taken
createTab silently minted a fresh id when the caller's requested id was
already in use. The caller's PTY routes agent status by the id it asked
for, so the new tab never received its agent status and the status went
to the other tab instead. Now the create throws and changes nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* refactor(agent-launch): drop the unreachable tab id mismatch guard
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Skip reindexing unchanged transcripts on cold session list reads
A cold session-list read re-parsed every self-contained transcript and rewrote its search rows, even when nothing had changed. That wasted work and churned the index on every list.
- When a transcript's stat (mtime, size, inode, device) matches a complete index entry, the list read now skips the rewrite. Agents with sidecar metadata, unknown sizes, or partial or stale entries still reread.
- Test fixtures that replay a "changed" transcript now pass a new mtime so they still exercise the replace path.
- New tests cover unchanged skips, changed size/mtime/file identity, sidecar refresh, due/failed repair, and append.
- Dependent-transcript and Codex title tests check that cold rereads keep search and title data current.
* Make the self-contained transcript check exhaustive over every agent
- Replace the hand-maintained `Set` of self-contained agents with a
`Record<AiVaultAgent, boolean>`, so adding an agent type fails typecheck
until someone decides whether its transcript is self-contained.
- Classification is unchanged: the agents that were in the set are `true`,
and the rest are `false` with a short note on the sidecar or metadata
source they depend on.
- Make the replace-generation tests derive the second mtime from the first
candidate instead of a hard-coded timestamp, so they stay valid if the
default fixture mtime changes.
* Guard file-stat reuse with a self-contained transcript test
Indexing skips reparsing unchanged transcripts for agents marked self-contained. That is only safe if their parsers read nothing but the transcript itself, and nothing enforced it. A parser that started reading a sidecar or dependency file could serve stale index entries.
- Export SELF_CONTAINED_TRANSCRIPT_AGENTS so the test checks the real list
- Add a test that parses each self-contained agent's fixture, both direct and cached, and fails if any file other than the transcript is read
- Register the test in the SQLite runtime-file include list
* Require stored file identity before skipping a transcript rewrite
- Rows with a NULL dev or ino were treated as covered, so a file replaced with the same size and mtime could be skipped and never reindexed.
- Such rows now count as uncovered, so the rewrite runs and records the identity.
- The identity is read through the shared `fileIdentity` helper instead of the raw file fields.
* Add regression test for session rows indexed without file identity
A session row indexed before file identity (dev/ino) was recorded was never reread once the stat began supplying one, so it could keep stale search content. This test covers that case: the first read with identity replaces the row, and a second read with the same identity leaves it alone.
* test(session): compare what the window shows before and after the shared session loader
Boots the window's real startup hydration on each saved-profile fixture as
stored and as the shared loader rewrites it (load then save), and compares
tabs, groups, active tabs, pane trees, terminal bindings, editor and browser
tabs. Today's eight differences are listed with the loader rule behind each;
the list may only shrink, so any new difference fails.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(session): let the parity test own its store so the harness reads no host focus
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(session): restore the parity boot's UUID spy even when the boot throws
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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
Seven call sites created a terminal tab and then queued its startup command
in a second store write. Pass the command through createTab's existing
pendingStartup option instead, so the tab and its command land in one write.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The dialog title and cancel button said 掃除 (household cleaning), while its own description and confirm button already say クリーンアップ. Use クリーンアップ throughout.
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
The Japanese option read 掃除済み ("housekeeping done"), while the migration notice that points to the same setting already calls it クリーン. Use クリーン in the option and its settings-search keyword.
Also restore the literal CLI command in the reset hint, which translation had re-capitalised in ja, zh, and fr so it could not be copied and run.
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
* feat(wsl-mover): background writers back off a project a WSL move is taking (D1b-5c-3)
* fix(wsl-mover): re-check before renames, quiet owned automations, stable folder ids (D1b-5c-3)
* test(wsl-mover): seed journals one phase at a time and advance existing moves (D1b-5c-3)
* fix(wsl-mover): a branch rename that already ran settles even when the move skips the folder (D1b-5c-3)
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>
* 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>
OpenCode in a \\wsl$ repo runs in WSL whatever the project's setting, and Orca can't verify a
model there yet, so picking one is refused, as it already is for a project set to WSL, instead
of being checked on Windows.
* fix(files): never write through a dangling symlink
A path that doesn't exist yet was authorized by walking up to the nearest
existing folder. A dangling symlink fails realpath with ENOENT, so the walk
stepped over it and approved the link's own path; the write then followed
the link and created its target outside the allowed folders. The walk now
continues from the link's target, and returns that real destination.
* refactor(native-chat): rename the chat visuals folder to the chat scratch folder
The per-chat folder agents write into is the chat's scratch space, not only
a visuals folder. Its root becomes <state>/chat-scratch/<hash> (the hash is
unchanged) and the agent variable becomes ORCA_CHAT_SCRATCH_DIR. The old
ORCA_CHAT_VISUALS_DIR is never set and is still stripped from what every
agent child inherits, Pi included. The visuals skill names the new variable
and says the folder is temporary.
* test(native-chat): keep the delivery test to the rename
The launch parity snapshot already pins that every agent drops the
pre-rename variable.
* fix(files): refuse any dangling symlink in the missing-path walk
Following a dangling link by hand resolved relative targets against the
lexical parent, not the link's real folder: through a folder link the walk
could loop forever or authorize the wrong file. Refuse instead: realpath
can't say where a dangling link leads, but a write would follow it.
* feat(runtime-files): the host serves a chat's scratch folder as a file root
File commands accept `path:<this host's chat-scratch root>/<32 hex>` and
resolve it only when it names this host's own folder, at the file-commands
seam so the selector never reaches chat placement. They authorize against
the project roots plus the chat-scratch root, refuse files.open/openDiff
for the folder, and agentSession.readVisual's ok results carry the file's
absolute path so a client can build the selector.
* test(runtime-files): name the readVisual helper's parameter type
* test(files): drop the loop case that duplicated the dangling-link refusal
* test(runtime-files): run the readVisual RPC test, which opens a real SQLite store, under Node
* test(runtime-files): put the same-suffix folder inside the authorized root so only the selector refuses it
* refactor(native-chat): open a chat visual like any file
"Open in new tab" on an inline chat visual now opens the visual's file the
way any HTML file of the chat's workspace opens: a file:// browser tab for a
local chat (its overflow menu gains "Open source file"), the document
preview for a paired-host chat (with its existing source action and Share).
Edits save on the chat's host through the exact path: selector the host
serves, and a matching editor save re-reads the inline copy freshly. The
read-only chat-visual tab is removed.
* feat(native-chat): share a chat visual from the chat
The inline visual's toolbar gains Share beside Open. It publishes under the
file's own key on the chat's host, the key the opened preview and editor use,
so every surface updates one link. The published text comes from a fresh read
begun after the click; a failed read publishes nothing and says the visual
couldn't be read. The toolbar stays shown while Share's popover is open.
* fix(native-chat): a visual read without a path is a malformed reply
A visual's path is always on the current host's readVisual answer, so the
inline Open needs no branch for a missing one. Also prune the deleted
chat-visual tab action from the layout-writer baseline.
* test(native-chat): give visual read replies their path without longer lines
* fix(native-chat): address a scratch file by its folder only outside every workspace
A workspace that contains the host's state folder keeps its own address, so
explorer drops, folder creation and renames inside it stay on one root.
Document preview Share reads a runtime grant's own selector and root
directly instead of passing the selector off as a workspace id.
* fix(native-chat): show a chat visual's Share whenever it shows
Every read now carries the visual's path, so Share no longer waits on one; its
key comes from the path the click's fresh read returns.
* test(runtime-files): wait for the stores to close before removing the state folder
* 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)
* Rank browser history above fuzzy file matches in the omnibox
Scattered-character fuzzy file matches are weak evidence, so a remembered
page should appear above them. Exact and literal file matches and typed
URLs still rank above history. Adds a test for typing a host like
linear.app, which should rank the page above unrelated fuzzy files.
* Anchor omnibox history on the typed URL instead of demoting fuzzy files
The real bug: after visiting https://linear.app/, typing `linear.app`
made Enter open an unrelated file. The history row removes the typed-URL
row it duplicates, but was then placed below every file match, so the
page lost the top slot the URL row had.
History now sits with the typed URL row (in its slot when it replaced
it). Queries with no typed URL keep the old rule: below every file match.
This replaces the previous commit's rule of ranking history above
"fuzzy" files. That label covers every non-exact match for queries with
a slash, a dot suffix or a space, so a code-host page whose title holds
the file path took Enter away from local rows for path queries (or left
nothing selected when pasted). It also left `localhost` broken when a
file name contained it.
* feat(telemetry): count agent start failures from the host too
The host spawn path (CLI, phone, orchestration workers, headless automations,
worktree startup) now records agent_error when starting an agent fails, as the
window path already did. Removes C5a's TEMPORARY recordsAgentError input; the
host already threads each launch's telemetry, so failures get real kinds.
* fix(telemetry): count a claimed start that several requests joined once
Concurrent resumes of one agent session join one claimed start. When it
fails, every joined request ran the host catch and recorded agent_error, so
one failed start counted once per request. Only the request that ran the
start records it now; the others still clean up.
* fix(telemetry): only skip agent_error for a request that joined another start
The host marked a request as joined before calling ensure, so a claim that
refused the request on its own (conflict, capacity, unreachable owner) recorded
no agent_error. ensure now reports the join itself, right before awaiting the
other request's start.
* chore: re-run CI after main's localization fix (#28810)
* feat(chat): Resume in New Native Chat for Pi terminal conversations
A Pi conversation started in the terminal now offers "Resume in New Native Chat" in its Session
History row menu and its tab's right-click menu, like the other chat agents: a new Pi chat takes
it over, showing its history and continuing it.
Pi joins the shared adoption path. Its import finds the session file Session History lists under
the row id, and reads it with OMP's decoder, since OMP kept Pi's session format. A Pi chat's handle
names its session file, so the import says so and create mints the adopted handle from the found
file; the committed-create replay compares through the registration's row id, and the adopted
link id is kept to the link-id alphabet. A Pi chat forks a conversation recorded in another folder
instead of resuming it, so the workspace rule covers Pi too.
* fix(pi): preserve adopted session identity and active history
* Fix saved Pi adoption history and summary content
* test: keep only the tests that pin user-visible behavior
* 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)