* Revert "Keep same-machine folders with matching Git remotes in separate projects (#32272)"
This reverts commit 29a5f89b8a.
On a machine with several clones of one repo, #32272 moved the oldest clone
into the shared cross-host project. Shared Windows QA machines have several
orca clones, so everyone's sidebar "orca" project suddenly gained that
machine's main checkout and its worktrees. Revert until the intended
grouping is decided.
Conflicts resolved against later main: Settings files moved into
settings/repository (imports adjusted), and two test files later deleted on
main stay deleted.
* Use checked types in restored test fixtures
* Combine restored fixture type imports
* fix(runtime): accept Muse's composer when the voice-input label is absent
Muse labels its composer's top rule "Voice input" only where voice is
available, so on Linux the readiness predicate never matched and
worker-start timed out at agent_readiness. Keep the voice-label match and
also accept the composer itself: a rule (two or more rule chars) directly
before the prompt glyph after the latest Muse banner, so a shell prompt like
'~/app ❯' or '╰─❯' under a printed banner is still not ready.
Fixes#25005
Co-authored-by: j33pia <242526320+j33pia@users.noreply.github.com>
Co-authored-by: Nawapat Buakoet <nawapat.b@covest.finance>
* fix(runtime): escape Muse composer regex so the orcad bundle stays ASCII
---------
Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: j33pia <242526320+j33pia@users.noreply.github.com>
Co-authored-by: Nawapat Buakoet <nawapat.b@covest.finance>
* fix(wsl): background repo probes, PR refresh and worktree scans never start a stopped distro (E9)
Any Windows touch of a \\wsl.localhost path, or Git/gh run for it, boots a
stopped distro. These background paths ran without asking the stopped-distro
gate: the worktree scan refresh (Git-admin fingerprint reads plus git worktree
list), the remote-identity and username enrichment sweeps, the startup
upstream backfill, the quiet-period ref maintenance, and queued PR refreshes.
Each now asks blockedWslDistroForPath first and skips, keeping known data,
until the distro runs; a host path never asks the gate.
* fix(wsl): a user act's wake allowance ends with the act
The allowance lived in an AsyncLocalStorage store, so any timer, listener or
queue created during a user act (opening a workspace, a wake read, the first
git status) kept it forever and could start the distro later, after a
terminate. The scope now carries an active flag cleared when the act settles.
* fix(wsl): skill discovery and automatic refreshPRNow never start a stopped distro (E9)
- Skill discovery (mounted by passive UI) leaves out roots on a stopped or
unverifiable distro, and skips plugin discovery for such a cwd, instead of
reading \\wsl.localhost; they are not reported missing, so the next scan
picks them up.
- refreshPRNow skips automatic reasons (visible, active, post-push) on a
blocked distro like the drainer does; only a manual refresh may start it.
- Ref maintenance's opt-out probe takes the same sync wslDistroForPath
early-out as the other paths.
- Tests: stopped-with-no-cache worktree scans answer from stored rows, and
'unverifiable' is treated as blocked.
* fix(wsl): skill discovery for a WSL target never starts a stopped distro (E9)
Passive UI discovers skills for projects whose agents run in WSL. The target
resolution probed the distro home (wsl.exe) and the scan ran in the distro,
so either booted a stopped one. Discovery now refuses a stopped or
unverifiable WSL target before the home probe and answers no skills and no
sources, so nothing reads as missing and the next scan retries. Delete and
share keep resolving without the gate.
* fix(wsl): a settled user act marks its distro woken; host skill scans never await the gate
- runAsWslUserAct (the gate's wrapper) notes the distro woken inside the act
when it settles, success or throw, so a follow-up is never answered by a
'stopped' read taken before the act.
- Skill discovery takes sync early-outs: a host-only root set and a host cwd
never await the WSL gate.
* fix(wsl): Share discovers as a user act; a stopped distro's skills read as unknown, not absent
- skills:prepareShare (and the skills.share RPC) discover as a user act on the
target's distro, so an explicit Share on a stopped distro finds its skills.
- A blocked WSL target answers an 'unavailable' source per requested kind, and
roots (or a workspace plugin folder) on a stopped distro are reported
'unavailable' instead of dropped, so the installed-skill verdict says the
status may be incomplete rather than offering Install.
* test(wsl): use a fixed fetchedAt in the stopped-distro PR refresh test
* fix(wsl): Share scans stopped distros' skill folders, with or without a target
The desktop Share dialog sends no target, so the user-act scope had no distro
and the gated scan reported a stopped distro's repo folders unavailable; Share
then failed with skill-share-source-not-found. discoverSkills takes
gateStoppedWslDistros: false for both share paths (IPC and RPC), skipping the
stopped-root split and the plugin-cwd check; passive discovery keeps the gate.
Gated and ungated scans of one target no longer share a coalesced answer.
* fix(runtime): re-list a repo's worktrees when repo.update changes visibility
`orca repo set --external-worktree-visibility show` (and any other repo.update
client) only emitted repos:changed, so the host renderer kept stale
`visible: false` worktree rows and the newly shown worktree vanished from the
sidebar. The settings controller now also emits worktrees:changed for the repo
when a visibility input changes, without invalidating cached Git scans.
Fixes#32764
Co-authored-by: Younghwan Chae <chyohw97@gmail.com>
* fix(runtime): declare notifyWorktreesChanged on RuntimeConstructionServices
The repository settings controller is built in OrcaRuntimeWithPreservedBranchCleanup,
but notifyWorktreesChanged is implemented further down the chain in
OrcaRuntimeWithGetStatus, so the base class needs the abstract member to typecheck.
---------
Co-authored-by: Neil <neil@stably.ai>
* fix(native-chat): list OMP skills in the / menu as /skill:<name>
* test(native-chat): OMP now carries the Pi-shaped skill profile
* Publish native OMP skills with compatible command catalogs
* Index native skill descriptions once per picker build
* Combine catalog test composer imports
* Correct native catalog test types and project inputs
* Run cross-platform picker scaling contract with mobile tests
* fix: discover native commands before the first chat message
* test: isolate native command discovery from mobile typechecking
* fix: release command discovery ownership after managed root exit
* refactor: reuse the ACP child owner during shutdown drain
* test(acp): load filesystem implementation before test execution
* test: drive discovery close completion explicitly
* test: await discovery admission cleanup between demand waves
* test: control discovery close ordering in demand waves
---------
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
* fix(wsl): refuse Windows drive folders on a WSL host and offer to add them on this computer
A /mnt/<drive> project on a WSL host shows false line-ending changes, misses
edits made from Windows, and searches slowly. Add Project refuses typed,
picked and dropped Windows drive folders for a WSL host and shows the refusal
inline with Add on this computer, which switches the open dialog to this
computer. The WSL-host orcad re-checks by /proc/self/mountinfo (after
resolving symlinks) in repo.add, repo.create, repo.clone, explicit
folderWorkspace.create and the nested scan/import, answering with the
existing runtime_error code plus optional data, so older clients still show a
readable message. Everything is behind the WSL hosts gate; SSH is untouched.
* test(wsl): hold the e2e's this-computer add instead of racing its failure
On the Linux CI host the switched local add of a Windows path fails its nested
scan and hands off to the Open as Folder modal, closing Add Project before the
test looked. The refusal itself already came before any scan. The e2e now
records the local add at its scan step and asserts it went to this computer
with the Windows path; a unit test pins that a refused pick never reaches the
host path step.
* test(wsl): type the e2e's held-scan window hooks instead of Reflect
* Add native chat hand-off menu on main
* Fix saved chat hand-off observations and RPC exports
* Reuse indexed chat tabs for hand-off subscriptions
* Match saved-chat clear fixture to current journal API
* fix(gitlab): keep paging merge requests when GitLab omits the totals
When total headers are absent, a full response advertises another page to probe and a short response ends pagination. Keep the existing header precedence and unknown total count.
Tracked in #33800
* test(gitlab): cover MR pagination exhaustion and header precedence
* test(gitlab): verify unknown-total metadata across list consumers
* test(gitlab): cover remaining screen consumers of list metadata
* test: use checked GitLab RPC runtime fixtures
---------
Co-authored-by: Hotragn <103170876+Hotragn@users.noreply.github.com>
* fix(editor): Copy Remote URL links to the code the workspace is on, with the selected line range
The gutter menu's Copy Remote URL always built the link on the default
branch and dropped any multi-line selection. Prefer the HEAD commit when
origin already has it, then the origin branch the current branch tracks,
then the default branch; carry an optional end line through IPC, RPC and
the git provider so a selection becomes a line range.
* fix: pair remote file links with published repository refs
* fix: prepare exact remote file fallback before publication scan
* test: consolidate remote file URL integration coverage
* test: document real-clock cancellation deadline proof
* test: handle optional cancellation signal in assertion
* test: reuse spawned child fixture across runtimes
---------
Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
* fix(windows): stop recursive deletes from retry-storming when a file is held open
Node's async recursive rm retries every nested entry separately and orphans
sibling walkers when it rejects, so deleting a workspace holding a live
browser profile multiplied filesystem work per directory level until the
main process hung. Delete Windows host trees with a walker that retries
whole passes from one shared budget and leaves nothing running on failure.
Also bound and log detached worktree removal, and fail a file transaction
whose proper-lockfile lock is compromised instead of throwing from its timer.
* fix(windows): retry a locked delete as whole passes instead of a custom walker
Replace the hand-rolled tree walker with Node's own recursive rm and no
per-entry retries. Async rm gives each nested entry its own retry counter and
never stops siblings, which is what multiplied the work; with retries off each
pass is one bounded walk, and a transient Windows lock repeats the whole pass
from the existing 250/500/1000/2000 ms budget, checking the job's signal
between passes.
A failed delete now names the file another program holds open instead of
Node's EBUSY/EPERM text. Drop the 30-minute background deadline. The lost-lock
error no longer embeds the library's message and says the write may or may not
have been saved.
* test: cover bounded deletion failure and recovery contracts
* test: prune unchanged cleanup coverage
* fix(worktrees): give truthful failed-delete cleanup advice
* test: document fake-clock retry adapter
* fix(windows): preserve checkout ownership until files are removed
* fix: preserve worktree ownership checks across metadata aliases
* test: make checkout retry clock completion explicit
* Keep failed Windows workspace deletions retryable
* test: correct removal fixture imports and path formatting
* fix: retain failed removal until a retry is accepted
* test: identify the mocked backoff clock
* test: preserve failed removal records and recreate marker fixtures
* test(worktrees): preserve exact checkout bytes in refusal contract
* test(worktrees): exercise current native deletion contracts
* test(windows): prove long-path deletion through native checkout removal
* test(windows): preserve real Git runner exports in removal fixture
---------
Co-authored-by: Orca Worker <orca-worker@localhost>
* fix(native-chat): resting chat skill checks share one capped Codex process per account
A resting chat's slash list started one hidden codex app-server per
folder, each kept alive 70 s outside the two-check limit, and a scan
waiting in line for 30 s was treated as hung and doubled. With many
resting folders this kept about a hundred Codex processes alive.
- The catalog runs one scan per folder at a time; readers join it.
Failures retry three times, then wait for the TTL. Entries unread for
an hour are dropped.
- Codex folders that share an account, binary, arguments and
environment are answered by one app-server, batched into skills/list,
with at most two probe processes alive until their teardown ends.
A probe that cannot start backs off, and a refresh does not reset it;
an explicit refresh asks a live probe to reload.
- Batched replies are matched to their own folder.
Tracked in #34141.
* test: use fake timers for resting Codex probe cache checks
* fix(native-chat): bound resting discovery and retain process ownership
* fix(native-chat): close cancelled late directory acquisitions
* test(native-chat): complete cancellation discovery fixture
* test(native-chat): align fixtures with resolved workspace contracts
* refactor(mobile): share the queued-card projection with desktop
Image-only queued drafts showed a blank card on the phone.
* fix(mobile): honor the host's Queue follow-ups setting
With it off, a mid-turn send from the phone still queued while desktop sent it into the running turn.
* fix(mobile): keep a queued-card edit when the card leaves the queue
The phone closed the editor and dropped the typing; it now goes to the chat box as on desktop.
* fix(mobile): hold /clear and /compact for background work and sends
The phone fired the command where desktop holds it, showed start failures twice, and left the agent unnamed in failures.
* fix(mobile): hand a queued edit back to the chat it came from
* fix(mobile): scope a command's send hold to its own chat
* fix(mobile): read a published null queue as empty
* refactor(mobile): share the returned queued-card caption rule
* test(mobile): drop queued-card tests the shared rules already own
* refactor(native-chat): share the needs-attention rule and drop leftover wrappers
* fix(mobile): type the structured sends mock, drop the moved queued-cards path and ship queued edit copy at boot
* fix(native-chat): drop the queued card's unused image-label import after the rebase
* fix(mobile): order the phone's queue reorder preview by position, as the shared cards sort
* test(mobile): keep the queued-messages test within its line budget
* fix(mobile): settle terminal chat working state and turn timing with desktop's rules
Move desktop's live-status merge, Stop suppression, hook-state resolver and
terminal turn timing to src/shared/native-chat. Mobile reads the transcript
lifecycle the host already sends, so a provider turn end settles Working the
same way desktop does. Terminal chats now get the turn bar, timer and folding,
and the streaming preview uses the shared deriveNativeChatStreamingText.
* fix(mobile): send desktop's terminal Stop keys, a second Escape only for OpenCode
Desktop sends one Escape on Stop. It adds a paced second Escape only for
OpenCode, which confirms an interrupt that way. Claude Code and Codex read
Esc-Esc at an idle prompt as rewind. The rule moves to
native-chat-agent-support, and the phone now paces the second Escape at
desktop's answer step instead of 80ms.
* fix(mobile): word Orca-stop and usage-limit notices like desktop
Move desktop's Orca-stop sentences to src/shared with an English table that
desktop translates. The phone names the Orca host it pairs with, and when
that host is unnamed it says "the remote server". Usage-limit rows rebuild
desktop's sentence from the failure fact. The usageLimitLineText fallback,
which only the phone used, is deleted.
* test(mobile): pass the overlay's host name in the prompt controller harness
* test(mobile): re-record Stop goldens at desktop's step, split status-notice tests, pin the turn clock and ship notice copy at boot
* fix(mobile): offer structured Stop while a send is out and read queue-sends-next as working
Move desktop's structured Stop rule, its Stop-joining helpers and the
queue-sends-next rule to src/shared. Both sides now use them. The phone
counts its in-flight sends, so a conversation-stop host offers Stop before
the turn opens. Between queued turns the phone reads as working, and
commands that can't wait in line hold like they do on desktop. Untargeted
Stops are no longer joined on legacy hosts.
* fix(mobile): offer terminal Stop again when its Escape went nowhere
Stop hides Working on the phone like it does on desktop. The phone's Escape
can fail outright, though, while desktop writes to a local PTY. When no Escape
could have landed, the phone now drops that suppression. The streaming preview
also treats a pending echo as the transcript's tail, as desktop does, so an
earlier reply can't hide a new preview.
* fix(mobile): hold structured Stop while a send it covers is in flight
On desktop, Stop's held and Stopping state depends on whether the chat can
stop, and that includes a send still in flight. The phone now does the same.
Once Stop is pressed before the turn opens, the button holds and repeated
presses send no more untargeted cancels.
* fix(mobile): end the terminal Stop hold when a new message is sent
Desktop clears Stop's working suppression on an optimistic send, so a new turn
that keeps the same hook epoch (Claude with working subagents) still offers
Stop. The phone now does the same when a new pending echo appears.
* refactor(mobile): trim chat turn wiring after the desktop rule move
Drop the controller's unread nativeChatAgentWorking field. Re-render only when
a chat starts or stops having a send out. Keep the structured turn indicator
stable across stream frames. Type the Stop test table instead of casting.
* refactor(mobile): track structured sends in flight once for Stop and command holds
* test(mobile): re-record Stop goldens now that Stop settles with its Escape delivery
* fix(mobile): escape terminal image paths like desktop drops
* fix(mobile): keep launch-draft prefill over older user turns
* fix(mobile): rank @ file matches with desktop's fuzzy Quick Open search
* fix(mobile): use desktop's composer triggers for mid-prompt / and $ picks
Picked @ files are now quoted when the path has spaces.
* fix(mobile): send picked skill paths on structured chats
* fix(mobile): list the host's disk-scanned skills in the / and $ menus
The phone names the workspace and the host resolves its folder, refusing SSH
workspaces as desktop does; hosts without skills.discover-workspace.v1 list none.
* fix(mobile): forget a picked skill once its token is deleted
* fix(mobile): drop a picked skill as soon as its token is deleted, and retry failed skill scans
* fix(mobile): treat a picked leading skill as chat and stop failed skill scans from refiring
* test(mobile): drop the menu ranking case the shared picker tests own
* refactor(mobile): keep skill picks on the draft record and reuse shared send rules
A rejected send now keeps its picks and leading-skill origin on both send paths.
* fix(mobile): replace a re-picked skill's file and restore picks with a rejected send
* fix(mobile): read the chat agent for the skill catalog from the active resolution
* style(native-chat): format the composer autocomplete files
* fix(native-chat): import the picker's apply and send-classify rules from the shared composer module
* refactor(mobile): import the composer's draft-store hooks once
* style(mobile): format the notice row's style import
* fix(native-chat): list a resting Claude chat's / commands from the account it will start on
A resting chat's next start follows the selected Claude account, but its / menu was read from the account saved when the chat was created. Read it from the same account a new chat would be created on, and rescan when the selection changes.
* refactor(native-chat): resolve the at-rest account in the shared catalog so its key matches the scan
* test(native-chat): build the second at-rest chat record from a lease fixture
The observed (`worker-start --setup run`) and sequenced (`wait-for-setup`) setup
commands are typed into the user's interactive shell. Pair-inserting line
editors such as zsh-autopair rewrite the `( ` of the `( bash runner )` wrapper
into `( )`, so bash -lc receives a stray `)` and rejects the whole line: setup
never runs, no completion marker is printed, and the worker stays at
setup_state: running (or the agent gate waits out its timeout).
The runner command is always a single external command (bash/cmd.exe/
powershell.exe), so the subshell added nothing; run it directly.
Fixes#18059
Co-authored-by: Neil <neil@stably.ai>
The orchestration skill description only advertised coordinator work, so a
dispatched worker never loaded it and built its heartbeat loop from the
preamble alone. Neither the preamble nor the guide said to stop a background
heartbeat loop before worker_done, so the loop outlived the task.
Add worker-role triggers (heartbeats, ask, worker_done) to the description and
stub, and tell workers in the preamble and guide to restart an expired
heartbeat loop mid-task and stop it before worker_done.
Fixes#26605
`orca worker start --worktree new-top-level --repo <selector>` no longer
requires the dispatching terminal to sit inside a managed git worktree; the
explicit repo is all a top-level worktree needs. new-child (and
new-top-level without --repo) still need a caller worktree, and now fail
with an actionable invalid_argument error before any effects are recorded
instead of a bare selector_not_found.
Fixes#22345
* fix(projects): register a folder once when two adds race on a server
A paired server's repo.add looked for an existing project, then awaited icon
and upstream detection before saving. Two adds of the same new folder both
passed the check and saved it twice. Re-check right before saving, as the
desktop's local add already does.
Part of STA-12331.
* refactor(projects): reuse the add's store when adopting an existing project
Startup evaluated every structured-agent adapter (claude, codex, acp, pi)
even when no chat was opened. The host install already loaded the
registrations with a dynamic import, but structured-chat-cli-fork imported
the same module statically to read sessionHistory, which the lightweight
metadata already exposes.
- structured-chat-cli-fork reads structuredAgentRuntimeMetadata (the same
objects, so behavior is unchanged).
- installOnJournal moves unchanged into structured-agent-session-host-assembly,
which install() loads on first host install; the existing installing slot
already single-flights and retries it.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(repos): let a project be removed while its paired server is unreachable
An unreachable server's repo.rm timeout aborted the whole removal. The error toast
now offers 'Remove from this desktop now', which purges this desktop's rows, records
a pending repo.rm (persisted UI state, optional), fences the server's catalog so it
cannot re-add the project, and replays the removal once the server is ready again.
Re-adds and replays for one server are serialized so neither undoes the other.
Fixes STA-9705
* fix(repos): replay owed removals whenever the server is ready, and lift the fence on refusal
Main publishes status only on change, so a record written or seeded after the ready
snapshot now replays at once. A refused replay refreshes the server's catalog, a
retired server drops its records, a user disconnect also offers local removal, and
the field is main-owned so paired clients cannot overwrite it.
* fix(repos): keep owed removals across disconnects and re-pairs; drop them only for forgotten servers
Also picks up records written during an in-flight replay, classifies the new UI field for
WSL moves, and fixes the test's projection shape.
* fix(repos): say 'disconnected' when the user disconnected the server, and test records surviving re-pair
* fix(repos): retry a replay when the server reconnects while it is still failing
* test(repos): narrow the toast action instead of asserting its type
* test(repos): run the toast action's removal directly instead of dispatching its handler
* fix(native-chat): keep Claude approval choices across model changes without freezing delivery
A Claude chat saved as "Approve for me" could reopen asking for every approval,
because Orca read the folder's saved model list as launch policy, and a model
change could keep running in a weaker approval mode Claude opened with. The
first fix for this was reverted after it froze the app: restored history left
a turn reading as running, a send was refused against it, and delivery retried
the same send with nothing changed.
- The saved approval choice goes to Claude as-is; the menu offers every mode.
- Orca records the mode Claude actually opened in. A send that picks a new
model reopens Claude first when that mode differs from the one requested,
only when the chat owes no work; Orca mail notices never reopen it.
- A message sent while a Claude turn is running joins that turn on its current
choices; new choices apply at the next new turn. Nothing is refused.
- History catch-up closes every turn it opens, in the thread it opened in.
- At startup, a turn reading as running under the new agent that the agent is
not running is ended as interrupted.
- Delivery goes round again only after a step shows what it changed (a commit,
a different child, a start it joined ending, or a wake); otherwise it waits
for the next change instead of repeating the same step.
Tracked in STA-10953.
* fix(native-chat): preserve execution evidence at dispatch
* Fix delivery iteration ownership and progress contracts
* Correct journal fixture types in delivery regressions
* Separate Claude input choices from error correlation
* feat: drag to reorder queued messages on desktop and phone
* fix: use the queue grip button padding from its primitive
* fix: preserve the queue grip touch width with hit slop
* test: carry queue animation mocks into the chat view harness
* test: complete the shared chat view harness registrations
* test: carry the queue move cross-version wire contract
* Scope queue move feedback to the issuing chat and preserve phone touch width
* Keep queue reorder presentation stable during measurement and pending moves
* Keep measured row handoff tokens constant size
* Avoid rebuilding queue arrival IDs on unchanged renders
* Fix mobile queue regression test fixture boundaries
* Share the queued message leading slot with its reorder grip
* Fix queue regression fixture quality findings
* Check queue icons within the leading slot
* Allow every unsettled queued message to reorder
* Supply stable scope in queued row test mock
Condition waits never forwarded --timeout, so agent-browser always stopped at its own 25s default and --timeout 60000 still failed at 25s. orcad's external Chromium run and Electron sidecar socket also capped waits at a fixed 90s. One builder now passes --timeout (explicit or the documented 25000 default) on the local and orcad paths, process kills sit 5s above it, and every forwarding hop waits max(60s, T+30s).
When a worker's turn start was not observed, the dispatch receipt claimed
the input was "written and submitted". A swallowed Enter leaves the prompt
in the composer, so say the text and Enter were written, keep the wait bound
and possible causes, and point at `terminal read` before resending.
Co-authored-by: Neil <neil@stably.ai>
* fix(mobile): compare branches and show diffs with desktop's base-ref and whitespace settings
Base-ref resolution moves to src/shared and the host publishes the compare-against-upstream
and show-whitespace settings, so the phone's branch compare and diffs match desktop.
* fix(mobile): use the upstream compare policy on the review screen and rebuild diffs when whitespace changes
* fix(mobile): reread Source Control settings on Refresh and restart diffs loading under the old whitespace setting
* test(mobile): cover diffs dropped when desktop's whitespace setting arrives
* refactor(mobile): share one Source Control settings read per host across screens
* Reuse rendered chat history across readers
* test: cover current journal reads across source changes
* test: align journal assertions with current snapshot reuse
* fix(mobile): keep a renamed tab's name on mobile after the host restarts
After a restart, the reconnecting client restarts each saved tab's
terminal (restored-pane-materialize -> createRuntimeOwnedMobileSessionTerminal),
and the mobile row built from the new terminal carried no customTitle, so
the phone showed the terminal's own title although the saved session still
held the name. publishPtyBackedMobileSessionTerminal kept a name only from
an earlier mobile row, which a restart does not have.
Both builders now resolve the name through one helper: a value already on
the mobile row wins, including a cleared null; only a row with no value
falls back to the tab's saved name.
Fixes#33737
Co-Authored-By: Claude Code <noreply@anthropic.com>
* refactor(mobile): resolve a restarted tab's saved name through getPtyManualTitle
getPtyManualTitle already owns a terminal's manual name (the saved tab's,
else the live rename), so the row builders use it instead of a second
saved-session lookup. A cleared name reads as cleared from the saved
session, so the test now covers that instead of a row-only clear.
* fix(mobile): keep a row's cleared name instead of falling back to the saved one
A null customTitle on a row is a clear: paired desktops need it to drop a
cached name, and a desktop clear lands on the row before the debounced
session write. Only a row with no value falls back to getPtyManualTitle.
* test(mobile): pin that a row's cleared name survives a terminal restart
---------
Co-authored-by: clayphi <193966884+clayphi@users.noreply.github.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
Orca wrote a synthetic "OMP ready" / "OMP - action required" title over
the session title that OMP and Orca's titlebar extension already paint.
OMP's hooks are authoritative and its own rest title reads as idle, so
stop synthesizing terminal titles for OMP, as for OpenCode.
Linear: STA-11986
#33968 pushed terminal-send-method.ts to 301 counted lines against the 300-line rule, failing Lint on main and every PR that merges it. Eight refusal branches spelled out the same zero-byte result; one helper builds it.
* fix(runtime): clear Claude's question wait when a phone keystroke answers it
Claude sends no hook after AskUserQuestion is answered; desktop infers it, phone answers left the pane waiting.
* fix(mobile): answer multi-question cards like desktop, with Skip and back-stepping
Mobile required every answer and locked grouped structured questions once tapped; the card rules and structured mapping now live in shared code.
* fix(mobile): announce ask card options as checkboxes or radios
* fix(mobile): answer a grouped question only on the prompt it was picked on
* test(runtime): drop the multi-question case the shared answer rule already covers
* refactor(native-chat): share the typed-answer rules and fold the host answer check into terminal.send
* fix(mobile): send terminal paste, keys and query replies like desktop
* fix(mobile): encode Shift+Enter for the pane's negotiated keyboard modes
The phone's xterm now tracks Kitty flags and modifyOtherKeys with desktop's tracker, seeded from the host snapshot.
* fix(mobile): keep keyboard modes across terminal snapshots
* fix(mobile): adopt snapshot keyboard modes with desktop's rule
* refactor(terminal): share snapshot keyboard-mode adoption and mode mirroring
* fix(mobile): compare terminal modes field by field instead of a dynamic read
* refactor(mobile): share terminal display-mode adoption between snapshot and resize
* fix(mobile): accept only known terminal display modes from the host
* fix(mobile): use desktop's sort, colour, count and agent-row rules in the workspace list
Recent ignores terminal output, repo colours fall back to desktop's neutral,
Home counts skip archived rows, folder workspaces trail each lane, and a stale
agent row on a live terminal reads "No update in …" like desktop.
* fix(mobile): keep Delete disabled on a primary checkout, as desktop does
* fix(mobile): keep the task text on a silent agent row
* fix(mobile): show a silent agent row's time since its last update
* test(mobile): drop agent-row tests that replay the shared verdict
* refactor(mobile): check host PTY liveness once and keep the delete guard on the row flag
* test(mobile): re-record the home catalog goldens for the list's active count
* fix(mobile): list Source Control changes with desktop's sections, sort and row rules
Conflicts get their own section in the user's group order, submodule rows lose stage and
discard like desktop, paths sort with the shared collator, and review notes go out as desktop formats them.
* fix(mobile): read the group order the host now publishes and keep submodule rows read-only
The host's paired settings projection now carries sourceControlGroupOrder, the
normalized status projection keeps submodule metadata, and conflict rows reuse the
shared conflict-kind labels.
* refactor(mobile): share Source Control grouping and row rules with desktop
Desktop and mobile group rows through one shared helper, mobile's unstage button
follows desktop's rule, and the group order resets when the host changes.