Commit Graph
15854 Commits
Author SHA1 Message Date
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
Jinwoo Hong 5a097e7739 feat(mobile): decode page-bundle download windows natively (#31817)
* feat(mobile): decode page-bundle download windows natively

Each 384 KiB window of the page-bundle download cost about 200-300 ms of
Hermes JS time (tweetnacl secretbox open, fflate gunzip, a base64 re-encode
check and the TextDecoder polyfill), which kept the JS thread busy for the
whole download.

The phone now opens v2 frames with react-native-libsodium (secretbox open and
strict base64) and decodes ranges with a local Expo module,
orca-bundle-window-codec (bounded gunzip via system zlib on iOS and
java.util.zip.Inflater on Android, plus strict UTF-8). The shared v2 session
takes these as optional primitives; the desktop keeps tweetnacl.

If any native piece is missing or fails a known-answer probe, the phone keeps
today's JS path, with the base64 re-encode replaced by an O(1) canonical check.

* refactor(mobile): name the native decode for every inbound frame, not just bundle windows

The native secretbox, base64 and UTF-8 primitives decode every inbound v2
frame on the phone, so the files and the Expo module are renamed for what
they cover (paired-e2ee-native-*, orca-gzip-utf8-codec). A throw from the
native UTF-8 decode now falls back to TextDecoder, since the frame is
already open and its counter advanced.

* test(mobile): pin the TextDecoder fallback when native UTF-8 throws

* fix(mobile): hand the native decode to the transport from the app entry

The transport modules are reached by shared, desktop and e2e code. Importing
the native bindings there pulled expo-modules-core into the e2e typecheck,
whose global types make NODE_ENV required and broke ~20 e2e files. The app
entry now provides the bindings; without them the transport runs the JS path.

* fix(mobile): a native-codec lookup before the app provides bindings does not pin the JS path
2026-10-22 20:55:22 -04:00
Jinwoo Hong ca1e870dbb feat(connectors): reopen a closed or exited agent on its next message (B2c) (#32119)
* feat(connectors): reopen a closed or exited agent when its conversation gets a message (B2c)

Behind experimentalConnectors. When a connector message reaches a conversation whose agent tab was
closed or whose agent exited, the seam resumes the agent's own session in the same workspace
through resumeAgentSessionInWorkspace, waits for its composer, delivers the message and answers
accepted with reopened. The session id is copied onto the conversation link as hooks report it.
Refusals: agent_asleep_in_window, no_session_to_reopen, reopen_refused; a session another pane
may still hold (an SSH host out of contact included) stays agent_not_reachable.

Resume claims now end as soon as the hook store reports the resumed session, rather than at the
next claim, since an agent that exits to its shell drops its hook row and kept the claim held.

* fix(session-resume): end a resume claim when the hook store reports it, not at the next claim

A resume claim (#31718) ended only when a later claim found the hook store naming the session in
the claimed pane. An agent that quits to its shell drops its hook row, so that later check found
nothing and the claim stayed held for as long as the shell lived: every other resume of the
session was refused as held_elsewhere. Claims now watch the hook store's provider-session changes
while any is held and end each hold as soon as it is reported.

* fix(connectors): pin reopened process before readiness and capture existing session

* fix(connectors): watch persisted links' sessions from host startup and after re-enable

A fresh seam (connectors turned back on, or a runtime restart) watched only the links its own
calls touched, so a session that changed before the next connector call was missed and a reopen
resumed the old conversation. A new seam now snapshots every persisted link's hook-reported
session and watches it, and the runtime builds the seam when its hook store attaches at startup
rather than on the first connector call.

* fix(session-resume): end a hold on report only when it covers one bound spawn

The report names a pane, not a spawn, so with a second overlapping open of the same pane still
unsettled or bound to its own PTY, ending the hold early could let another pane resume while
that spawn still writes. Those holds keep the existing PTY-exit and next-claim ends.

* fix(session-resume): settle a lost-reply resume attempt when a retry of the same request binds

A targeted resume whose spawn reply was lost keeps its share held, since its process may run.
A retry of the same request reconciles that same create, so when the retry binds its PTY the
earlier attempt's share is accounted for by it: the hold now ends when that PTY exits instead of
never. A different request's spawn still accounts only for itself, and a lost reply is never
read as an exit.

* fix: preserve overlapping resume holds during lazy report checks

* test: verify disabled connector startup and restored capture
2026-10-22 20:44:33 -04:00
Jinjing 9070eb93b8 Track transcript content truncation across session readers (#32086)
* Track transcript content truncation across session readers

* Separate transcript decoding from preview truncation

- Preserve full searchable message content with explicit truncation metadata
- Keep bounded previews independent of transcript publication across parsers

* Fix AI Vault transcript preview parsing and cache upgrades

- Preserve full Devin and Grok transcript turns while bounding preview scans
- Exclude stale previews that may expose reasoning after cache schema changes

* Clarify Devin parser test payload terminology
2026-10-22 17:30:28 -07:00
Neil cae9a066b3 refactor: colocate Linear list-scoping owners (#32133) 2026-10-22 17:24:09 -07:00
Jinwoo Hong f0450469e4 fix(session-resume): end a resume claim when the hook store reports it, not at the next claim (#32120)
* fix(session-resume): end a resume claim when the hook store reports it, not at the next claim

A resume claim (#31718) ended only when a later claim found the hook store naming the session in
the claimed pane. An agent that quits to its shell drops its hook row, so that later check found
nothing and the claim stayed held for as long as the shell lived: every other resume of the
session was refused as held_elsewhere. Claims now watch the hook store's provider-session changes
while any is held and end each hold as soon as it is reported.

* fix(session-resume): end a hold on report only when it covers one bound spawn

The report names a pane, not a spawn, so with a second overlapping open of the same pane still
unsettled or bound to its own PTY, ending the hold early could let another pane resume while
that spawn still writes. Those holds keep the existing PTY-exit and next-claim ends.

* fix(session-resume): settle a lost-reply resume attempt when a retry of the same request binds

A targeted resume whose spawn reply was lost keeps its share held, since its process may run.
A retry of the same request reconciles that same create, so when the retry binds its PTY the
earlier attempt's share is accounted for by it: the hold now ends when that PTY exits instead of
never. A different request's spawn still accounts only for itself, and a lost reply is never
read as an exit.

* fix: preserve overlapping resume holds during lazy report checks
2026-10-22 19:53:40 -04:00
Jinwoo Hong bd5cb0b3a5 refactor(automations): share the idle agent-turn completion rule (#32114)
judgeIdleRun's rule (fresh done since the prompt went in, shell refusal of the
agent command, 2-minute grace for agents that never report status) moves into
judgeIdleAgentTurn, keyed by rows and send time instead of an AutomationRun.
Automations keep their wording and call order. No behaviour change.
2026-10-22 19:53:36 -04:00
Jinwoo Hong a61be4f11c refactor(runtime): share the phone push's terminal-agent turn news (#32113)
The transition-to-announcement rules (lead-agent finish under background work,
all-clear dedupe, quiet window for goal/Pi agents, restored-pane seeding) move
into TerminalAgentTurnNews; the phone push keeps its wording, window/mute gate
and burst cooldown and composes it. No behaviour change.
2026-10-22 19:53:32 -04:00
Jinwoo HongandClaude 41661e3312 feat(sidebar): main runs workspace sleep; the window follows (P3b) (#31564)
* fix(sidebar): land flip-a's switch-on fixes on main, still dark (no flip)

The fixes found while the sidebar ran from main's feed, without turning
that on: ORCA_SIDEBAR_INPUTS_IS_MAIN stays false, and none of flip-a's
stop-gaps come along.

- Main stops counting a closed tab's terminal once it was asked to stop
  and no pane shows it; a failed or refused stop takes the request back,
  and a host out of contact stays unverifiable.
- Main fetches a paired server's rows with the transport's normal bound,
  so a server slower than 5 s still lists.
- A deferred unread raise flips the folder row it was decided for, and a
  read while the owner check is out cancels it.
- Phone: no worktree.ps flash before the feed; a host's last installed
  feed stands in while a fresh read is out; it highlights its own
  last-opened workspace and a fold never scrolls; projects file under
  their project group with the desktop's indent; the collapse spinner
  shows only after 500 ms; "Reopen to update" keeps the rows on screen.
- e2e helpers and journeys for the switch-on suite.

* fix(sidebar): keep an owed relay stop marked, clear a thrown stop, and prune pending unread raises

- A stop-and-wait that throws takes its stop request back, like one that fails.
- A final stop the legacy relay still owes stays marked, since the relay retries it.
- Pending unread raises are tracked only while one waits, so the map no longer grows.
- The paired-server fallback poll test gives its third fetch a reply and asserts live.

* feat(sidebar): main publishes cached snapshots and announces its own stores; detected, view and live-content domains (inert)

* fix(sidebar): keep links confirmed only by a new git run, no rescan on metadata writes, no phone wait on detected checkouts

* fix(sidebar): rescan the workspace rows when the Windows runtime default changes

* feat(sidebar): one lifecycle queue per workspace in main, with in-progress hints (switch-gated)

Create, delete, terminal.closeAll, terminal.sleep and worktree.sleep now run through one
first-in, first-out queue per host-qualified workspace: strict order, no merging, delete
cancels what has not started and waits for what has, an unconfirmed outcome pauses until
the host's own answer. Hints publish in a new inProgress feed domain (no reader yet); the
creations domain is its projection. A finished create or delete keeps its hint until a scan
started after it applies, in the same revision. Adds the paired-server metadata serializer
(saving domain, no caller yet). Replaces the creation registry.

* fix(sidebar): a create never queues behind the previous occupant's delete

* feat(sidebar): main runs sleep; the window follows (P3b)

* fix(sidebar): keep electron out of the headless server's sleep path

The desktop registers how sleep reaches paired servers; a headless serve has none.

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

* test(sidebar): type-check the sleep e2e specs; drop the removed VM suspend stub

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

* fix(sidebar): resume a paused workspace by re-observing, never replaying

- A command issued while paused waits behind the pause; when the owner answers again main
  re-reads terminal liveness and the listing, then carries on. A forced delete runs past it.
- Commands keep their arrival order across a workspace lookup; deletes by name key by the
  resolved id, so they wait for that workspace's running sleep.
- A second delete with different options is refused as already in progress.
- Close and delete read lost contact as sleep does.
- A create always frees its own queue entry, even after a retry took over its id.
- Drops the unused opId, and the paired-server write serializer and its feed section,
  which land with their first caller.

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

* fix(sidebar): main is the only writer of a sleep's wake records; sleep classifies only lost contact as unconfirmed

- The window no longer captures wake records for a sleep main runs; it takes main's records
  from main's answer, which its wake and tab-open resume then read.
- A workspace reopened during its sleep keeps its VM running (the window and a phone's
  activation tell main).
- Only lost contact pauses: a definite chat-stop failure or a server's still-live answer is a
  plain failure with today's toast.
- A paired server's chats are asked with the Sleep mark, and again without it when an older
  server refuses the field, instead of reading an unprobed status.
- A phone's worktree.sleep is answered on acceptance and its activation no longer waits on a
  queued wake, so neither can outlast the phone's request timeout. The web client passes
  markChatsAsleep and keeps the receipts.
- One desktop adapter, passed where the desktop builds the runtime, replaces the two module
  slots; a headless server gets none.

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

* chore(sidebar): share worktree.sleep's params with the RPC catalog; lint fixes

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

* test(sidebar): test the paired-server sleep where main runs it; drop the window's copies

The window no longer sleeps a paired server's terminals, so its convergence and order tests for
that path move to main (remote-workspace-terminal-sleep.test.ts) or follow main's answer.

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

* test(sidebar): retry the sleep spec's liveness read while terminals stop

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

* fix(sleep): main resumes every workspace-sleep wake; the window only attaches

- Main claims and starts each slept pane through its windowless resume path, with or
  without a window: the "window present" check is gone.
- A phone's open queues main's wake, which finishes only once the resumes have started,
  and always notes the reopen so a running sleep leaves the VM up.
- The window no longer relaunches a workspace sleep's records in fresh tabs; opening a
  slept pane asks main to resume it and the pane's spawn attaches to main's terminal.
- A window save cannot overwrite main's workspace-sleep records.
- A VM that would not suspend no longer reads as "kept open": the terminals slept, and
  the toast says the machine is still running.

* test(e2e): main resumes a slept pane once, in place, and keeps its record

* chore(i18n): add the VM-still-running sleep message

* fix(sleep): a phone's or the CLI's failed sleep shows the desktop toast again

* fix: restore main's final P2 test fixes a merge reverted

* fix(sleep): window saves never write or clear main's sleep records; headless wake report counts only real sleeps

* test: a same-id twin's grace follows the rows' change, not the removed catalog hook

* fix(sleep): drop the 1 s settle wait after an observed exit, and wake a slept workspace's mounted agents on phone open

A workspace sleep stopped each terminal through main's stop-and-verify, which polled for a
further second after the exit it had already seen. And a phone opening a slept workspace no
longer reached the window's mounted panes of agents that had finished before the sleep, so
they stayed asleep until the window opened their tab.

* test: give the workspace-sleep wake record its prompt field

* refactor: match slept-agent records to the workspace with worktreeIdsEqual

* chore(sleep): one import from sleep-record-pane-claim

* test(sleep): route the disconnected-sleep SSH spec, declare the desktop sleep adapter, and open the workspace after its sleep starts

* test(sleep): delete a workspace the spec creates, not the seeded one later specs share

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-22 19:39:07 -04:00
Jinjing c1a47b0c16 fix(i18n): translate recent UI copy (#32125) 2026-10-22 16:31:30 -07:00
Neil ba0603c764 refactor: colocate repository AI persistence queue (#32122) 2026-10-22 16:29:51 -07:00
Kelvin Amoaba 5288d26a10 fix(mobile): copy OSC 52 terminal writes to the phone clipboard (#32042) 2026-10-22 23:02:30 +00:00
Kelvin Amoaba 1ac2c6a827 fix(agent-status): keep a finished turn done when the agent reports an approval at idle (#32015) 2026-10-22 22:56:04 +00:00
Neil ed5ad7f09b refactor: colocate repository worktree defaults (#32112) 2026-10-22 15:45:59 -07:00
Kelvin Amoaba 31bffb8c00 fix(sidebar): switch workspaces when accessibility tools press a sidebar row (#32007) 2026-10-22 22:40:39 +00:00
Kelvin Amoaba 2266260bbd fix(links): end autolinked urls at CJK punctuation in chat, terminal and mobile (#32013) 2026-10-22 22:38:36 +00:00
Kelvin Amoaba c69e83176d fix(gitlab): find issues and #N in the new-workspace gitlab source (#32005) 2026-10-22 22:36:52 +00:00
Kelvin Amoaba e0bd073930 feat(browser): Chrome-style page context menu and DevTools window shortcuts (#31821) 2026-10-22 22:36:18 +00:00
Kelvin Amoaba 494ecd2141 fix(settings): keep agent environment values with spaces when the field loses focus (#31772) 2026-10-22 22:35:00 +00:00
Kelvin Amoaba fc672f7d81 fix(pi): continue the chat when a background subagent wakes an idle parent (#31778) 2026-10-22 22:31:37 +00:00
Neil 799bb18aa5 refactor: colocate repository Jira project settings (#32107) 2026-10-22 15:15:31 -07:00
Kelvin Amoaba f4974b8958 fix(mobile): send multi-line chat messages as one bracketed paste (#31776) 2026-10-22 22:14:18 +00:00
Jinwoo Hong 0a8c7680be feat(session-lifecycle): targeted resume of a recorded agent session, sharing an in-flight claim with pane resume (#31718)
* feat(session-lifecycle): one targeted resume of a recorded agent session, sharing an in-flight claim with pane resume

resumeAgentSessionInWorkspace composes the lifecycle owner's existing
ownership check, window-wake claim, resume builder and terminal create, and
returns the new binding or a typed refusal, never a shell or fresh agent.
Pane resume now takes and consults the same in-memory claim, so an SSH
resume before its first hook (or any spawn in flight) cannot be resumed
twice. The explicit-command create path now carries launchRuntime.

* fix(session-lifecycle): claim before deciding, create runtime-owned, keep ambiguous spawns held

Both resumers take the in-flight claim before any awaited check, so a
settled claim always hands off to a fresh holder decision. The targeted
resume creates through the runtime-owned create with a pane identity
derived from its request, keeping launchRuntime with a window attached and
letting a retry reconcile the pane it may have started. A failure after the
spawn request left keeps the session held; a bound hold ends on its PTY's
exit as it happens.

* fix(session-lifecycle): bind a failed create's spawned PTY, retry over its own pane, forward abort

A create that spawned and then failed binds the hold to the PTY its pane
gained since the claim, so that PTY's exit still ends it (both resumers).
The targeted resume's holder check excludes its own request-derived pane,
so a same-request retry reaches create reconciliation after its hook. The
request signal reaches the runtime-owned create; an abort before dispatch
refuses as aborted.

* fix(session-lifecycle): settle resume claims only from the create's own PTY

A claim binds only to the exact PTY the runtime-owned create produced,
reported before publication can fail; its exit ends the hold. A spawn that
proved its exit during start, or a failure before dispatch, releases it.
Any other dispatched-but-unidentified outcome stays held. Drops the
pane-difference fallback, which could bind an unrelated shell. Signals
dispatch only after the create-mutation recipe check, which can still
refuse before dispatch.

* test(runtime): remove duplicate review-only test runner

* fix(session-lifecycle): hold a resume until every PTY its overlapping opens bound exits

Overlapping opens of one pane can each spawn; the hold now watches every
bound PTY and ends only when all have exited and no open is still
spawning. Test helpers replace Reflect calls with typed guards.

* fix(session-lifecycle): key resume claims by destination pane
2026-10-22 18:03:05 -04:00