Commit Graph
15876 Commits
Author SHA1 Message Date
Neil b4ee652bcf Show child workspace statuses in the children toggle (#32224)
* Show child workspace status counts in lineage toggle

* Give child status summaries room and wrap narrow layouts

* Use solid working dots and keep child summaries on one line

* Restore children icon and clarify worktree tooltip

* Keep child totals clear of status counts in narrow layouts
2026-10-23 01:50:50 -07:00
Neil f9e883a4bf Show activity status with worktree-style counts (#26443)
* Show prioritized agent counts on the activity bell

* Move activity badge into the corner and shrink its count

* Use a fixed side column for activity status and counts

* Fix activity count spacing and status alignment

* Use worktree-style superscript counts for activity

* Keep activity count positions and update only number styling

* Keep idle layout fixtures out of active agent status updates
2026-10-23 01:30:46 -07:00
Brennan Benson 6d473f4bea Bound per-write chat selector work and guard ownership scans (#32109)
* Guard per-write chat selector work with shared ownership indexes

* Use checked sender session identities in the scale fixture

* Read each indexed tab row once during snapshot rebuilds

* Fix lexical binding and cache matching in selector lint rules

* Keep behavioral selector guards and resolve imported bindings

* Require selector binding definitions to declare functions

* Key performance subscribers by saved chat scope
2026-10-23 01:02:18 -07:00
Brennan Benson 47484b13d6 fix(native-chat): keep queued messages in the chat's own record, so a refused one can't be skipped (#30418)
* fix(native-chat): a refused queued message still blocks the queue when its card write fails

Every reader of a queued card goes through one derived view of the journal's dispatch facts,
so a card whose message was refused reads as returned even when its card-table update and heal
both failed. One decision and one writer store the derived state for every action.

* refactor(native-chat): keep each queued message in the chat's journal, not a second table

A queued message lived in its own SQL table, and a hook that may be skipped copied
each refusal from the journal into it. When that write failed, a refused card
vanished: the cards behind it sent, and its Send and Delete did nothing.

Each queued message is now a `queue` row in the chat's journal beside the
submission that hands it off and the dispatch row that answers it. The reducer
folds the card from those rows, so a refusal returns the card and holds the
cards behind it with nothing written, and replay reads the same. Every action
writes its own rows in one transaction. Cards an earlier build stored are read
through the same classification until they move: each action moves its own
card, and a bulk import runs once per open. A new epoch restates every card
still owed an answer in the transaction that deletes the old rows.

The settlement hook and its savepoint, the open-time heal, the drain's heal and
the derived-card view are gone. The published card list is unchanged.

* test(native-chat): adapt the queue tests to cards kept in the journal

Cards are written through the journal, so tests queue them with their body
alone and hand them off under their real fingerprint. Tests of the removed
settlement hook, heal and SQL store are deleted; the text-update spec now
covers the edit decision alone, and a test of an earlier build's stored holds
seeds the legacy table and reads the imported cards. Rolling over an epoch now
keeps a card whose hand-off was never handed over, so that test checks the
retried id never sends rather than that nothing sends.

* test(native-chat): a refused card holds the queue through rewind, a new epoch and a restart

One whole-flow test through the host: the refusal writes no card row, a rewind
that retires the refused hand-off and a rolled-over epoch keep the card
returned, a restart and Resume send nothing behind it, its own Send refused
again still holds the queue, and its Delete releases the next card in order.

* test(native-chat): an earlier build's queued cards move into the journal once, each read the same

One mixed-import test through the host. The first open's import fails and
moves nothing, yet every card reads as it will; Delete and Send each move only
their own card. The next open moves the rest in one transaction, writing a
refusal only where its hand-off is gone, nothing for answered cards, and leaving
an unreadable row on disk. A later command turn spends a moved command card, a
third open writes nothing, an old Delete replays from its receipt, and a chat
with only answered legacy rows clears them in a delete-only transaction.

* test(native-chat): adapt typechecked tests to cards kept in the journal

The row-kind table lists a queue row, the clear and legacy-import tests
match the current signatures, and the downgrade test keeps only the
leftover-send case: a queued card is now a newer-version journal row an
older build keeps read-only, and users don't downgrade.

* refactor(native-chat): drop the journal row writer's unused transaction hook

No caller passes one since the queue's savepoint bookkeeping left.

* test(native-chat): downgrade probes write rows at the version older builds read

The highest version this build reads is now 4, the queue row's. A newer
build's row in these probes is written at version 3 so the older build
meets its kind, not a newer version, and the Stop-event probe hands the
older build the rows as stored, since a read raises each row's version.

* test(native-chat): unit tests follow the queue row's version 4

The legacy-import test opens real SQLite, so it runs in the Node runtime
project. The newest version this build reads is now 4, and a read raises a
row's version to it, so the turn-lifecycle test no longer pins the
in-memory version (the written one stays pinned by journalRowSchemaVersion).

* fix(native-chat): one batch echoing two refused queued messages spends both

The per-row delivery check returned only the first waiting card an echo
proved delivered, so when one settlement carried echoes for two cards the
second stayed waiting and was sent again. It now returns every card the
row proves delivered, and the fold withdraws each; replay folds the same.

* fix(native-chat): a rewind moves an earlier build's cards into the journal first

While the open's import had failed, an earlier build's card that read as
refused through its hand-off lost that reading when an in-place rewind
retired the hand-off: it disappeared and the card behind it sent. The
rewind now adopts every legacy card ahead of its tombstones and deletes
their rows in its own transaction, as an epoch replacement already does,
so the fold latches each card's reading before its hand-off is gone.

* fix(native-chat): keep an earlier build's card whose hand-off is still unconfirmed

The import dropped a legacy card handed off as a send whose delivery was
unknown, though the fold keeps such a card linked and a later refusal
returns it. The import now keeps every card whose hand-off a later row can
still answer, through the same check the reducer folds dispatch rows by.

* fix(native-chat): one delivery echo withdraws at most one queued card

One provider echo proves one delivery, yet it withdrew every waiting card
with the same text whose hand-off was refused, so a second identical card
was lost. The fold now pairs each echo with one card: on its own row the
earliest-positioned match no other echo of that row took, and for a card
that waits again the earliest applied echo no card has taken. Paired echoes
live in the fold's state, so live and replay pair the same; readers of
cards not yet imported work on a copy.

* fix(native-chat): a queued message handed to the agent is sent again only on proof it never got it

Pressing Stop after Orca handed a queued or steered message to the agent,
before the agent confirmed it, put the card back in the queue, and Resume
or the next send sent it again. A check matching the agent's echo of the
text was the only guard against a double send, and it kept trading a
resend for a lost card. Whether the card waited again was decided by the
rejection's category, not by proof the agent never got the message.

A refused hand-off now waits again only where Orca proves the agent never
received it: the host still held it, or whoever settled it recorded that.
A failure still returns the card and holds the cards behind it. Anything
else may have reached the agent, so the card is spent and its message
reads as sent, derived on every fold from the stored rejection: with the
turn it was answered into, as that turn's unconfirmed message where it was
handed over; withdrawn before any turn opened, as a person's own send a
Stop took back. The reopen mark ignores a recovered doubt, and the restart
reconciler no longer judges a queued hand-off unsent from what history
lacks. The echo text matching and its pairing are deleted.

A close or quit while the agent starts settles sends with the unrun hold.
The host hands nothing to a child before its start answers
(structured-agent-session-delivery-loop.ts: a handover needs phase
ready), so such a send went to an earlier child and may have run: it now
reads as sent instead of waiting again.

* fix(native-chat): Claude's report that it removed a queued message unrun lets the card wait again

Claude says when it removed a send without running it: the interrupt
receipt's cancelled list, or a command_lifecycle cancelled, discarded or
refused frame for a command that never started. Every one settles through
rejectClaudeDispatchWaiters, which now marks the settlement unrun. For a
queued card's hand-off the host records that as proof the agent never got
it, so the card waits again under the queue's pause. A direct send keeps
the plain refusal: there the proof would owe it as stopped history.

* fix(native-chat): an earlier build's card stopped after hand-over follows the same rule on upgrade

Earlier builds put a card back to waiting after any refusal without a
verdict and cleared its link, so a card the agent may already have would
be sent again after the upgrade. The card's own hand-offs in the journal
decide now: unchanged and last sent as one that may have reached the
agent, it is spent on that hand-off and its message reads as sent; edited
or sent again since, it is held for its own Send under a host-only marker
that publishes as a plain hold; with no hand-off in doubt, including one
that never left Orca, it waits as before. The import writes a card spent
on a hand-off in doubt, so its message shows.

* fix(native-chat): read a queued row's hand-off before the lookup that uses it

The lookup's callback lost the narrowing of the row's change, which the
mobile test typecheck rejects.

* test(native-chat): a card steered into a turn a Stop ends stays sent in the Stop tests

Three tests pinned the old rule, that a card handed into a running turn
comes back to waiting when a Stop ends it. Under the new rule nothing
proves the agent never got it, so the card is spent: with the turn named,
its message reads as that turn's unconfirmed one; without, as a send the
Stop took back. Neither is ever sent again.

* fix(native-chat): a queued message stopped before Orca handed it to the agent waits again

A Stop that aborts a hand-off after its row is written but before the agent call now records
the withdrawal as never reaching the agent, for queued hand-offs only, so plan D's rule returns
the card to waiting under the Stop's pause instead of spending it. Direct sends keep the plain
withdrawal (the flag would owe them as stopped history). The agent's own refusal while aborted
is kept rather than overwritten, and an abort thrown during the call stays in doubt.

* fix(native-chat): a queued message stopped while the agent prepares it waits again

The abort signal reaches only an adapter's preparation (its options, the previous turn opening),
never its write, so the signal's own reason thrown back is the adapter saying nothing was
written. The handover now reads that, for queued hand-offs only, as never reaching the agent,
so the card waits again under the Stop's pause. Claude no longer wraps that abort as an option
refusal, which had returned a stopped card as a refused one blocking the queue. A real refusal
keeps its cause and its barrier; any other throw stays in doubt and is never resent.

* test(native-chat): the usage-limit Continue backlog case writes its card through the journal queue

Main's #30396 wrote its backlog card with the stored fingerprint and host-instance stamp the
journal queue derives instead; the card the Continue must yield to is the same waiting card.

* test(claude): the real-CLI queued Stop expects the unrun mark Claude's cancelled-unrun receipt carries

* fix(native-chat): retain spent legacy messages when import fails
2026-10-23 00:53:44 -07:00
Jinjing fd1875084f fix(chat): allow visuals to declare open without breaking scripts (#32226) 2026-10-23 00:40:12 -07:00
Neil a3512bcd47 perf(renderer): scope runtime connection and parking subscriptions (#32199) 2026-10-23 00:36:08 -07:00
Neil 758b9c2b71 ci: avoid slow Ubuntu mirrors during WebKit setup (#32205)
* ci: reuse bounded Ubuntu mirror setup for WebKit

* ci: preserve Ubuntu setup for dispatched older refs
2026-10-23 00:32:31 -07:00
OrcaWinandOrcaWin c43ec4ddbb test: keep explicit regressions without legacy algorithm copies (#32218)
* test: keep explicit regressions without legacy algorithm copies

* test: use Number.NaN in latency fixtures

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-23 00:25:30 -07:00
OrcaWinandOrcaWin 0841e09b64 test: remove classification inventories and verify settled boundaries (#32216)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-23 00:03:24 -07:00
OrcaWinandOrcaWin a5b2543d85 test: retire copied oracles and implementation inventories (#32206)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-23 00:01:39 -07:00
OrcaWinandOrcaWin 456e5830bb test: consolidate discovery coverage and replace copied oracles (#32211)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-22 23:59:35 -07:00
Neil 22a95c4efe refactor: colocate repository draft input and tests (#32155) 2026-10-22 23:33:51 -07:00
OrcaWinandOrcaWin 55b255e164 docs: condense test anti-pattern guidance (#32201)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-22 23:25:44 -07:00
Jinjing 1de36398ab fix(daemon): clear route proof during synthetic exits (#32196) 2026-10-22 23:19:23 -07:00
Jinjing 54e8ee5e96 Scope daemon inventories for safe worktree teardown (#32171)
* Fix scoped daemon inventories without changing terminal input routes

* Serialize daemon owner inventory refreshes safely

* Serialize daemon owner inventory refreshes safely

* test(daemon): protect baseline inventory budgets and recovery
2026-10-22 23:01:16 -07:00
Jinjing afe62effd3 fix(workspace): show launch actions in empty tab groups (#32182)
* fix(workspace): show launch actions in empty tab groups

* fix(workspace): resolve empty-pane browser policy by owner
2026-10-22 23:00:37 -07:00
Neil 52e413ec85 fix(mobile): finish bundle downloads over slow links with smaller ranges (#32174)
* fix(mobile): serve bundle ranges within slow-link stall budget

* test(mobile): consolidate range compatibility coverage and typed dispatch
2026-10-22 22:05:45 -07:00
Jinjing 3f7b34106a Refine Agent Dashboard lifecycle handling (#32172)
* Track Agent Dashboard adoption and daily visible use

- Record enablement, board opens, and per-surface daily visibility
- Persist daily limits across restarts and respect consent and window visibility

* Track dashboard telemetry at surface roots
2026-10-22 21:49:13 -07:00
72864c1844 fix(terminal): allow independent hidden account restarts to progress (#31994)
* fix(terminal): let independent account restarts progress in parallel

* docs(terminal): explain the detached restart concurrency cap

The regression tests reproduce the stalled-spawn scenario reported in #22243.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Tauri-EPO <176725071+Tauri-EPO@users.noreply.github.com>

* fix(terminal): re-ask and free the slot when a detached restart spawn stalls

A spawn that never settles no longer holds one of the four restart slots or
leaves its pane silently input-blocked: after 90s the pane's restart prompt
reopens and the slot is released, while the claim stays until main settles
so a late result is still adopted or reaped.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Tauri-EPO <176725071+Tauri-EPO@users.noreply.github.com>
2026-10-22 21:23:21 -07:00
NeilandClaude 601e900617 fix(orchestration): reject task messages for another implicit Run (#32037)
* fix(orchestration): reject task messages for another implicit Run

* fix(orchestration): keep task_run_mismatch typed and defer explicit Dispatch scope

Add task_run_mismatch to the RPC passthrough allowlist so clients see the
code instead of runtime_error, skip the guard when the payload names a
resolved Dispatch so lifecycle validation keeps its audited
task_dispatch_mismatch rejection, and tell the sender how to recover.

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

* fix(orchestration): let lifecycle validation own implicit-Dispatch task mismatches

Lifecycle sends (worker_done/heartbeat/escalation/decision_gate) from a worker with
an active Dispatch now skip task_run_mismatch so the rejection is recorded in the
Dispatch Run, as on main, instead of throwing advice that loops into
dispatch_run_mismatch.

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

* fix(orchestration): keep nested coordinator child-Task reports and give runnable task_run_mismatch steps

A worker that coordinates the Task's child Run still reports to its parent Run implicitly, as on main.
The refusal now names the exact --run that will be accepted; Dispatch-bound senders are only offered their own Run.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 21:23:11 -07:00
Jinjing 075ed138bd Fix GitHub PR auto-merge eligibility (#32075)
* Fix GitHub PR auto-merge eligibility handling

* Preserve GraphQL auto-merge state over REST fallback
2026-10-22 21:23:08 -07:00
NeilandClaude 26f677ee94 fix(codex): pair structured launches with the CLI runtime (#32061)
* fix(codex): pair structured launches with the CLI runtime

* test(codex): align launch snapshots with runtime pairing

* fix(agent-session): keep this app's CLI ahead of the paired runtime dir

Pairing ran after the Orca CLI prepend, so a runtime dir that also holds an
`orca` (e.g. /usr/local/bin with node+codex+orca) shadowed this app's
launcher for the child. Pair first; the CLI dir stays first on PATH.
Drops a PATH-shape test the parity snapshots already cover.

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

* fix(cli-runtime): skip compiled CLIs and keep inherited PATH when pairing a sibling node

A native codex/claude beside a node (Homebrew, /usr/bin) never runs on it, so
pairing only reordered PATH. An env naming no PATH now pairs over the PATH the
child inherits instead of replacing it with the CLI dir alone.

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

* test(cli-runtime): type the PATH-less env fixture

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 21:23:04 -07:00
NeilandClaude f4a1b0586a fix(agents): apply paired host preferences to launch menus (#31971)
* fix(agents): apply paired host preferences to launch menus

* fix(agents): keep desktop preferences for older hosts and reopen menus instantly

Hosts without settings.agent-launch.v1 (before 2026-10-11) cannot store
launch preferences, so their menus keep the desktop's visibility and
default instead of losing both. Cache the last host answer per
environment so freshly mounted menus render at once and revalidate;
host-settings saves invalidate the cache.

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

* fix(agents): align new-agent shortcut with host menu and bound first read

The tab.newAgent shortcut, its menu badge, and bound per-agent shortcuts now use
the same per-host preference snapshot as the menu. A first read that fails or
stalls past 3s falls back to desktop preferences (pre-PR behavior) instead of a
neutral order or a long placeholder; a late answer still applies.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 21:22:59 -07:00
NeilandClaude 1ec8f079d8 fix(usage): read Cursor Unified Ultra current-period quotas (#31978)
* fix(usage): read Cursor Unified Ultra current-period quotas

* fix(usage): fall back when Cursor serves the current-period route as HTML

Cursor answers unknown /api/dashboard routes with a 200 HTML app shell, so a
retired current-period endpoint would surface as a permanent parse error for
every Unified Ultra account instead of the summary fallback.

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

* fix(usage): stop labelling Cursor plan usage as monthly

Unified Ultra now reports a weekly period, so the Accounts heading and search
copy no longer promise a monthly window.

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

* fix(usage): read weekly Cursor periods for all unified and idle-pool plans

Cursor's weekly X Subscription plans (Plus/Premium/Super/Ultra, incl. enterprise
seats moved to Premium) all keep stale monthly zeros in usage-summary. Gate on
unified_* membership, or on idle summary pools with a sub-monthly current period;
non-unified plans ignore current-period failures so their behavior is unchanged.

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

* fix(usage): skip the Cursor current-period request for unlimited non-unified plans

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 21:22:54 -07:00
NeilandClaude 3d6306789a fix(cli): reject ask waits above the documented 30-minute maximum (#32044)
* fix(cli): reject orchestration ask waits above the documented maximum

* fix(cli): keep ask timeout help ASCII and trim redundant cases

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 21:22:50 -07:00
Jinwoo Hong 28c726855e fix(runtime): tab property edits live with the other tab properties, and main typechecks again (#32168)
#32018 pushed headless-terminal-tab-close.ts over the 300-line lint limit,
and its new test passed sleepWorktree to RuntimeNotifier after #31564 removed
it. setMobileSessionTabProps moves unchanged into RuntimeHeadlessTabProperties,
which already owns the helpers it calls and directly extends the close class.
2026-10-22 23:59:41 -04:00
Neil c089ca5812 fix(ci): preserve rename boundaries in React Doctor gate (#32159)
* fix(ci): preserve rename boundaries in React Doctor gate

* fix(ci): retain coverage and reject inconsistent audit reports

* test(ci): update Git status fixture for rename-aware ranges
2026-10-22 20:40:05 -07:00
NeilandClaude 77f1523d72 fix(claude): retain managed WSL selection across distro casing (#31992)
* fix(claude): match WSL account selection across distro casing

* fix(claude): keep exact WSL selection spelling ahead of casing aliases

A saved key that matches the launch distro exactly now resolves as before,
so existing mixed-alias selections do not regress to System default.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 20:31:11 -07:00
NeilandClaude 18ee07f767 fix(terminal): resolve Markdown file destinations before bare paths (#32056)
* fix(terminal): parse Markdown file destinations before bare paths

* fix(terminal): keep Windows backslashes in Markdown file destinations

Markdown unescaping turned C:\Users\me\.config\app.json into
C:\Users\me.config\app.json, a regression versus bare-path detection.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 20:31:06 -07:00
NeilandClaude 27d29bb61a fix(github): reject cached same-branch PRs with foreign heads (#32060)
* fix(github): reject cached same-branch PRs with foreign heads

* fix(github): keep same-repo cached PRs behind renamed remote URLs

A stale origin URL after a repository rename or transfer made the
foreign-head check reject the checkout's own same-repo PR and clear its
cache. Treat a PR whose head matches its canonical base URL as local.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 20:31:02 -07:00
Neil 722bb2495a fix(chat): retain unlisted reported Codex models (#32068) 2026-10-22 20:30:58 -07:00
NeilandClaude 0dc7b88358 fix(search): include undated Cursor sessions in time filters (#31991)
* fix(search): date undated Cursor sessions and retain sidecar metadata

* fix(search): truncate repaired Cursor dates to whole milliseconds

SQLite rounds sub-millisecond file times while Date#toISOString truncates,
so repaired rows could land 1ms after the date a re-read writes.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 20:30:54 -07:00
NeilandClaude 8f2f620ae8 fix(runtime): reject unsupported renderer-owned tab properties (#32018)
* fix(runtime): reject unsupported renderer-owned tab properties

* refactor(runtime): keep tab-props rationale above its method

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 20:30:51 -07:00
NeilandClaude 6c38b40984 fix(git): retain authentication guidance for push failures (#32078)
* fix(git): retain normalized authentication diagnostics in push errors

* fix(git): label auth failures for every remote operation

Pull, fetch, fast-forward and rebase toasts leaked the IPC wrapper around the
normalized auth message; Git <2.46 also reports 'could not read Password' for
remotes whose URL carries a username.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 20:30:47 -07:00
NeilandClaude ab1563e6f3 fix(cli): negotiate agent launches with paired runtimes (#32029)
* fix(cli): negotiate agent launches with paired runtimes

* refactor(cli): share paired client capability list across request paths

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 20:30:42 -07:00
Neil d7f6234274 fix(ssh): scope launch-session verdicts to managed environments (#32047) 2026-10-22 20:30:38 -07:00
95323024a1 fix(packaging): exclude root development configs from desktop packages (#32021)
Exclude the seven repository-root development configs reported in #30993
from app.asar, using the exclusion glob suggested in the issue.

Co-authored-by: Marcin Nowicki <31430+pr0d1r2@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 20:30:34 -07:00
NeilandClaude 6bbc8e2b96 docs(chat): explain structured sessions and conversation handoffs (#32063)
* docs(chat): explain structured sessions and conversation handoffs

* docs(chat): distinguish copy handoffs from in-place view switches

Same labels mean different things by surface: tab/header Continue in
Chat UI opens a new structured chat, while the terminal-pane context
menu toggles the transcript view in place. Scope composer live-value
routing by session type.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 20:30:31 -07:00
Jinwoo Hong 6a96733ba9 Install Orca's skills with one click on every setup screen (#31918)
* Add Orca's own bundled-skill planner and installer (not wired in yet)

One planner decides what installing Orca's bundled skills does to each
target folder; execute re-plans under per-path locks and runs only a plan
whose digest still matches; a shared summary derives badge, wording and
exit code. A copy counts as Orca's untouched one only when its SKILL.md
bytes match a version some build shipped (resources/skills/released-digests.json,
generated from git history and checked add-only).

Nothing calls this yet; the npx path is unchanged.

* Report left-alone folders as warnings and keep backups in the home

A leave is no longer a failure: the outcome line says what happened plus
"N left alone: <reason>", and the exit code is 1 only for a failed or
changed op. Backups for every scope go to <home>/.agents/.orca-skill-backups
on the executing host, so a project Replace never writes into the repo;
moving there falls back to copy, verify, then remove across filesystems.

* Update Orca's skills with Orca's own installer instead of npx skills

The app's Update skills dialog, badge, nudge and status pills now read the
bundled-skill plan and summary, and Update executes the reviewed plan's
digest. `orca skills install|update` runs the same planner in-process with
--dry-run, --force, --json and per-summary exit codes. Removes both npx
spawn sites, the freshness inventory modules and the npx round-trip CI.

* Update only where the skill already is; one provider-root rule for app and CLI

installedOnly now drops every location that holds nothing (keeping the shared slot
only when an existing agent link points at it), so Update never adds a skill for
another agent. The app and CLI resolve the Claude skills folder through the same
rule in localBundledSkillInput; a test asserts both plan identically.

* Compact Update skills dialog: one row per skill, locations named by agent

summarizeBundledSkillPlan now returns each skill's locations, labelled by
agent (or "Shared folder") with a ~-collapsed path; the dialog shows one row
per skill that needs something, collapses up-to-date skills into one line, and
lists every location behind "Show all locations". The result reads "Updated N
skills · M left alone". Under installedOnly a Replace with no shared copy
replaces in place instead of adding one.

* fix(skills): keep location paths readable by putting the state under the path

* fix(skills): hold the last plan in state, not a ref mutated during render

Split the update dialog's rows, headline and footer into components, move the Update label
next to the other plan copy, and use z.strictObject for the request schemas.

* Escape non-ASCII characters in bundled-skill regex and wording

The orcad bundle rejects a literal non-ASCII character in a regex.

* fix(cli): escape non-ASCII apostrophes in the skills install help text

* Plan and update Orca's skills on paired servers, SSH hosts and WSL

* Show the skills pill for paired hosts; real-WSL installer test

* test(orcad): check the bundled CLI plans a skill install without npx

Drop the deleted roundtrip workflow's group from the closed-PR cancellation fixture.

* Let the WSL installer create the backups folder itself

* Review fixes: follow the active workspace's host, keep hosts' plans and runs apart, never boot WSL for a background check

* test: execute requests carry the plan request; CLI pill follows the local target

* Write large WSL skill files in chunks that stay under the command-line limit

* Make bundled-skill test fixtures link folders the way the product does on Windows

Directory links in fixtures are junctions on Windows, which need no
Developer Mode; the one file-link fixture is skipped there.

* Let a client ask a host to install named Orca skills, not only update installed ones

* WIP surfaces

* fix casts

* Prune ratchet and shard entries for deleted files

* Review fixes: disable feature-wall Install without a host, name unknown-skill errors, drop leftovers

* Setup buttons follow the plan: Update only when it would change something, Replace for an edited copy; complete translations

* Plan an SSH workspace on the managed server that serves its host; ask to connect otherwise

* Translate the remote skill states into every locale

* Install on SSH workspaces through their managed server; ask to connect an unserved SSH host

* Resolve legacy skill agent keys canonically

* Reject stale skill replacements when auxiliary content changes

* Remove the Windows-hosted WSL bundled skill installer

* Wait for active workspace ownership before planning bundled skills

* Keep legacy WSL skill setup on its inline npx flow

* Use each setup surface's target for discovery and installation

* Describe skill setup actions and results from their install plans

* Keep ordinary bundled skill classification shallow

* Leave unreadable skill replacements alone without aborting plans

* Show blocked skill setup plans as needing attention

* Resolve skill setup discovery and installation from workspace ownership

* Keep legacy WSL setup scoped to the selected runtime

* Pass force-all through shallow planning and describe unreadable copies

* Keep skill setup previews shallow until Replace is clicked

* Stop Replace when its explicit plan cannot replace a selected copy

* Keep skill setup within the focus and workspace-record read ratchets

* Clarify skill update statuses and folder details

* Clarify skill setup results and blocking reasons

* Keep selected skill replacements in place with one status

* Use first-install wording when no agents have the skill

* Report completed skill replacements with their backup confirmation

* Preserve main’s skill selection for unavailable Computer Use

* Derive setup status and coverage from the install plan

* Use shared plan status labels on every setup panel

* Show blocking skill folders and keep incomplete setup steps pending

* Clarify available skill updates and skipped copies

* Pass setup execution outcomes to the skill result API

* Use update skipped wording in skill setup results

* Keep skill update results in preview order

* Show skipped skill copies before installing for more agents

* Show unsupported skill setup guidance before installation

* Use the host install plan for orchestration agent coverage

* Show each skill skip reason once

* Count skipped skills instead of skipped folders

* Make installer input and link tests work on Windows

* Show disconnected host guidance before offering skill installation

* Bound bundled skill classification reads and parse names linearly

* Keep workspace skill roots inside the resolved workspace

* Compare workspace skill roots with native path semantics

* Restrict bundled skill backups to their owner on POSIX

* Keep bundled skill updates on the proven local workspace host

* Keep skill details on the originating setup target

* Keep recovered skills needing attention until they are updated

* Expect recheck after a failed skill setup plan

* Count completed skill updates in the status tooltip

* Count only usable skills in orchestration agent coverage

* Sync the runtime localization catalog
2026-10-22 23:03:13 -04:00
Jinwoo Hong fa71556085 Install and update Orca's skills on paired servers and SSH hosts (#31867)
* Add Orca's own bundled-skill planner and installer (not wired in yet)

One planner decides what installing Orca's bundled skills does to each
target folder; execute re-plans under per-path locks and runs only a plan
whose digest still matches; a shared summary derives badge, wording and
exit code. A copy counts as Orca's untouched one only when its SKILL.md
bytes match a version some build shipped (resources/skills/released-digests.json,
generated from git history and checked add-only).

Nothing calls this yet; the npx path is unchanged.

* Report left-alone folders as warnings and keep backups in the home

A leave is no longer a failure: the outcome line says what happened plus
"N left alone: <reason>", and the exit code is 1 only for a failed or
changed op. Backups for every scope go to <home>/.agents/.orca-skill-backups
on the executing host, so a project Replace never writes into the repo;
moving there falls back to copy, verify, then remove across filesystems.

* Update Orca's skills with Orca's own installer instead of npx skills

The app's Update skills dialog, badge, nudge and status pills now read the
bundled-skill plan and summary, and Update executes the reviewed plan's
digest. `orca skills install|update` runs the same planner in-process with
--dry-run, --force, --json and per-summary exit codes. Removes both npx
spawn sites, the freshness inventory modules and the npx round-trip CI.

* Update only where the skill already is; one provider-root rule for app and CLI

installedOnly now drops every location that holds nothing (keeping the shared slot
only when an existing agent link points at it), so Update never adds a skill for
another agent. The app and CLI resolve the Claude skills folder through the same
rule in localBundledSkillInput; a test asserts both plan identically.

* Compact Update skills dialog: one row per skill, locations named by agent

summarizeBundledSkillPlan now returns each skill's locations, labelled by
agent (or "Shared folder") with a ~-collapsed path; the dialog shows one row
per skill that needs something, collapses up-to-date skills into one line, and
lists every location behind "Show all locations". The result reads "Updated N
skills · M left alone". Under installedOnly a Replace with no shared copy
replaces in place instead of adding one.

* fix(skills): keep location paths readable by putting the state under the path

* fix(skills): hold the last plan in state, not a ref mutated during render

Split the update dialog's rows, headline and footer into components, move the Update label
next to the other plan copy, and use z.strictObject for the request schemas.

* Escape non-ASCII characters in bundled-skill regex and wording

The orcad bundle rejects a literal non-ASCII character in a regex.

* fix(cli): escape non-ASCII apostrophes in the skills install help text

* Plan and update Orca's skills on paired servers, SSH hosts and WSL

* Show the skills pill for paired hosts; real-WSL installer test

* test(orcad): check the bundled CLI plans a skill install without npx

Drop the deleted roundtrip workflow's group from the closed-PR cancellation fixture.

* Let the WSL installer create the backups folder itself

* Review fixes: follow the active workspace's host, keep hosts' plans and runs apart, never boot WSL for a background check

* test: execute requests carry the plan request; CLI pill follows the local target

* Write large WSL skill files in chunks that stay under the command-line limit

* Make bundled-skill test fixtures link folders the way the product does on Windows

Directory links in fixtures are junctions on Windows, which need no
Developer Mode; the one file-link fixture is skipped there.

* Let a client ask a host to install named Orca skills, not only update installed ones

* Plan an SSH workspace on the managed server that serves its host; ask to connect otherwise

* Translate the remote skill states into every locale

* Resolve legacy skill agent keys canonically

* Reject stale skill replacements when auxiliary content changes

* Remove the Windows-hosted WSL bundled skill installer

* Wait for active workspace ownership before planning bundled skills

* Keep ordinary bundled skill classification shallow

* Leave unreadable skill replacements alone without aborting plans

* Pass force-all through shallow planning and describe unreadable copies

* Clarify skill update statuses and folder details

* Keep selected skill replacements in place with one status

* Report completed skill replacements with their backup confirmation

* Clarify available skill updates and skipped copies

* Keep skill update results in preview order

* Show each skill skip reason once

* Count skipped skills instead of skipped folders

* Make installer input and link tests work on Windows

* Bound bundled skill classification reads and parse names linearly

* Keep workspace skill roots inside the resolved workspace

* Compare workspace skill roots with native path semantics

* Restrict bundled skill backups to their owner on POSIX

* Keep bundled skill updates on the proven local workspace host

* Keep recovered skills needing attention until they are updated

* Count completed skill updates in the status tooltip

* Sync the runtime localization catalog
2026-10-22 22:50:05 -04:00
Jinwoo Hong 2f2a0bca5e fix(connectors): a connector backlog cannot fill orchestration's receipt ledger (#32130)
* fix(connectors): a connector backlog cannot fill orchestration's receipt ledger

Connector deliveries now refuse with delivery_backlog_full once 1,000 are
unsettled, and a new seam settles a previous process's pending connector
receipts as completed-unknown so the ledger can prune them.

* fix(connectors): settle only a previous process's receipts, not a re-enable's

The delivery receipt owner now lives for the install (one per process) and
is shared by every enabled-period seam, so toggling connectors off and on
no longer completes this process's still-running deliveries as unknown.
2026-10-22 22:46:38 -04:00
Jinwoo Hong d3dbd9683f Update Orca's skills with Orca's own installer instead of npx skills (#31688)
* Add Orca's own bundled-skill planner and installer (not wired in yet)

One planner decides what installing Orca's bundled skills does to each
target folder; execute re-plans under per-path locks and runs only a plan
whose digest still matches; a shared summary derives badge, wording and
exit code. A copy counts as Orca's untouched one only when its SKILL.md
bytes match a version some build shipped (resources/skills/released-digests.json,
generated from git history and checked add-only).

Nothing calls this yet; the npx path is unchanged.

* Report left-alone folders as warnings and keep backups in the home

A leave is no longer a failure: the outcome line says what happened plus
"N left alone: <reason>", and the exit code is 1 only for a failed or
changed op. Backups for every scope go to <home>/.agents/.orca-skill-backups
on the executing host, so a project Replace never writes into the repo;
moving there falls back to copy, verify, then remove across filesystems.

* Update Orca's skills with Orca's own installer instead of npx skills

The app's Update skills dialog, badge, nudge and status pills now read the
bundled-skill plan and summary, and Update executes the reviewed plan's
digest. `orca skills install|update` runs the same planner in-process with
--dry-run, --force, --json and per-summary exit codes. Removes both npx
spawn sites, the freshness inventory modules and the npx round-trip CI.

* Update only where the skill already is; one provider-root rule for app and CLI

installedOnly now drops every location that holds nothing (keeping the shared slot
only when an existing agent link points at it), so Update never adds a skill for
another agent. The app and CLI resolve the Claude skills folder through the same
rule in localBundledSkillInput; a test asserts both plan identically.

* Compact Update skills dialog: one row per skill, locations named by agent

summarizeBundledSkillPlan now returns each skill's locations, labelled by
agent (or "Shared folder") with a ~-collapsed path; the dialog shows one row
per skill that needs something, collapses up-to-date skills into one line, and
lists every location behind "Show all locations". The result reads "Updated N
skills · M left alone". Under installedOnly a Replace with no shared copy
replaces in place instead of adding one.

* fix(skills): keep location paths readable by putting the state under the path

* fix(skills): hold the last plan in state, not a ref mutated during render

Split the update dialog's rows, headline and footer into components, move the Update label
next to the other plan copy, and use z.strictObject for the request schemas.

* Escape non-ASCII characters in bundled-skill regex and wording

The orcad bundle rejects a literal non-ASCII character in a regex.

* fix(cli): escape non-ASCII apostrophes in the skills install help text

* test(orcad): check the bundled CLI plans a skill install without npx

Drop the deleted roundtrip workflow's group from the closed-PR cancellation fixture.

* Make bundled-skill test fixtures link folders the way the product does on Windows

Directory links in fixtures are junctions on Windows, which need no
Developer Mode; the one file-link fixture is skipped there.

* Resolve legacy skill agent keys canonically

* Reject stale skill replacements when auxiliary content changes

* Keep ordinary bundled skill classification shallow

* Leave unreadable skill replacements alone without aborting plans

* Pass force-all through shallow planning and describe unreadable copies

* Clarify skill update statuses and folder details

* Keep selected skill replacements in place with one status

* Report completed skill replacements with their backup confirmation

* Clarify available skill updates and skipped copies

* Keep skill update results in preview order

* Show each skill skip reason once

* Count skipped skills instead of skipped folders

* Make installer input and link tests work on Windows

* Bound bundled skill classification reads and parse names linearly

* Keep workspace skill roots inside the resolved workspace

* Compare workspace skill roots with native path semantics

* Restrict bundled skill backups to their owner on POSIX

* Keep recovered skills needing attention until they are updated

* Count completed skill updates in the status tooltip

* Sync the runtime localization catalog
2026-10-22 22:35:14 -04:00
Jinjing b3b493c5b7 Remove favicon drop shadows from browser tabs (#32143) 2026-10-22 19:33:40 -07:00
Jinwoo Hong 3ef3ab95fa fix(automations): a slept server run opens its own tab from a paired desktop (#32132)
* fix(automations): a slept headless run opens from a paired desktop, and a half-failed sleep keeps its pane link

A paired desktop now asks the server to open a run whose pane retention slept (its PTY id
is dropped, its pane kept), instead of only opening the workspace. Retention finishes a
sleep that stopped the run's PTY and then failed, as the host's sleep state still holds it,
instead of forgetting the run's pane on the next sweep.

* test: use typed automation retention drain hook

* test(automations): fail the real resume-record write, and recover a slept run whose record failed to save

* revert(automations): drop the half-failed sleep recovery, which no real path reaches

A real headless serve keeps a slept run's pane resolving to its stopped PTY, so retention's
retry already re-sleeps and keeps the pane link; a failed resume-record write is swallowed
inside the sleep. Only a mocked null PTY lookup reached the runSleepHeld branch.
2026-10-22 22:21:51 -04:00
Jinwoo Hong 6768988ed6 Add Orca's own bundled-skill planner and installer (not wired in yet) (#31662)
* Add Orca's own bundled-skill planner and installer (not wired in yet)

One planner decides what installing Orca's bundled skills does to each
target folder; execute re-plans under per-path locks and runs only a plan
whose digest still matches; a shared summary derives badge, wording and
exit code. A copy counts as Orca's untouched one only when its SKILL.md
bytes match a version some build shipped (resources/skills/released-digests.json,
generated from git history and checked add-only).

Nothing calls this yet; the npx path is unchanged.

* Report left-alone folders as warnings and keep backups in the home

A leave is no longer a failure: the outcome line says what happened plus
"N left alone: <reason>", and the exit code is 1 only for a failed or
changed op. Backups for every scope go to <home>/.agents/.orca-skill-backups
on the executing host, so a project Replace never writes into the repo;
moving there falls back to copy, verify, then remove across filesystems.

* Escape non-ASCII characters in bundled-skill regex and wording

The orcad bundle rejects a literal non-ASCII character in a regex.

* Make bundled-skill test fixtures link folders the way the product does on Windows

Directory links in fixtures are junctions on Windows, which need no
Developer Mode; the one file-link fixture is skipped there.

* Reject stale skill replacements when auxiliary content changes

* Keep ordinary bundled skill classification shallow

* Leave unreadable skill replacements alone without aborting plans

* Bound bundled skill classification reads and parse names linearly

* Keep workspace skill roots inside the resolved workspace

* Compare workspace skill roots with native path semantics

* Restrict bundled skill backups to their owner on POSIX
2026-10-22 22:19:34 -04:00
Jinwoo Hong 07a07a0326 fix(relay): stop reviving a session outside the cell's map, keep the seat feed on live sessions, and log demote outcomes (#32149)
* fix(relay): repair cell seat-log drift, and keep a new session's generation above a listed seat

Directors mirror each cell's seat feed, so the feed must list exactly the cell's live sessions.
The cell now sweeps its seat log against its sessions on a director's poll: a seat no session
backs is left (4409) and the live session listed, and a live session the feed lost is listed
again, each once two sweeps in a row find it. A demotion naming an unbacked seat repairs it at
once. A host's new session now starts above any generation the feed still lists, which closes
the drained-session reconnect race that removed a live seat.

Claude-Session: asia-drain-pulse

* fix(relay): refuse a rebind whose session left the map during activation, and keep a per-host generation floor

A rebind whose database activation outlived the orphan grace (or a drain) revived the removed
session outside the map: connected, still in the seat feed, and unreachable by phones or
demotion for as long as the host stayed up. Activation now rechecks the map after its awaits and
refuses with PEER_DROPPED so the host redials. Generations come from a per-host floor that
outlives the session, and an activation at a generation already used here is refused.

Claude-Session: asia-drain-pulse

* fix(relay): log each demote outcome on the director by host digest

The director now reads the cell's existing {v:1, outcome} demote reply and logs it; the cell's
feed stays the only source of its map. The supersede line now reaches the log as well.

Claude-Session: asia-drain-pulse
2026-10-22 22:16:58 -04:00
Neil d667e54b02 refactor: colocate relay assignment admission owners (#32142) 2026-10-22 18:39:05 -07:00
Jinwoo Hong 385418e0db fix(mobile): the shell returns to a screen already on its stack (#32110)
* fix(mobile): the shell returns to a screen already on its stack

The page's own "back to hosts" chevron calls dismissTo('/') inside the page, which the page's
router hands to the shell as one navigate message. The shell pushed every such href, so leaving
a host from its page left [Home, Host, Home] with the old host page still mounted (WebView and
live subscriptions), and every round trip stacked another one. System Back then walked back
through stale host pages.

The shell now reads the navigation container's state first: an href that is already a screen
below this one (same path and query) is popped back to, and an href that is this screen is
dropped. Anything else is pushed as before. The pop names its navigator and source route
explicitly, because a screen's dispatch otherwise stamps its own key as the source and a parent
stack that cannot find it drops the pop.

The wide host-route dismissTo stays for the hrefs this rule does not cover: a host route whose
query differs from the one below (the missing-worktree bounce), and a cold deep link with no host
route below to return to. Overlay replace is unchanged, and so is the bridge message.

* fix(mobile): a param cleared to empty and a fragment still match a screen on the stack

The session screen clears paneKey with setParams({ paneKey: '' }), which leaves ?paneKey= on the
stack entry, so a later navigate to the plain session href found no match and pushed a duplicate.
Empty query values are now dropped when canonicalising, and the fragment is stripped since
expo-router keeps it as a param no href spells the same way.
2026-10-22 21:07:32 -04:00
Jinwoo Hong 5aa5467c27 feat(mobile): one download bar whose fill follows progress on the native driver (#31755)
* feat(mobile): one download bar whose fill follows progress on the native driver

The page download's replies keep the JS thread busy, so React committed
nothing until the end and both bars sat at zero, then jumped to full.
The session now publishes each progress step to a small feed as it is
dispatched, and one shared bar eases its fill to each value with
Animated on the native driver (scaleX). The caption stays React-drawn.

* fix(mobile): the download bar always moves on the native driver

With reduced motion, the fill jumped through a JS-side setValue on a value
that never became native, so on Fabric it only moved with React commits,
which the download holds off. An unread preference also counted as
reduced, so a freshly mounted bar took that path. Every step is now a
native-driven timing, of zero length when motion is reduced, and the
preference is read through a ref.

* fix(mobile): the download bar starts at most one ease per 50 ms

The feed fires per asset, often well under a millisecond apart. Starting a
new 150 ms timing on each one replaced every ease before it drew a frame,
so on iOS the fill stayed near empty until the last update.

Now a callback inside the 50 ms window only records the latest fraction;
the next callback past the window, or a trailing timer at its end, eases
to it over 100 ms. Full lands at once. The effect cleanup clears the timer.
2026-10-22 21:03:28 -04:00
Jinwoo Hong ccc520ab09 feat(mobile): download only the page assets the cached generation lacks (#31769)
* feat(mobile): download only the page assets the cached generation lacks

Before paging the bundle, the phone matches the new manifest against the
host's active generation by content (sha256 and length). Matches are read
from disk and hashed again while the changed assets come over the wire;
one whose bytes no longer hash to the manifest is downloaded instead.
Progress counts only the bytes that cross the wire.

* test(mobile): put the older-build manifest note back on its describe

* perf(mobile): copy unchanged page assets natively instead of reading and hashing them

The reuse pass read every unchanged asset into JS and hashed it again,
which kept the JS thread busy for most of an update. The cached
generation was hash-verified when it was written, is never written
again, and is what the page already opens as is, so matching assets are
now copied natively into the staging tree and checked by size. A copy
that fails or comes up short is downloaded instead; stage refuses a
reused copy that is no longer whole. Path rules move to
generation-asset-path.ts and the copying to generation-reuse.ts.

* fix(mobile): copy reused page assets at stage, on the store's queue

Copies made when the manifest was read sat in tmp for the whole download,
where a second shell mount's sweep, or a second download of the same
build, could take them away and fail the stage. The fetch now only checks
that each reusable file is still whole (a native stat) and leaves it to
the stage, which copies it from the generation active at that moment and
checks its size. Copy destinations must not exist, as on both platforms.
2026-10-22 20:59:14 -04:00