Commit Graph
16002 Commits
Author SHA1 Message Date
Neil 51cb2f189c refactor: organize native chat input and transcript owners (#37334) 2026-11-02 03:14:58 -08:00
Neil 95d1e9127e fix(wsl-hosts): a stopped distro still lists all its projects after a restart (#37396)
* fix(wsl-hosts): a stopped distro still lists all its projects after a restart

The desktop now keeps each WSL host's last project list (from the repo.list
answers the window already receives) and seeds those rows at startup before any
live host catalog is requested. The first live list replaces them, so projects
deleted on the host disappear on that fetch. Loading the saved list is a desktop
read only: no wsl.exe, no host RPC, no \\wsl.localhost access. The saved list is
cleared when the host is removed.

* fix(wsl-hosts): pin saved project list writes, removal, WSL gate and seed races

- Exempt HostRepoCatalogSnapshotPersistence.environmentId from the id-only
  store write ratchet like the paired-server layout snapshot (the id names the host).
- A live list applied before the startup seed now skips that host's seed, and
  a live answer requested before the seed may still drop seeded rows.
- Tests now count saves, cover remove then re-add, check paired servers in
  storage and in the listing, and cover both seed/live-list orderings.
2026-11-02 03:10:36 -08:00
Neil 6c6e3d93c3 Show a penguin icon for WSL host rows and the stopped-distro notice (#37389)
* WSL hosts: penguin mark for WSL host rows, and on the stopped-distro notice

Sidebar project headers and workspace rows that named a WSL host with a
text badge ("orca-demo (WSL)") now show a small penguin icon instead,
labelled and tooltipped "Runs on WSL: orca-demo (Linux)". The same mark
replaces the host chip in the jump palette. The "<distro> is stopped"
notice leads with the same penguin.

* Wait on the tooltip instead of sleeping in the WSL mark tests

* Redraw the WSL penguin as the classic mascot; focusable tooltip mark; muted token on the stopped notice icon

* Use the classic Linux mascot silhouette for the WSL penguin

* Tolerate unloaded runtime environments in the WSL host mark selector
2026-11-02 03:10:29 -08:00
Neil 499da04f10 fix(wsl-hosts): keep the e2e fake WSL connector out of release builds (#37378)
* fix(wsl-hosts): keep the e2e fake WSL connector out of release builds

The fake WSL host connector was compiled into every build and honored
whenever ORCA_E2E_FAKE_WSL_HOSTS was set. Gate main and preload on
import.meta.env.MODE === 'e2e' (the mode every e2e build already uses),
so other builds fold the branch away and drop the module, and mark its
module-level schemas pure so none of it is retained.

* fix(wsl-hosts): build the e2e fake's zod schemas lazily so release builds drop them

Eager module-level zod chains survived tree-shaking even with a PURE
annotation on the outer call, so the fake's schema construction still
shipped in out/main/index.js.
2026-11-02 03:10:25 -08:00
Neil 76320e58cf fix(wsl-hosts): remove a freshly installed server that fails its start check (#37388)
* fix(wsl-hosts): remove a freshly installed orcad that fails its start check

A WSL connect that uploaded an orcad build whose candidate then failed its
preflight or readiness check left the complete install in place, so every
later connect reused the same broken bytes. deployOrcad now reports whether
it uploaded the slot and whether the candidate's own start check failed, and
the WSL deploy removes that slot under the same pins, liveness probe and GC
claim the version GC uses (active, rollback target, the serving daemon's
build, journaled transactions), so the next connect re-uploads it.

* fix(wsl-hosts): fence the failed-install removal and keep a slot any process runs from

Review follow-up. The pin check and the delete now run under the
activation fence (a held fence keeps the copy), so a concurrent connect
cannot preflight or launch the slot between them; it waits, finds the
slot gone and re-uploads. Liveness now also scans the process table and
the daemon pid files for anything running from the slot, because a
candidate's stop ends only its server, not a terminal daemon it spawned
there.

* fix(wsl-hosts): match the resolved slot path in the slot process probe

Node realpaths its entry, so a daemon behind a symlinked home or data
root names the resolved slot. The probe now also matches
$(cd slot && pwd -P)/ and answers UNKNOWN (keep) when it cannot resolve.

* test(wsl-hosts): wait for sibling slots to run before proving this slot idle

Replaces a fixed 100 ms sleep (flagged by test-no-real-time-wait) with an
expect.poll until each sibling's own slot probes LIVE, so the DEAD answer
for this slot is meaningful.
2026-11-02 03:10:09 -08:00
Kelvin Amoabaandagustin2606 47506f3f33 fix(github): link a branch's open PR instead of a newer closed one (#37452)
* fix(github): prefer the open PR when a branch has several

The branch lookup asked GitHub for one PR across all states. GitHub sorts
a branch's PRs newest first, so a closed PR opened after the live one
shadowed it and got linked to the worktree on every checkout.

Fetch a page of the branch's PRs, REST and the `gh pr list` fallback alike,
and take the open one; with none open, keep the newest as before.

* refactor(github): keep branch lookup casts on their own lines

---------

Co-authored-by: agustin2606 <agustinvarela2606@gmail.com>
2026-11-02 10:59:44 +00:00
Kelvin Amoabaandrafael rotiroti a444233103 fix(sidebar): keep folder project roots visible when hiding the default branch (#37444)
* fix(sidebar): keep folder roots visible when hiding default branch

* test(sidebar): trim folder-root hide-default tests to distinct cases

---------

Co-authored-by: rafael rotiroti <rotirotirafa@gmail.com>
2026-11-02 10:47:45 +00:00
Brennan Benson 1ce79608a4 Full access Claude chats stop asking for approval (#37246)
* fix(claude): Full access approves Claude's own permission asks in chats

A Claude chat in Full access still showed Allow/Deny cards whenever Claude Code
forwarded an ask it keeps under bypass mode (ask rules, ask-answering hooks,
built-in shell safety checks). Approve those at once while the chat runs with
Full access, read per request; questions and plan approval still go to the user.

* fix(claude): Full access grant comes from the launch; Claude's mode reports restrict it in wire order

Only a process Orca launched with Full access can auto-approve Claude's own
asks; Own settings never does, whatever Claude reports. Claude's init/status
mode reports, read from stdout before the SDK sees them, can suspend and
restore that grant, and each permission request keeps the mode in effect at
its own position in the stream, so a paused journal consumer or a read-ahead
chunk cannot apply a report late or early. Questions, plan approval and
requests Claude flags as needing the person's answer keep their card.

* fix(claude): Full access keeps every request's own wire position and restores after an approved plan

A permission request Orca never saw on stdout no longer inherits a later
mode: each request keeps the first snapshot for its id until the SDK hands
it over, including after a cancel and past any number of unread requests,
and requests resent in initialize's reply are recorded where that reply
arrived. Approving a plan in a Full access chat now reads Claude's mode in
wire order, so the restore is sent even while the chat's presentation still
lags behind the plan report.

* test(claude): narrow contract-pin frames to permission requests with a type guard

* test(claude): count the policy's stdout search work instead of timing it

* test(claude): type the contract-pin frame guard with the fixture frame union

* refactor(claude): let the launch permissions wrap the exit handler, keeping acquisition under its line limit
2026-11-02 02:27:35 -08:00
Kelvin Amoaba 8458e704c4 fix(native-chat): show a terminal's unsent input in the chat composer and replace it on send (#36493)
* fix(native-chat): show a terminal's unsent input in the chat composer and replace it on send

Switching a pane to chat view now seeds the composer with the text left unsent in Claude Code's or Codex's input box, and a chat send clears every line of it instead of one Ctrl+U. The clear is confirmed with the same typed-only read and kept under the 64-byte chunk Claude Code reads as a paste.

* test(native-chat): drop the removed screen-text clear check from the background-rows test

* fix(native-chat): clear a seeded multi-line draft before typing a Codex command from chat

* test(native-chat): expect the typed command's clear argument in composer tests

* fix(native-chat): confirm a seeded draft is cleared before typing a Codex command

* fix(native-chat): find Claude's closing frame past dim suggestion rows

A typed-only read stopped at the suggestion row, so a draft under Claude's hidden caret never reached chat.
2026-11-02 10:22:23 +00:00
Brennan Benson 255401c2a5 Continue chats automatically when a usage limit resets (#36873)
* fix(native-chat): an open chat moves to the account you switch to before its next message

A running chat's agent read its account only when it started, and nothing compared it with the
account a start would use now, so open chats kept answering on the old account after a switch.

The agent a chat runs now records the account its launch used, and the host's replace-before-the-
next-send check replaces an idle one whose account is no longer what a start would use. A chat
mid-reply finishes on the old account first. Claude chats follow; agents whose chats keep the
account they were created on are never compared.

A chat's model-list reads and saves now use the account it runs on, so a moved chat no longer
writes its new account's list under its first account (STA-11281).

Tracked in STA-11211.

* fix(native-chat): declare the launch-account read for the runtime layer that wires the host

* fix(claude): find custom chat history before managed-account resume

* test(claude): assign the complete custom account home

* feat(native-chat): offer account switching and hand-off at usage limits

* fix: track the provider in account-list reload effects

* fix(native-chat): target recovery actions at the chat host and transcript

* fix(native-chat): verify account recovery for each chat on its host

* refactor(native-chat): retain the existing image-support result

* fix(native-chat): withdraw account recovery after failed eligibility reads

* fix(native-chat): leave unavailable recovery facts absent

* Align Japanese usage-limit recovery copy with catalog convention

* Preserve complete chat context through usage-limit recovery

* Keep Continue callback focus optional

* Keep recovery fixtures and account effects type safe

* Keep chat recovery on native sources and native accounts

* Validate native recovery files after path admission

* Use the optional cursor shape in recovery fixture

* fix(native-chat): exclude source CLI family from limit handoff

* Resolve recovery context in the owning workspace directory

* Add the continue-at-usage-limit-reset setting and its chat row lines

* Continue chats automatically after usage limits reset

* Fix automatic continuation fairness, lifecycle and host settings

* fix: bind automatic continuation withdrawal to accepted actions

* fix: withdraw source auto continuation after handoff starts

* Read unopened chats with the saved-record reader for usage-limit continue

Unopened chats were read through the raw-row replay, which no longer sees
chats saved as keyed records, so a usage-limited chat that was not open
was never continued after its reset. Read them the way the rest of the app
reads a chat without opening it. Also use the shared visible-tab check,
keep the ordinary rewind result without a sequence as main does, and adapt
two tests to the current queued-message and saved-status behavior.

* Keep a usage-limited turn idle after any rewind restores it

Rewind completion read the resulting conversation through the raw-row
replay, which no longer sees chats saved as keyed records, and a forked
rewind wrote its completion before the new history's records. So a
limited turn that a rewind brought back was continued automatically
after its reset. The completion now reads the saved result the way the
app reopens a chat, and the forked rewind writes its completion after
the new history in the same transaction.

* Type the usage-limit auto-continue test mock without an assertion

* Fix type errors from main's settings, failure-wording and refusal changes

* Keep ordinary settings replies when the paired host changes mid-call, and list the cancel method in wire contracts

Settings reads and writes that don't carry the automatic-continue choice go
through the common runtime call again, so a reply that completes after the
paired host is removed still merges, as before this change. Only a write of
that choice stays pinned to the host it was made for. The structured method
count and the cross-version method manifest now include the cancel method.

* Keep a stopped turn's automatic continue withdrawn when its usage limit arrives later

A person could Stop a running Codex turn, have the turn then end with a
usage-limit failure, and still get an automatic "Continue where you left
off." after the reset, because Stop had nothing to cancel yet. The journal
write that first reveals a limited turn the latest personal Stop owns now
saves the same exact cancellation in that transaction, and a Stop accepted
just after the limit landed withdraws it too. Resume, deleting a queued card
and restarting keep it withdrawn; manual Continue and later turns are
unaffected.

* Bound the automatic-continue sweep and keep notice rows from re-rendering

The 10-second sweep now does nothing while the setting is off, republishes
only chats with a scheduled continuation, reads at most three unopened chats
per pass, and keeps going when one chat's saved history can't be read (that
chat is retried after the others instead of stopping every chat on the host).
Settings writes republish only when the switch changes. Working out the
usage-limit cut no longer indexes the whole conversation on every streamed
row. The chat's notice rows no longer re-render for status changes they
don't show. Adds operation-count and render-count tests for these bounds.

* Test that streamed journal commits after a Stop scan no history and build no command index

Drives real Codex rows through the host at 20 and 200 history rows: each streamed commit runs the Stop's commit hook and the status projection's cut reader with no newest-turn scan, no render and no full command index; the next turn end scans once and renders nothing.

* Leave a usage limit manual once its reset passed more than a day ago

Turning automatic continue on later no longer sends into chats whose limit reset days ago. Eligibility, which the row's summary, the sweep and the pre-send recheck all read, now requires the reset to be within the last 24 hours; older limits show the usual manual actions and are never continued unasked.

* Show only manual actions for a usage limit Orca can never continue

A limit more than a day past its reset is never continued, but its row still showed the setting link, inviting people to turn on a switch that could not help that chat. One shared check now decides whether a cut can ever be scheduled; the status summary and the sweep's eligibility both use it, so past the bound the row keeps only Continue Now, Hand Off and Add Account. A row already on screen when the day passes drops the line on the shared minute clock; the host alone decides sends.

* List every journal row kind in the Stop cut filter

The type-aware lint requires exhaustive switches; epoch, tombstone, submission and queue rows still cannot reveal a cut.

* Type the status-subscription mock instead of casting its handler

The changed-code casting gate rejects type assertions; the mock now carries the real subscription signature, so the recorded handler is typed.

* Open store-less conversations without the Stop withdrawal hook

Acquisition-only opens have no record store, so a person's Stop followed by a limited turn end made the journal commit throw and drop the turn end. Install the withdrawal only when a store exists; without one there is no continuation to withdraw. Also narrow the status summary before reading it and type the sweep test's send mock.
2026-11-02 01:52:02 -08:00
Brennan Benson c1641a8d7d Show the open Orchestration panel as a floating card (#37412)
* Show the open orchestration panel as a floating card

The open panel now floats in the closed tab's corner as a card as tall as
its rows. In chats it stops above the composer (the transcript frame
already ends there); in terminals it keeps the bottom quarter clear for
the CLI's prompt and recent output. Past that it scrolls inside.

* Keep the orchestration card's collapse button reachable in tiny panes

A terminal split can be 50px high, leaving the card no room under the 75%
limit, so its header and collapse button were clipped away. The card is
now never shorter than its header.

* Keep the orchestration card's collapse button inside narrow cards

In a narrow split the card is 20px narrower than the pane and its title
didn't truncate, so the collapse button was pushed past the card's edge.
The title now truncates and the header's side padding gives way before
the button, down to the 50px pane minimum.
2026-11-02 01:50:54 -08:00
Brennan Benson 10a623b910 Launch an agent with a first prompt from its setup panel (#36659)
* Launch an agent with a first prompt from its setup panel

The agent setup panel in the new-tab menu gets an optional prompt box above
its Launch buttons. It is the chat composer in a compact launch layout: one
line that grows to six, Attach as its only control, / listing the launch
workspace's skills and commands and @ finding its files. Enter launches the
panel's default way, either Launch button sends the prompt its own way, and
with nothing typed both launch exactly as before. The prompt rides the
existing launch prompt field and is kept in memory only until the launch.

* Preserve launch prompt input across submission and refusal

* Retain scoped composer submissions through launch ownership

* Keep launch prompt tests deterministic during collection and persistence checks

* Retire launch source drafts at committed qualified removals

* Retain workspace launch setup through ordinary rich drafts

* Preserve rich draft authority through accepted setup handoffs

* Keep setup prompt moves within current rich draft memory

* Create setup drafts on first input instead of on row render

Rendering an agent row in the launch menu or search no longer creates a
setup record. The row derives its scope from its workspace, host and
agent without touching session state; the record is created by the first
typed prompt, option change or pending attachment, matching main, which
kept only authored setups. Catalog applies, readoptions and renames now
visit authored setups only.

Option listeners use the existing per-scope draft listeners and subscribe
only while the setup popover is open. Also return the runtime-status
files to main, which only carried leftovers from a removed hook.

* Return group-delete draft revocation to main and repair launch tests

Deleting a project group no longer retires in-flight setup submissions
for its folders: folder keys are never derived again, so it changed
nothing users could see. The group mutation, its removal state and the
prompt-delivery type widening go back to main's content, with the test
that exercised the revocation.

Test fixtures catch up with the setup prompt composer: the TabBar window
stubs gain event listeners, the picker inventory's mock store gains agent
status, create-rejection handbacks expect inComposer, and the folder
removal test expects a same-ID survivor's chip to stay, as on main.

* Keep each search preset's setup options in its own slot

Opening a search result's setup no longer writes its preset over the
workspace's setup. As on main, each preset keeps its own options slot,
now inside the workspace/host/agent setup, keyed by what the search
parsed rather than by defaults; the plain row keeps its own slot. Only a
real change saves, into that entry's slot, and creates the setup then.
The typed prompt stays one per workspace, host and agent.

* Fix the moved agent profiles import and merge duplicate imports

Main moved the native chat agent profiles module under shared/native-chat,
so the setup prompt composer imports it from there. Files that imported
one module twice now import it once; nothing else changes.

* Fix the web typecheck for the setup prompt changes

The catalog continuity test no longer imports the main process's SSH
target reassignment, which pulled the whole main graph into the web
program; it builds the reassigned folder inline. Test fixtures and spies
now match current types, the edit-session tests pass a composer ref as
production does, and the setup panel again accepts callers that return
no launch answer. The pending-chip owner filter drops an unused name.
No shipped behavior changes.

* Show the setup prompt's skill and file lists above the setup panel

In the agent setup popover, the / and @ lists opened underneath the
panel, so they could not be seen or clicked. A list opened inside a
popover now takes the menu layer that selects and dropdowns already use
above popovers; an ordinary chat's lists keep their container and layer.

The prompt placeholder is translated in every locale, and folder draft
continuity takes the fetched catalog itself instead of reading its
folder list field.

* Fit the setup prompt box to a placeholder that wraps

With a longer translation, the empty setup prompt's placeholder wrapped
to a second line that the one-line box cut off. The empty launch prompt
now lets its placeholder's wrapped height count, so the box fits it;
English still fits one line, and an ordinary chat's box is unchanged.

* Type the submit test's pending sends as the boolean main now returns

* Show the dictation button in the agent setup prompt

* Update draft test handle for agent references
2026-11-02 01:27:02 -08:00
Neil 2541edc98e feat(settings): import Kitty configs through a shared terminal config import pipeline (#37375)
* feat(settings): import Kitty configs through a shared terminal config import pipeline

* fix(settings): harden Kitty include and value parsing

* fix(settings): match Kitty globs linearly, skip read-only system configs, report non-family font selectors

* refactor(settings): read current settings through a typed map when diffing imports

* style: format Ghostty importer

* fix(settings): type the import hook stub and let dialog primitives own their typography
2026-11-02 01:11:26 -08:00
Neil 36f17a04a7 plugins: Box layout container for components panels (catalog 4) (#37420)
- Box (ui.catalog 4, since 1.4.248): direction, gap/padding/paddingX/
  paddingY/margin on the gap scale, align, justify, wrap, grow, shrink,
  width/height/min/max (px up to 4096 or whole percents), columns,
  scroll, border (true or a tone), radius, background (theme surfaces or
  tone tints). Strict props: hex colours, CSS lengths and unknown props
  are dropped with a warning like other components.
- Renderer maps props to theme tokens through data attributes; sizes
  reach inline style only as validated px or percents.
- Typings, docs, skill references, gallery Layout tab; orca/testing
  finds Boxes and summarizes danger or warning Boxes.
2026-11-02 01:05:57 -08:00
Jinjing 81ec82b365 Rename Chat settings to Chat UI (#36613)
* Rename Chat settings section to Chat UI

* Localize Chat UI settings titles

* Update chat settings search fallback to Chat UI
2026-11-02 01:52:17 -07:00
Neil 3fa4a059d0 feat(settings): import Ghostty themes, including light/dark pairs, as per-mode terminal themes (#37368)
* feat(settings): import Ghostty themes, including light/dark pairs, as per-mode terminal themes

* fix(settings): keep Ghostty theme re-imports stable and explicit colors when a theme half is missing

* fix(settings): reuse identical built-in terminal themes and label Ghostty variants

* fix(settings): keep same-named Ghostty theme files apart, import theme divider colors, follow Ghostty lookup order for picked configs
2026-11-02 00:50:40 -08:00
Brennan Benson 3aa633d389 Mention an agent from the orchestration panel with one click (#34836)
* Add scoped terminal identity acquisition and preserve crew source wakes

* Share raw crew identity inputs through scoped production readers

* Exercise crew generation retirement through actual source owners

* Retire crew inputs on consumed ownership and visibility writes

* Use typed crew mutation and fixture access

* fix: use owned crew styles and committed render counters

* Repair crew fixture and RPC type contracts

* Align crew fixtures with pane and mention contracts

* Count crew consumer render attempts in the fixture

* Localize crew panel labels and details

* Align crew integration fixtures and RPC parameter contracts

* Keep mention contracts within their compiler boundaries

* Encapsulate terminal identity mutations and captured reader contracts

* Seed terminal identity fixtures through canonical mutations

* Complete crew panel English catalog entries

* Fix terminal identity fixture return type

* Cover terminal identity lifecycle schedules

* Align terminal fixtures with canonical identity sources

* Repair runtime fixture source contracts

* Use checked database fixtures for federation contracts

* Update crew source inventories and exit fixtures

* Preserve crew setup outcomes at existing subscription owners

* Match managed restore fixture to its nullable async return type

* Keep absent setup observations distinct from undefined failures

* Drive pending Crew questions from existing metadata

* Preserve nested pairing repair outcomes for shared callers

* Route attached workers to explicit local recipients

* Type Crew pending-question measurement receipts

* Match SSH repair fixture target absence to store contract

* Repair composer fixture and consolidate crew English catalog

* Add finite crew subscription boundary candidates

* Isolate crew portal in terminal file drop fixture

* test: use checked property access for crew owner assertions

* Consolidate web runtime auth type imports

* test: type crew API legacy arguments and pending results

* Bound cold terminal layout construction and finite pane acquisition

* test: use public runtime identity in pane acquisition fixture

* Follow image reference module relocation in mention serializer

* Avoid repeated searches in cold workspace layout loading

* Verify cold loader fault identity and hook claimant effects

* Revert "Route attached workers to explicit local recipients"

This reverts commit f1335d1c06.

Keep attached workers on the existing Run-home routing path for this change.

* Omit crew peer addresses outside the active home route

* Align crew disclosure and availability with shared UI

* Keep crew retries on the verified runtime session

* Bound cold layout retirement and recorded-key construction

* Verify original cold layout failure identity

* fix: preserve surviving layout split references

* test: use typed retirement instrumentation properties

* Keep crew overlay inside narrow panes

* Resume Crew streams on verified runtime sessions

* test: preserve pane and retirement fixture contracts with checked types

* Prepare Crew record admission and wake identity changes

* Derive Crew recipient actions from current target owners

* Keep nested Crew process facts within selected acquisition

* Defer Crew legacy facts to consumers and complete raw coverage on success

* Use deterministic time in Crew command fixtures

* Restore pane-local Crew menu dismissal focus

* Document schema-owned Dispatch row assertions

* test: align Crew authority fixtures with typed project boundaries

* Cover menu agent mentions through production insertion paths

* test: place Crew CLI integration in cross-surface project

* Type retained identity test meters with canonical source maps

* test: adapt mounted Crew fixture to Run unbind contract

* Document suffix Dispatch row boundary and preserve fixture unbinding

* Close crew menus when their terminal pane hides

* Remove unused structured activity component

* test: migrate Crew authority arguments and mailbox observations

* Forward native pane visibility to crew menus

* Keep rich draft offsets aligned with agent references

* Preserve later explicit pane selection after Mention delivery

* test: check the complete overlay focus host fixture

* test: use the DOM containment contract for menu focus

* Fix pointer dismissal enrollment and modal permission

* Remove shared menu primitive patches

* Reuse message avatars in the crew panel

* Focus the captured input when Mention is pressed

* Test the exact Mention all worker selection

* Derive Crew attention and actions from complete recipient authority

* test: repair Crew avatar store fixture and operation accounting

* Keep selected references structural during paste projection

* Fix Crew public-command fixture type contracts

* Align Crew fixtures with runtime reader and routing contracts

* Keep shared message avatar glyphs at their declared size

* fix: preserve existing native mention separators

* Narrow receiving fixture calls to unary RPC methods

* test: load crew Open sender before test execution

* test: consolidate pasted text value imports

* test: supply crew avatar panel mention contract

* Age pending question fixtures from every actual answer timestamp

* test: give mounted mention fixture a portable return type

* Complete Crew public-command workspace fixture result

* Test delegated helper follow-up through Crew advertised address

* Qualify Crew follow-up addresses through shared command admission

* Complete finite follow-up authority and lifetime evidence

* Assert exact remote authority acquisition error identity

* Consolidate Crew SQL test fixture imports

* Trim Crew panel tests to the high-impact set

Keep one mounted test per panel flow, the review-found regressions (avatar glyph size and attribution, stable labels, unavailable sending, hidden-pane menus, navigation remedies), the real producer-to-hook contract, cross-version refusal and recovery, and one N vs 10N contract per scaling piece. Remove permutation matrices, focus-timing proofs, and the duplicated web API and attempt suites.

* Trim Crew Mention tests to the high-impact set

Keep the native and terminal Mention flows, the review-found regressions (send and Goal serialization, label collisions, offsets and handback, Mention-all membership, press-time focus, late write responses, the native double space), the provider delivery contract, and the serializer N vs 10N bound. Remove menu and boundary permutation matrices, panel duplicates, recall and paste cases covered elsewhere, and the retained-group selection fixture. Panel-test cuts mirror the lower PR's so the stack merges cleanly.

* Trim Crew read-model tests to the high-impact set

Keep the real CLI/RPC/database command paths, one regression per review-found bug, the cross-version contracts and one N vs 10N operation contract per scaling piece. Drop permutation matrices, equivalence oracles, near-duplicate scenarios and diagnostic output, and return the SSH, managed-server and WSL test files to main, since their production changes were reverted earlier in this PR.

* Drop diagnostic output and a duplicate error case from Crew tests

Remove two leftover console.log diagnostics, an unused 2x2 sample matrix and unused return fields in the follow-up cost contract, and the subscription AbortError serialization case that the subscription identity and preload tests already cover.

* Pass the recorded-leaf reader in main's check-details loader test

* Build the approved orchestration panel design

Closed tab: panel icon, lineage icon with the worker count, then agents
grouped by status (needs you, working, idle, failed) with the sidebar's
status icon, up to three overlapping agent icons and +n. Rows are one
card with the task, the latest message or question, the relative time
and Details, Open, More. Rows sort by latest message. The open panel
reaches the pane top under the title strip. No user-visible 'crew'
text; counts use plurals. One store subscription resolves every row's
live sender state so the tab and the rows agree.

* Keep pane title buttons above the orchestration panel; tick row times

The open panel now sits just below the pane title strip in stacking
order and starts at the pane top in every host, so the strip's buttons
draw over its top band and no chat or terminal text shows above it. An
open panel lifts its pane's drag strip above it. Row times re-render on
the sidebar's shared 30s clock. Each status group keeps one fixed icon,
and the panel's needs-you count has its own plural.

* Move the orchestration row into its own file

* List every status case in the orchestration icon switches

* Name the orchestration row 'Mention <agent>:' while keeping its status, task and message

* Use the outline xs Button as is for Mention all

* Subscribe the memoized orchestration row to language changes; type the listener count

* Fit the orchestration tab and avatar stack to main's Button and key lint rules

* Ship the orchestration panel's plural counts in the runtime English catalog

* Subscribe the memoized crew row to language changes; read the nullable listener count

* Ship the orchestration panel's plural labels in the boot catalog

* End the chat's orchestration panel above the composer

The panel overlaid the whole chat body, so with it open the composer's
send button sat underneath it. The frame now wraps only the transcript;
the queued drafts, prompt cards and composer stay where main puts them.

* Skip escalations when choosing a crew row's latest message

Orca writes its failure notices (a worker stopped without reporting, a
chat agent error, a terminal exit) as the worker's own escalation, with
terminal, task and dispatch IDs and CLI syntax meant for the coordinator
agent. The panel showed that text as the row's second line. Only the
panel reads this query, so escalations are skipped there and the row
shows the agent's last real message. An agent's own Blocked escalation
is skipped too; it still reaches the coordinator's inbox.

* Point Mention's tests at the modules main moved

Main moved the composer command, send mutation and Claude dispatch
content modules; two of this PR's test files still imported the old
paths and failed to load. Also drop a mock of a module main removed.

* Say why a crew row's agent can't be opened

Opening a row whose agent is gone showed "This agent is no longer
available." Use the existing reasons instead: the chat is no longer on
this host, or the terminal has exited.

* End the panel above the composer in terminal-hosted chats too

A terminal's chat view still mounted the orchestration panel over the
whole chat, so it covered that view's composer and send button. Both
chat hosts now wrap their transcript in the same frame, which takes the
panel's props.

* Show only an agent's own words as a crew row's latest message

Besides failure notices, the latest line could pick up an empty setup
receipt (a blank line that also moved the row) or a lifecycle message
Orca rewrote to "Orca rejected this worker_done: ...". The panel's
query now admits only conversational types with a body and without the
lifecycle rejection marker, before choosing each peer's latest.

* Keep worker launch stages out of crew rows and Details

A row with no message fell back to the worker's internal launch stage
("input accepted", "worker report queued") as its second line, and
Details repeated it as Progress. The row now has no second line until
the agent says something, and Details drops Progress; the status icon
already shows the state.

* Fit both chat hosts under the line limit after the frame merge

Name each host's existing Mention availability once and pass it in the
frame's one-line crew props.

* Mention each agent once per chat draft

Mention all after a row Mention added a second chip for the same agent.
Inserting references now skips agents already in the draft or repeated
in the list; a repeat row click just focuses the composer. Terminal
Mention types text and is unchanged.

* Test a row Mention followed by Mention all

The QA sequence is two separate inserts; cover the draft scan that keeps
the first agent from being added again.

* Give the recipient-authority test's history message a body

The panel no longer admits empty-body messages as a row's latest; the
test's history message now carries the words a peer would send.

* Clip the chat's orchestration panel to its transcript

In a short split or under a tall composer, the transcript can be shorter
than the panel's header, which then painted over the composer. The chat
frame now clips the panel to the transcript; terminals are unchanged.

* Check a terminal's readiness when Mention is pressed

The panel read the terminal's connection once while rendering. A
restored pane connects later without a re-render, so its rows and
Mention all stayed disabled. Mention is now available whenever the pane
has a terminal, and the pane and connection are captured and checked
when the user presses it.

* Keep a row's status at full strength when it can't be mentioned

A row that couldn't be mentioned dimmed everything on it, including
another agent's "Waiting for you" line. Its content now stays as is;
only the hover highlight and pointer cursor go away.

* Translate the crew row Open failure toasts

The crew's Open failures were English literals. They now go through
translation, and a gone or outdated chat uses main's existing texts.

* Translate the crew row Open fallback for agents without a target

* Put the Orchestration panel behind an experimental setting, default off

Settings > Experimental > Orchestration panel (experimentalOrchestrationPanel).
Off mounts nothing: the chat frame, the terminal-hosted chat's identity lookup
and the terminal pane portals all gate where they mount, and toggling applies
live without remounting the transcript.

* Give the terminal-hosted chat's panel its own module

* Leave the setting-off path exactly as on main

The message card's avatar and its single-sender hook are back to main's code;
the panel keeps its own list hook. The panel's code now loads only when it
first mounts, behind the setting.

* Leave /goal and ordinary sends exactly as on main

A typed multi-line /goal is prose again, as on main; only Mention's own
routing lines after a one-line /goal join its objective. A draft with no
agent reference skips the reference serializer, so its send text is projected
once, as before. The routing line format now lives with the other reference
formats.

* Keep main's abort reason and send-failure handling for every web subscription

* Build the panel tests' settings from defaults instead of a cast

* Load the panel with plain lazy so a failed load never retries or reloads the app

* Keep main's /goal parser and put a goal's Mention notes on its one line

The shared command parser is main's code again, so any typed or pasted text
parses as before. A typed /goal or Goal-mode objective with mentions carries
its routing notes on the same line instead.

* Let a failed panel load try again the next time the panel mounts

* Type the queued-edit test's pending send as main's boolean result

* Keep a mention's routing notes in Goal mode on hosts without goals

There /goal goes to the agent as a message, so its notes keep their own lines,
as a typed /goal there already does. A draft with no mention sends main's text.

* Give the lazy panel test the Mention props this branch's panel requires
2026-11-02 00:41:40 -08:00
Rayyan34andNeil e1ff15ee91 feat(settings): preview each font in its own typeface in font pickers (#33254)
* feat(settings): preview each font in its own typeface in font pickers

* perf(settings): skip offscreen font rows so opening the picker loads only visible fonts

* fix(settings): keep symbol font names readable in font pickers

* fix(settings): size skipped font rows by their content box

---------

Co-authored-by: Neil <neil@stably.ai>
2026-11-02 00:31:59 -08:00
Neil adb2d2d2cd feat(settings): delete imported terminal themes from the theme picker (#37356)
* feat(settings): delete imported terminal themes from the theme picker

* fix(settings): theme delete reads latest settings, undo keeps later choices, focus stays in picker

* fix(settings): serialize theme deletes and keep later edits on undo

* fix(settings): theme delete button visibility on a wrapper, not a Button restyle
2026-11-02 00:31:45 -08:00
Brennan Benson c7195a8d50 Show who each agent works with in a panel on its chat or terminal (#34891)
* Nest chat-UI orchestration workers under the agent that started them

Main's lineage projection only walked terminal panes, so workers running
in the chat UI never got a parent link and listed flat in the sidebar.
It now also projects chat workers, keyed by their visible chat row, and
resolves a chat creator or coordinator to that chat's visible row
instead of its handle or private mailbox pane key.

* Fix public worker lineage across assignment and row identities

* Complete terminal lineage provenance and bound active session selection

* Repair lineage test runtime boundaries and SQLite counters

* Provide read-only crew snapshots for each agent

* Batch public lineage verification after exact recency selection

* Derive crew relations once per meaningful host change

* Remove package manager lockfile churn from hook

* Show each pane’s agent crew with open and copy actions

* Use checked runtime values in lineage integration tests

* Preserve host-aware crew navigation remedies

* Document the trusted Dispatch SQL row boundary

* Keep lineage integration imports within their test programs

* Load native lineage fixtures before test execution

* test: complete lineage inputs in runtime and sidebar fixtures

* test: seed benchmark facts from active dispatches

* test: replace partial orchestration DB casts with typed fixtures

* test: complete stale-leaf mailbox fixture session input

* Derive durable crew parents from retained assignment proof

* fix(test): render worker lineage fixture with production list

* fix: preserve crew pane controls and summary identity

* refactor: extract crew row details presentation

* Add scoped terminal identity acquisition and preserve crew source wakes

* Share raw crew identity inputs through scoped production readers

* Exercise crew generation retirement through actual source owners

* Retire crew inputs on consumed ownership and visibility writes

* Use typed crew mutation and fixture access

* fix: use owned crew styles and committed render counters

* Repair crew fixture and RPC type contracts

* Count crew consumer render attempts in the fixture

* Localize crew panel labels and details

* Align crew integration fixtures and RPC parameter contracts

* Encapsulate terminal identity mutations and captured reader contracts

* Seed terminal identity fixtures through canonical mutations

* Complete crew panel English catalog entries

* Fix terminal identity fixture return type

* Cover terminal identity lifecycle schedules

* Align terminal fixtures with canonical identity sources

* Repair runtime fixture source contracts

* Use checked database fixtures for federation contracts

* Update crew source inventories and exit fixtures

* Preserve crew setup outcomes at existing subscription owners

* Match managed restore fixture to its nullable async return type

* Keep absent setup observations distinct from undefined failures

* Drive pending Crew questions from existing metadata

* Preserve nested pairing repair outcomes for shared callers

* Route attached workers to explicit local recipients

* Type Crew pending-question measurement receipts

* Match SSH repair fixture target absence to store contract

* Add finite crew subscription boundary candidates

* Isolate crew portal in terminal file drop fixture

* test: use checked property access for crew owner assertions

* Consolidate web runtime auth type imports

* test: type crew API legacy arguments and pending results

* Bound cold terminal layout construction and finite pane acquisition

* test: use public runtime identity in pane acquisition fixture

* Avoid repeated searches in cold workspace layout loading

* Verify cold loader fault identity and hook claimant effects

* Revert "Route attached workers to explicit local recipients"

This reverts commit f1335d1c06.

Keep attached workers on the existing Run-home routing path for this change.

* Omit crew peer addresses outside the active home route

* Align crew disclosure and availability with shared UI

* Keep crew retries on the verified runtime session

* Bound cold layout retirement and recorded-key construction

* Verify original cold layout failure identity

* fix: preserve surviving layout split references

* test: use typed retirement instrumentation properties

* Keep crew overlay inside narrow panes

* Resume Crew streams on verified runtime sessions

* test: preserve pane and retirement fixture contracts with checked types

* Prepare Crew record admission and wake identity changes

* Derive Crew recipient actions from current target owners

* Keep nested Crew process facts within selected acquisition

* Defer Crew legacy facts to consumers and complete raw coverage on success

* Use deterministic time in Crew command fixtures

* Restore pane-local Crew menu dismissal focus

* Document schema-owned Dispatch row assertions

* test: align Crew authority fixtures with typed project boundaries

* test: place Crew CLI integration in cross-surface project

* Type retained identity test meters with canonical source maps

* test: adapt mounted Crew fixture to Run unbind contract

* Document suffix Dispatch row boundary and preserve fixture unbinding

* Close crew menus when their terminal pane hides

* Remove unused structured activity component

* test: migrate Crew authority arguments and mailbox observations

* Forward native pane visibility to crew menus

* Fix pointer dismissal enrollment and modal permission

* Remove shared menu primitive patches

* Reuse message avatars in the crew panel

* Derive Crew attention and actions from complete recipient authority

* test: repair Crew avatar store fixture and operation accounting

* Fix Crew public-command fixture type contracts

* Align Crew fixtures with runtime reader and routing contracts

* Keep shared message avatar glyphs at their declared size

* Narrow receiving fixture calls to unary RPC methods

* Age pending question fixtures from every actual answer timestamp

* Complete Crew public-command workspace fixture result

* Test delegated helper follow-up through Crew advertised address

* Qualify Crew follow-up addresses through shared command admission

* Complete finite follow-up authority and lifetime evidence

* Assert exact remote authority acquisition error identity

* Consolidate Crew SQL test fixture imports

* Trim Crew panel tests to the high-impact set

Keep one mounted test per panel flow, the review-found regressions (avatar glyph size and attribution, stable labels, unavailable sending, hidden-pane menus, navigation remedies), the real producer-to-hook contract, cross-version refusal and recovery, and one N vs 10N contract per scaling piece. Remove permutation matrices, focus-timing proofs, and the duplicated web API and attempt suites.

* Trim Crew read-model tests to the high-impact set

Keep the real CLI/RPC/database command paths, one regression per review-found bug, the cross-version contracts and one N vs 10N operation contract per scaling piece. Drop permutation matrices, equivalence oracles, near-duplicate scenarios and diagnostic output, and return the SSH, managed-server and WSL test files to main, since their production changes were reverted earlier in this PR.

* Drop diagnostic output and a duplicate error case from Crew tests

Remove two leftover console.log diagnostics, an unused 2x2 sample matrix and unused return fields in the follow-up cost contract, and the subscription AbortError serialization case that the subscription identity and preload tests already cover.

* Pass the recorded-leaf reader in main's check-details loader test

* Build the approved orchestration panel design

Closed tab: panel icon, lineage icon with the worker count, then agents
grouped by status (needs you, working, idle, failed) with the sidebar's
status icon, up to three overlapping agent icons and +n. Rows are one
card with the task, the latest message or question, the relative time
and Details, Open, More. Rows sort by latest message. The open panel
reaches the pane top under the title strip. No user-visible 'crew'
text; counts use plurals. One store subscription resolves every row's
live sender state so the tab and the rows agree.

* Keep pane title buttons above the orchestration panel; tick row times

The open panel now sits just below the pane title strip in stacking
order and starts at the pane top in every host, so the strip's buttons
draw over its top band and no chat or terminal text shows above it. An
open panel lifts its pane's drag strip above it. Row times re-render on
the sidebar's shared 30s clock. Each status group keeps one fixed icon,
and the panel's needs-you count has its own plural.

* Move the orchestration row into its own file

* List every status case in the orchestration icon switches

* Fit the orchestration tab and avatar stack to main's Button and key lint rules

* Subscribe the memoized crew row to language changes; read the nullable listener count

* Ship the orchestration panel's plural labels in the boot catalog

* End the chat's orchestration panel above the composer

The panel overlaid the whole chat body, so with it open the composer's
send button sat underneath it. The frame now wraps only the transcript;
the queued drafts, prompt cards and composer stay where main puts them.

* Skip escalations when choosing a crew row's latest message

Orca writes its failure notices (a worker stopped without reporting, a
chat agent error, a terminal exit) as the worker's own escalation, with
terminal, task and dispatch IDs and CLI syntax meant for the coordinator
agent. The panel showed that text as the row's second line. Only the
panel reads this query, so escalations are skipped there and the row
shows the agent's last real message. An agent's own Blocked escalation
is skipped too; it still reaches the coordinator's inbox.

* Say why a crew row's agent can't be opened

Opening a row whose agent is gone showed "This agent is no longer
available." Use the existing reasons instead: the chat is no longer on
this host, or the terminal has exited.

* End the panel above the composer in terminal-hosted chats too

A terminal's chat view still mounted the orchestration panel over the
whole chat, so it covered that view's composer and send button. Both
chat hosts now wrap their transcript in the same frame, which takes the
panel's props.

* Show only an agent's own words as a crew row's latest message

Besides failure notices, the latest line could pick up an empty setup
receipt (a blank line that also moved the row) or a lifecycle message
Orca rewrote to "Orca rejected this worker_done: ...". The panel's
query now admits only conversational types with a body and without the
lifecycle rejection marker, before choosing each peer's latest.

* Keep worker launch stages out of crew rows and Details

A row with no message fell back to the worker's internal launch stage
("input accepted", "worker report queued") as its second line, and
Details repeated it as Progress. The row now has no second line until
the agent says something, and Details drops Progress; the status icon
already shows the state.

* Give the recipient-authority test's history message a body

The panel no longer admits empty-body messages as a row's latest; the
test's history message now carries the words a peer would send.

* Clip the chat's orchestration panel to its transcript

In a short split or under a tall composer, the transcript can be shorter
than the panel's header, which then painted over the composer. The chat
frame now clips the panel to the transcript; terminals are unchanged.

* Translate the crew row Open failure toasts

The crew's Open failures were English literals. They now go through
translation, and a gone or outdated chat uses main's existing texts.

* Translate the crew row Open fallback for agents without a target

* Put the Orchestration panel behind an experimental setting, default off

Settings > Experimental > Orchestration panel (experimentalOrchestrationPanel).
Off mounts nothing: the chat frame, the terminal-hosted chat's identity lookup
and the terminal pane portals all gate where they mount, and toggling applies
live without remounting the transcript.

* Give the terminal-hosted chat's panel its own module

* Leave the setting-off path exactly as on main

The message card's avatar and its single-sender hook are back to main's code;
the panel keeps its own list hook. The panel's code now loads only when it
first mounts, behind the setting.

* Keep main's abort reason and send-failure handling for every web subscription

* Build the panel tests' settings from defaults instead of a cast

* Load the panel with plain lazy so a failed load never retries or reloads the app

* Let a failed panel load try again the next time the panel mounts
2026-11-02 00:21:42 -08:00
Neil 9d22b026de feat(settings): let the Ghostty import read a config file you pick (#37353)
* feat(settings): let the Ghostty import read a config file you pick

* fix(settings): guard Ghostty file-pick races and non-regular files
2026-11-02 00:12:22 -08:00
Neil 522c7b6b8c fix(fonts): list Windows fonts through Chromium instead of PowerShell and surface failures (#37369)
* fix(fonts): enumerate Windows fonts natively instead of through PowerShell

Read the registered font files' name/fvar/STAT tables so a Group Policy
block on PowerShell no longer collapses the picker to five fonts, and say
so in the picker when the OS list is unreadable.

* fix(fonts): harden sfnt parsing and Windows font file discovery

* fix(fonts): follow STAT naming rules and bound Windows font reads

* test(fonts): type platform timeout cases without assertions

* refactor(fonts): list Windows fonts with Chromium's queryLocalFonts instead of a custom sfnt parser

* fix(fonts): scope the local-fonts grant to the main window and keep the web client quiet
2026-11-02 00:11:32 -08:00
Neilandmmarabel 72099885dd fix(appearance): changed divider colors also paint workspace splits (#37342)
* fix(appearance): changed divider colors also paint tab-group splits

Co-authored-by: mmarabel <mmarabel@users.noreply.github.com>

* fix(appearance): follow the terminal divider slot and keep the value's case

---------

Co-authored-by: mmarabel <mmarabel@users.noreply.github.com>
2026-11-02 00:11:26 -08:00
Neil e7575e5bed fix(theme): ignored files in the explorer meet 4.5:1 in the built-in themes (#37355) 2026-11-02 00:11:21 -08:00
ab0e81d341 fix(repo-icon): round project image icons on desktop to match mobile (#37383)
* fix(repo-icon): round project image icons on desktop to match mobile

Mobile rounds project image icons with a 4px radius, but desktop draws them
with square corners, so the same avatar looks different across clients and
sits awkwardly beside the rounded sidebar controls.

Apply the same 4px radius to the image in RepoIconGlyph so every desktop
surface picks it up. Emoji and lucide icons are unchanged.

Covered by a repo-icon test that failed before the change.

* test: drop repo-icon radius test

---------

Co-authored-by: Rongzheng Liu <tianlrz@users.noreply.github.com>
Co-authored-by: Neil <neil@stably.ai>
2026-11-01 23:40:46 -08:00
Neil f8ce00682c Say why to move projects in the WSL move dialog (#37390)
* WSL move dialog: one line on why to move, and the way back

* Capitalise Git in the WSL move why-line
2026-11-01 23:40:03 -08:00
Neil f358f420af fix(wsl): offer the existing host when adding a folder from a distro that already runs as one (#37377)
* fix(wsl): offer the existing host when adding a folder from a distro that already runs as one

* fix(wsl): translate the existing-host offer, let a later drop win, keep the offer when the host fails to start

- Translate existingTitle/existingWhy/existingAccept into every locale.
- A drop onto the open dialog after "Add on host" now prefills the dropped path.
- A failed host start keeps the offer so the user can retry or add on this computer.
- Tests run the real saved-host read (flag off gives the run-as-host offer) and the
  offer-to-prefill wiring.
2026-11-01 23:38:05 -08:00
NeilandClaude 2bbf73adc4 fix(wsl-move): land on the workspace view after a move's window reload (#37376)
* fix(wsl-move): land on the workspace view after a move's window reload

A move or "Use on this computer again" reloads the window from Settings.
Settings cannot restore which page was open, so the reload opened General,
and the saved view kept reopening Settings on later launches. Main now
switches the saved view from Settings to the workspace view right before
that reload.

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

* fix(wsl-move): leave Settings even when the window is gone at reload

The landing view now comes from the write hold whenever a reload is owed,
so a window closed before the reload still relaunches on the workspace view.

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

* fix(wsl-move): keep the reload going if the landing view cannot be saved

Picking the landing view is now best-effort, so a failing store write no
longer strands the write hold or skips the reload. Adds a wiring test that
fails if the landing is not registered.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-01 23:37:51 -08:00
Neil 3a00c74dbd test: remove the redraw wall-time race and shrink oversized scaling populations (#37385)
Deletes terminal-tail-redraw-wall-time: its result equality duplicates the
randomized equivalence suite and its complexity claim is pinned by the
join-counting scaling suite; it only added a 3x wall-clock race.

Shrinks scaling suites whose bounds are exact or log-bounded formulas in n to
the smallest population that still separates linear from superlinear work, and
pairs a worktree-poll test's scans so it no longer waits out the 5 s scan timeout.
2026-11-01 23:22:14 -08:00
Brennan BensonandClaude Opus 5.5 f5a36554ff fix(plugins): keep the plugin consent fingerprint Hermes-compatible so main's Mobile checks pass (#37370)
* fix(plugins): build the consent fingerprint without toSorted so the phone bundle passes Hermes checks

Main's Mobile verify has failed since #37316 because the plugin consent fingerprint (bundled into the phone app via src/shared) used Array.prototype.toSorted, which Hermes lacks. flatMap already returns a fresh array, so sorting it in place keeps the same result.

* test(plugins): pin the consent fingerprint's command-order independence

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-01 23:20:09 -08:00
Neil d8a66e41c9 fix(wsl): name the stopped distro, not its raw hold code, wherever a held terminal is shown (#37380)
The terminal error banner and a paired host's held pane showed
terminal_held_wsl_distro_*:<distro> as is; the banner now swaps either
the code (older hosts) or the English sentence (newer hosts) for the
localized copy, and drops the issue link for it. A held start that
arrives as the sentence now gets the Start card too. The CLI names the
distro for an older server's raw hold code and for an unavailable WSL
folder. The banner's footer reports the shell whose spawn failed
(wsl.exe, say) instead of the client's default shell.
2026-11-01 23:17:46 -08:00
Neil 4f0aaccc5f fix(repos): a catalog answer sent before an add no longer drops the project that add made (#37384) 2026-11-01 23:16:37 -08:00
Jinjing e6a9ce50e2 Preserve bounded tool evidence in chat handoffs (#36842)
* Preserve bounded tool evidence in chat handoffs

- Keep recent conversation and useful tool failure context without exporting huge outputs
- Safely summarize tool inputs and retain transcript order

* Preserve tool call IDs and block order in handoffs

* Preserve cross-message tool results in handoff context

* Prioritize latest tool results in handoff context

* Preserve bounded saved tool failures in handoff context

* Avoid reflective tool preview reads
2026-11-02 00:03:46 -07:00
Brennan Benson 4343dc212a fix(native-chat): report missing saved conversations once (#37189)
* fix(native-chat): report missing saved conversations once

* fix(native-chat): keep failures of answered Claude sends and translate the missing-conversation row

A Claude result settles its own send before the journal sees it, so a
failed send with no echo yet lost its owner and its failure row. The
result now carries the send it answered. Desktop and phone rows also
show the missing saved conversation sentence in the reader's language.

* fix(native-chat): keep failures of Claude results that name a user message

A root failure result that names a user message answered accepted input, so it keeps its row even when that send's waiter was retired, in doubt or ambiguously written. Only a result with no turn, no started send and no named user message (the pre-init missing-resume capture) is left to the host's final startup row. This replaces the per-frame settlement carry, so the acquisition and sign-in tests return to main.

Also ship the new missing-conversation sentence in the runtime English catalog.

* fix(native-chat): leave only a starting Claude session's failure to the startup row

A Claude failure result with no turn now writes no row only while its own
session is still opening (initialize and resume catch-up). Once open
succeeds, every failure result is reported as before, whatever send
evidence it carries, so per-send ownership checks are removed.

* fix(native-chat): fail a starting Claude session with the startup failure it reports

A turnless failure result that names no user input or resumed turn, arriving
while its own acquisition is still starting, now fails that acquisition's open
(initialize and resume catch-up) with Claude's own diagnostic; only then is its
provider row left to the host's final startup row. Results naming input, and
every result once open succeeds, keep main's reporting. The missing-conversation
classifier is shared by stderr and the result's errors, so the typed refusal
ends in one attempt whichever arrives first; other reported startup failures
stay retryable through the existing provider-request error.

* fix(native-chat): keep a Claude startup result's row once another failure ended the start

A Claude startup failure result was still taken by its acquisition's startup
outcome after initialize, a transport fault or an unexpected exit had already
failed that start, so its diagnostic was neither shown nor kept in the final
failure. The outcome now declines once the open fails by another route or the
exit is observed (synchronously, before buffered frames drain), so such a
result keeps its row as on main. It still takes a repeated result it already
accepted, and a result whose refusal the ending exit already carries; a Stop
still owns its start.

* fix(native-chat): report a Claude start's first ending cause from its open

The startup outcome now records the first cause that ends a start: an
accepted startup result, the raced initialize or catch-up rejecting, a
transport fault or unexpected exit, or any other open failure. That cause
rejects the pending race, open() refuses success after it, and the open
rejects with it, so a hidden result is always the open's error and any
other result keeps its row.

* test(native-chat): check the startup rejection with a type guard instead of an assertion
2026-11-01 22:46:57 -08:00
Neil 0fad93e2ad test: stop unit tests from waiting out real 5 s fallbacks; fix two flaky tests (#37362)
The ConPTY prelude mock delivered its DA1 query on a microtask, which reached only
the physical owner's early onData listener (added in #36422); the startup watch
subscribes after an await, never saw it, and every Windows-path spawn waited out
CONPTY_STARTUP_DECISION_LIMIT_MS (5 s). Deliver it on a macrotask like real output.

Also give two fixtures the readiness their production peers provide, and fix the
counter-file race in structured-agent-shell-environment and the async sign-in
marker race in claude-status-sign-in.
2026-11-01 22:44:16 -08:00
Neil cb031c4517 fix(plugins): merge disk writes into a custom editor's unsaved edits (#37343)
* fix(plugins): merge disk writes into a custom editor's unsaved edits

A write to the file on disk while a custom editor tab had unsaved edits
never reached the editor: the buffer kept the edits, Orca showed its
Reload/Overwrite banner, and the session's merge never ran. Now a frame
whose document session has merge announces it (editor.merges), and Orca
sends it the new disk text with the text the edits started from
(editor.document with ancestor). The session merges, posts the result,
and the tab stays unsaved with it; the banner is skipped. Without merge
the banner decides as before.

* test(editor): an explicit save under the changed-on-disk banner keeps the edits

* fix(plugins): make the outside merge exact, and narrow it to where it is

- The host settles a merge only on the session's edit made against the
  merge's own document version, and always commits that result to the
  buffer (even when it equals the disk text); silence past the 1 s flush
  deadline, a remount or a throwing merge leave the banner and the
  suspended autosave in place.
- Orca stamps exactly the disk snapshot the acknowledged merge used and
  records it as the next ancestor; a write that landed meanwhile puts the
  conflict back for its own merge.
- The ancestor is the tab's disk text recorded while clean and advanced on
  acknowledged merges, and must match the tab's disk baseline.
- Only a local file in one merging editor view, with no other tab on its
  buffer, takes this path; anything else gets the banner.
- Frame events keep reaching their handlers after the merge capability.

* fix(plugins): move nothing on a failed disk merge; advance the saved text on success

A merge that throws now leaves the session's document, baseline and
version untouched, so the user's next edit goes out against the old
version: Orca refuses it and keeps the banner instead of taking it as the
merge's acknowledgement. After an acknowledged merge the tab's saved text
moves to the disk text it used, so typing back to the old ancestor no
longer looks clean.

* chore(plugins): regenerate the testing bundle on main
2026-11-02 06:35:01 +00:00
Brennan Benson d712485fe2 Restore main unit checks for plugin routing and prompt receipts (#37345)
* test: restore plugin routing and prompt receipt checks on main

* test: flush pending receipts before releasing the prompt write

* test: route screenshot CLI sources to the journeys that run them
2026-11-01 22:34:12 -08:00
NeilandClaude 5846caf2ba plugins: editor.save.before hook (format on save, or refuse the save) (#37347)
* plugins: editor.save.before hook (format on save, or refuse the save)

Explicit saves of text files from an editor tab run plugins' editor.save.before
in main before the write (local, SSH, WSL and folder workspaces all save through
that one renderer path). A plugin can return changed text or deny with a reason,
shown in the save error. The buffer takes the hook's text only if it is unchanged
since the hook started; edits made meanwhile stay dirty. Autosave, restart saves
and bytes documents are not hooked, and with no live plugin listing the hook the
save path adds no await.

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

* test(plugins): editor.save.before text reaches the visible Monaco model

The hook writes its text into the tab's draft, which reaches the model through
the same content-sync bridge as Reload from disk. A model-level test covers the
formatted text showing, the next keystroke editing it, and edits typed during the
hook staying in the model.

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

* plugins: editor.save.before review fixes: flush held typing, update the surviving view, keep the denial

- After the hook answers, pending view text (rich Markdown's serialize timer) is
  flushed before deciding whether the buffer still holds the hook's input.
- The hook's text goes to whichever view of the buffer record is still open, so
  closing the saving view keeps a sibling view in step with disk.
- The save-request bridge passes Errors through whole, so the toast shows the
  plugin and its reason instead of a generic failure.

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

* chore(plugins): regenerate after rebasing the save hook on main

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 06:19:50 +00:00
Brennan Benson 8ddc35b8e9 test: import the conversation view from its new location (#37346)
#37191 added an import of the old path after #37289 moved the module, breaking
main's typecheck for every PR.
2026-11-01 22:10:22 -08:00
Neil 60e25bde45 feat(plugins): make the editor template the rich-editor recipe (#37349)
orca plugin create --template editor wrote an inline-script HTML editor
whose extension came from the folder name squashed to 12 letters. It now
writes the recipe: editor/main.ts (the view), editor/sync.ts (the
document session with a stand-in text merge), editor/sync.test.ts (a
mockEditorHost test of an outside write merged during a save), a
tsconfig on the generated typings, frame isolated, engines.orca
>=1.4.248, and extension .<id>. It passes plugin check and plugin test
as generated.
2026-11-01 22:04:31 -08:00
Neil 999160b3db feat(plugins): commands[].replaces lets a mod take over a built-in action (#37316)
* plugins: commands[].replaces lets a worker command take over a built-in action

A worker command with replaces: <action> (the declarative action list,
engines >=1.4.248, needs main) runs in place of that built-in from its
shortcut, plugin aliases and the sidebar menus; a failed or silent (2 s)
worker falls back to Orca's own. The install screen names each replacement,
the plugin page has a per-action switch (settings.pluginReplacementsOff), and
when two plugins replace one action the one installed first wins and the
other's log says so. Update review counts replaces as new access.

* fix(plugins): narrow replaced action ids before looking up their titles

* plugins: harden command replaces after review

- Consent includes the replaced actions, so adding replaces to a dev folder
  needs a new approval; CLI approval and update review name each takeover.
- Shortcuts main intercepts (Tasks, Workspace Board, history), search with a
  selection and floating maximize now go through the replacement too.
- A worker that only starts after the 2 s fallback no longer runs the
  command as well: main refuses to start it past the deadline.
- A workspace-only command does not replace an action without a workspace.
- An update keeps the plugin's first install time, so it keeps its takeover.
- Drop the commands.run promise until Orca offers it.

* plugins: commands.run always runs the built-in, never a replacement

A5b's commands.run dispatches with the 'plugin-host' source; the app
dispatcher now builds handlers that run Orca's own action for it, so a
plugin that replaces an action and calls commands.run cannot loop. Docs and
schema describe wrapping the built-in with commands.run; regenerated.
2026-11-01 21:59:27 -08:00
Neil 3e52963a9a docs(plugins): fix custom-editor authoring papercuts from dogfood (#37337)
- shot --act: say edits only dirty the tab; end with Cmd/Ctrl+S to save
- manifest: compound suffixes like .sketch.json open by default
- cli.md: list plugin check's exit codes, including plugin_check_failed
- workflow: how to run and stop the dev app from a source checkout
- plugin create --help: real descriptions for --template/--publisher/--id/--name
- recipes: declaration file for vendored ESM libraries
2026-11-01 21:48:46 -08:00
NeilandClaude 2fb3a0975e feat(plugins): workers can open files and run built-in actions (#37323)
* feat(plugins): add editor.open and commands.run for full-access workers

Both ride the existing plugin view request channel (the one plugin open and
plugin shot use) to the one main window's renderer; headless serve and a
missing window answer unavailable. editor.open takes a path that stays
inside the workspace (Git worktrees and folders) and opens it as a tab
without switching what the person sees. commands.run takes only the built-in
contributes.commands action list and dispatches Orca's own handler, never a
plugin replacement. Both need workspace:write.

workspace.list now also lists project-group folder workspaces.

* fix(plugins): open folder workspaces and host-naming ids through Orca's window

workspace.open of a project-group folder asks the window to show it
(setActiveFolderWorkspace), since the runtime activates Git worktrees only.
editor.open resolves the identity: ids workspace.list now returns. commands.run
documents that it must call the raw built-in, never a replacement wrapper.

* plugins: regenerate the testing bundle and skill guides on the rebased host actions

Generated files only (lint-staged's oxlint refuses a commit with no lintable files).

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

* chore(plugins): regenerate the testing bundle on main

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 05:47:35 +00:00
NeilandClaude 544577fe02 feat(plugins): workers can list and open workspaces, create and read terminals, launch agents (#37312)
* feat(plugins): let full-access workers act on workspaces, terminals and agents

Host API minor 3 adds worker-only rows: workspace.list (workspace:read),
workspace.open (workspace:write), terminal.create (terminal:send),
terminal.read (terminal:read, at most 2,000 lines) and agent.launch
(agent:launch). Each dispatches the runtime RPC method the orca CLI calls,
in process with the CLI's identity, so it runs on the host that owns the
workspace (local, WSL or SSH) and covers folder workspaces. The new
capabilities arrive in 1.4.248; typings, docs and skill references are
generated from the table.

* fix(plugins): make workspace host actions safe to revoke, cancel and target

- Each runtime effect re-checks the plugin's approval right before the
  runtime acts (a dispatcher beforeInvoke hook, after its own waits), and a
  worker's cancel or exit now aborts the call's signal through to the runtime.
- agent.launch starts the agent's CLI in a background terminal and returns
  its handle at once; a prompt is delivered afterwards through the runtime's
  own reuse-terminal path, so the host call never waits for the composer.
- workspace.list adds project-group folder workspaces and returns ids that
  name their host (identity: keys), so twins on two hosts are never ambiguous.
- terminal.create passes presentation background; terminal.read counts a
  runtime-limited read as truncated. workspace.open refuses folders as
  unavailable until a window-side open lands.

* plugins: keep both API extensions and host-call tracking under the line limits after rebasing on the hooks

Worker-only status bar and workspace methods spread into PLUGIN_HOST_API through
one module, the in-flight host call map moves into PluginWorkerHostCalls, and
bindPluginRuntime builds the runtime RPC so main-process-plugins.ts keeps its
size; regenerated docs and typings.

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

* chore(plugins): regenerate after rebasing on the editor recipe and shots

* chore(plugins): regenerate after rebasing on the plugin shot recipe

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-02 05:44:29 +00:00
Brennan BensonandClaude Opus 5.5 1783cf58b1 Show agent sign-in notices before the first chat message (#37191)
* Show explicit agent sign-out facts before sending a chat

* Drop the Grok status process; keep listed models when Pi or Claude replies arrive late

Grok goes back to one listing process with no Grok-specific sign-out guess;
an agent-authored auth-required reply still reports notSignedIn. Pi reports
notSignedIn only when it has no provider and nothing listable. Once Claude's
required replies are in, the listing deadline returns them instead of failing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Drop the runner tests' timeout bumps, which sat below the default

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Type the endpoint test's launch env as a string map

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Drive the signed-out Claude re-probe trigger in the scaling contract

N and 10N distinct chats (distinct read claims, one account-scoped
Claude fingerprint) read with waitForListing against the real probe and
store on an injected clock: one listing before the held-reason TTL,
exactly one more once it is due (held until every read has decided),
none within the next TTL, each result carrying notSignedIn and models.

Checked locally that it bites: making heldReasonDue ignore the TTL fails
it (2 listings inside the TTL). Removing the in-flight dedup (the
probeDue isListing guard plus the lister's early return) does not: store
refresh then runs once per chat, but a newer flight replaces each queued
one behind the two admission slots, so still one process per TTL.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Accept Claude control replies as main did, without a type field

The shared reader required type 'control_response' and prefiltered on
that text, dropping success frames main's model and slash-command
parsers accepted (the released-phone wire test's fake listing).
It now prefilters on request_id and keeps the structure limit and
success-only reading.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Narrow the scaling contract's catalog result before reading models

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-01 21:42:07 -08:00
Brennan BensonandClaude Opus 5.5 06b8f7dc37 Keep Windows and Linux chat switching separate from worktree shortcuts (#37199)
* fix(shortcuts): give Windows and Linux chat switching a working default

* test(shortcuts): verify the worktree and chat chords independently

* fix(shortcuts): preserve agent newline keys while switching chat views

* fix(shortcuts): use Ctrl+Shift+F11 for Windows and Linux chat switching

The Ctrl+Alt+Shift+J default could not match non-Latin layouts or IME
input, because Ctrl+Alt chords skip the physical-key fallback that
protects AltGr characters. A function-key primary matches on every
layout; Ctrl+Shift+J stays as the alias where Switch worktree doesn't
claim it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(shortcuts): keep the chat toggle's own default alias when its shortcuts are edited

Saving any change to Switch between Chat UI and terminal on Windows and
Linux kept its untouched Ctrl+Shift+J alias, which the conflict check
then refused against the worktree palette's default, so replacing or
removing the primary failed. The check now exempts a chord per binding
when it is the action's own default and every other owner also holds it
as a default, so non-default explicit claims are still refused.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(shortcuts): expect the new Windows/Linux chat switch label

The context menus show the toggle's primary binding, which is now
Ctrl+Shift+F11 on Windows and Linux.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-01 21:41:39 -08:00
Brennan Benson 5d3dfe943e Tasks source summary, repo link and Filters row follow the list's actual source (#37226)
* Show the active GitHub list source in Tasks summary

* Tasks header, repo link and source row follow the list's resolved source

The Tasks summary could name the saved upstream project while the list came
from the fork, and the "Open in GitHub" link could open the other kind's
repository when the active kind's source was unresolved. A new search or an
Issues/PRs switch also blanked the source until the new fetch landed.

Compute the source summary once, after mode and item kind are known, from
the list's resolved sources (saved project identity no longer reaches the
formatter). The summary, the single-project repo link (strict active kind)
and the Filters source row share one display-only read: the current query's
entry, else the latest same-scope sibling while the query is fetchable.
Notices, errors, Retry, filter metadata and page rows still read only the
current query's entry. Projects, GitLab, Linear and Jira output is unchanged.

* Tasks source carries the shown entry across queries, read live

While a new search or Issues/PRs switch has no cached result yet, the Tasks
summary, repository link and Filters source row keep showing the source of
the entry they last showed for that project copy, read live from the cache,
instead of picking the newest cached sibling. A refresh that changes that
entry is followed, other queries' results never take over, a preference
change's eviction ends the claim, and a present unresolved result or a
too-large query makes no claim.

The display read now happens in the existing current-entry selection pass
(at most two cache reads per selected project, no cache scan), and the
summary re-translates when the language changes. Adds a SourceBar fixture
with a long fork slug at normal and narrow widths.

* Tasks source display perf contract measures each update on its own

Bound every measured update (another host's patch, a non-cache store write,
current and sibling fetches, a real preference eviction) at 10 and 100
selected rows and 50 or 500 cache entries: no cache enumeration, at most two
reads per row per selector call, a fixed selector-call budget equal across
sizes, no key rebuild on cache writes, linear row visits including pointer
upkeep, and reused output references for writes that change nothing shown.

* Use typed reads in the Tasks source display perf instrumentation

The static-analysis rule rejects Reflect.get; the cache and row proxies now
read by typed keys and count exactly the same reads and enumerations.

* Drop type assertions from the Tasks source display changes

Stage hooks return Object.assign(model, {...}) instead of casting the model
(same object, same writes, same type). The fixture and test stubs keep their
partial-model casts on one line each with a SAFETY reason, the row proxy uses
a type guard, and the filler work item is a typed fixture.
2026-11-01 21:40:33 -08:00
Neil 3b5eed8ca4 docs(plugins): point the editor and status bar recipes at plugin shot (#37332) 2026-11-01 21:40:07 -08:00
Brennan Benson 9ce35be4ff fix(native-chat): effort, speed and fast controls stay usable while the model list refreshes; dotted versions in id-derived model labels (#36870)
* fix(native-chat): running chats keep effort menus during model discovery; dotted versions in id-derived model labels

* fix(native-chat): options stay usable while a model list refreshes; dated preview ids keep their dashes

A running host listing no longer disables effort, speed or fast mode. Those
controls follow the data they draw from: before any list exists they show
the placeholder or a read-only saved effort, and once a list or the chat's
own answer is shown they stay usable through every refresh, for every agent.
The listing flag is now only the host's raw fact, which keeps a seed from
settling to the built-in list while discovery runs.

Id-derived labels no longer dot a zero-led part, so MM-DD preview dates
(gemini-2.5-flash-preview-05-20) stay dates.

* fix(native-chat): a model list refresh keeps the verified models and default effort already shown

While the host refreshes a Claude or Codex list, the chat keeps the model
ids an earlier finished listing verified that the refreshing rows still
contain, so a running Codex chat's CLI-default effort ("Medium") no longer
blanks from the pill and menu until the listing lands. Ids no finished
listing verified stay unverified, and a finished listing still replaces
the set.

* test(native-chat): type the listing-wait check without an assertion

* fix(model-labels): month-day dates after October stay undotted

* refactor(native-chat): listing-verified model ids get their own module
2026-11-01 21:39:37 -08:00
Brennan Benson 0bf96e0d7a Show a GitLab MR's pipeline result even when it has no jobs (#37177)
* Show failed pipelines and check suites without jobs

* Use the parent pipeline as the GitLab checks verdict

The MR's own pipeline status now leads the Source Control Checks panel,
the MR dialog and the phone checks badge whenever the details reply
carries it, even when the returned jobs are empty, partial or all
passing. Job rows and counts stay a separate breakdown. The parent
follows pipeline-level policy (required manual is pending, canceled and
skipped are not failures, mergeable manual is neutral) from one shared
rule, and it is a provider link rather than an expandable job, so it
never shows a details error with Retry. A failed parent leads the
triage strip and joins the Fix prompt by name and link.

Drops the GitHub zero-run failed check-suite rows from this change;
existing approval-required suite rows are unchanged.

* Name the GitLab pipeline outcome and keep its verdict in one rule

The host now settles the parent pipeline's verdict with the same rule
and reply that produce the MR status, so a manual pipeline on older
GitLab reads pending everywhere. The phone checks badge names the
pipeline outcome (Pipeline passed/failed/pending) instead of an
unlabeled one-item count; job wording without a parent is unchanged.
The desktop parent row's status is localized, and a failed MR-details
read still shows its error beside a kept parent with no jobs.

* Keep Fix for failed GitLab jobs and treat waiting_for_callback as pending

The triage strip shows again when a returned job failed under a passing
parent pipeline, so its Fix stays available; a failed parent still
leads. A waiting_for_callback pipeline now reads pending instead of
neutral, in the MR status and the parent pipeline alike.

* Mark the checks-panel action test fixture cast as safe

* Pause the pipeline row spinner offscreen and under reduced motion
2026-11-01 21:39:18 -08:00