Commit Graph
128 Commits
Author SHA1 Message Date
Neil d5f2a17cd2 refactor: group agent launch contracts under concrete owners (#37915) 2026-11-03 14:45:49 -08:00
Brennan BensonandClaude Opus 5.5 d1d4ac3714 Stop retrying final native agent startup refusals (#37213)
* Stop retrying final native agent startup refusals

* Retire startup opens after exit and keep final answers across exit orders

- A start flight cancels its outstanding provider open on every ended path; a direct attach keeps the child-bound abort.
- The post-exit answer join is bounded by the remaining startup ceiling.
- An elapsed initialize deadline keeps its words when the exit wins the race.
- Codex cloud config temporary declarations retry on thread/resume as on thread/start.
- A Claude exit before acquisition publishes waits briefly for initialize's answer, so a rejected initialize stays final.
- The Claude startup stdout observer parses only failed root results, within the shared line budget, and detaches once it has one.

* Keep saving the last turn when a Claude process exits after startup

The exit path skipped saving the resume cursor whenever Orca had not
dispatched a message, but turns can settle without an Orca dispatch and an
already-started idle session still owns its exit save. Only a start that
died before initialize answered and before any turn now skips the save and
gets the short cleanup bound. A failed result captured before the first send
counts as a startup failure only when no turn ran in that process.

* Merge duplicate test imports

* Bound resumed Claude starts that exit during catch-up and keep untyped refusals final

Exit-time cursor writes and the short close bound now key on the host-awaited
open actually returning, so a resume that exits while transcript catch-up is
pending publishes ended at once instead of waiting on a cursor write. The
startup observer no longer reads an answer from an oversized line's prefix.
A typed acquisition refusal without a dedicated failure kind keeps its
refusal marker, so an exit-only start stays final.

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

* test: pin the fake clock in the resumed-exit start test

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

* test: bound startup answer parsing by candidates at N and 10N records

Drive the startup observer through the shared framer at 100 and 1000
irrelevant hook and assistant records, and assert that only the failed
root result is parsed, one capture happens, the data listener retires,
and no parse follows capture or finish, with identical counts at both
populations.

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

* test: shape startup fixtures like the real providers

Held opens in the launch test now reject when their child exits, as a
real connection does, and the temporary open failures use the provider's
actual overload envelope. Also fixes the test-only type errors CI found.

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

* test: use the real Codex canonical-filename refusal wire capture

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

* test(claude): align merged startup tests with answer-wins and final generic results

An exit with no stderr leaves the start to Claude's buffered result, so that result is the start's one failure. A generic startup failure result is final after one start; only an unanswered exit retries, and the recovery case now recovers from such an exit.

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

* fix(claude): let a final initialize answer outrank a physical exit reported fault-first

The connection reports one physical root exit through onFault and then
onExit. It now marks that error as an observed exit before either
callback, and acquisition's onFault leaves a proven exit to onExit's
bounded initialize join, so a final initialize rejection that arrives
just after the exit owns the start instead of a retryable bare exit.
Typed refusals, live-root faults and processless spawn faults still end
the start at once.

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

* test(claude): await a macrotask instead of real time in the exit-answer start test

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

* test(claude): replace casts in the exit-answer start test with an annotation and guard

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

* fix(agent-session): let each adapter decide a failed start, and give the start one owner

A start that the agent refused could still be replayed: the host joined a
child's exit with its open's error and rebuilt the meaning from provider error
classes, and an answer written just before exit could lose to the exit itself.

Each adapter now answers its own acquire, open and required startup reads with
one typed result (final, or safe to run once more), keeping a final answer
beneath the exit proofs cleanup adds. Transports keep reading answers already
written after the agent stops reading or exits, within the existing one-second
drain, and only a drained exit of the agent's own process counts as unanswered.

The child's open is the single owner of the start's outcome: it awaits the
adapter's result and required settlement, records the verdict once, writes a
direct attach's failure row, and stops the child. The start flight reads that
verdict instead of joining exit and open. A start whose adapter gives no outcome
within five seconds of its own process exit fails through a timer that no
bookkeeping can hold, and the original start deadline stays in force until the
start is decided.

Tracked in STA-12982.

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

* fix(agent-session): bound a failed start's lifetime and keep Orca's own refusals final

- A start's ending is kept only while its owner can read it: admitted when the
  acquisition starts, retired when the owner finishes, the acquisition fails, or
  the session is released or closed. An exit after ready records nothing.
- Codex takes its own exit as the start's wake from the moment the process is
  seen, before spawn bookkeeping, and a failed acquire keeps that exit as cause.
- Once the handle or rewind write began, an unanswered death no longer decides
  the start: the write's refusal stays final, and the exit grace bounds the wait.
- Stop, the deadline and the exit grace release the start's callers at once; the
  failure row is queued first but never awaited by them.
- An ACP connection Orca closed before the exit keeps that cause, so cleanup's
  exit is not read as the agent ending unanswered.
- A request deadline keeps its words when an exit is seen around it.
- A direct attach whose exit settled first keeps the exit's words.

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

* fix(agent-session): let a start's owner, not its live route, keep and retire its ending

Exit acknowledgment drops a session's route while the start's owner may
still be reading how its acquisition ended, so the router now reaches the
adapters by exact generation for both the read and the retirement. Claude
admits its acquisition before publication can observe an exit.

An ACP start Orca refused before the agent exited now fails with that
original refusal as the adapter's final verdict, through every cleanup
wrapper, instead of a generic closed-while-starting error.

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

* test(agent-session): give the worker retry fake the Codex adapter's typed start verdict

The host now reads only the adapter's verdict on a failed start, so the
fake open rejects with the verdict the Codex adapter returns for its
declared overload instead of the raw request error.

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

* fix(agent-session): let Claude's own exit record decide a start the SDK reports as exited

A Claude CLI missing from the launch PATH makes the supervisor exit 127 with the spawn error on
stderr. The SDK rejects initialize with only "process exited with code 127", and the start took
that report as its cause, so the missing CLI was lost: the chat said Claude stopped before it
finished starting and the start was retried as an unanswered exit. The SDK's exit report is no
answer; the start now reads Orca's own record of that exit, which carries the missing CLI.

Also brings two ACP tests in line with the typed start verdict (a signed-out open rejects with
the adapter's notSignedIn verdict) and the bounded drain after the agent stops reading.

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

* perf(agent-session): stop parsing Claude's startup output once its failure is captured, and pin start and drain work at N and 10N

A failed root result captured mid-chunk still let the rest of that chunk be framed and parsed;
nothing reads those records once the start has its answer. The observer now accepts no further
line once it has captured the failure, and drops what that chunk left in its framing state.

Two contract tests drive the production start owner and transports at N and 10N:
- starts through the host, router and Codex adapter (ready, final refusal, safe replay, deadline
  expiry): each start's owner, abort handles, tracked attempt, flight, buffered exits, adapter
  receipts, root-exit subscription and deadline timer return to baseline, a waiting start holds
  a fixed set, and spawns, opens, router reads and retirements, timers and failure rows grow
  exactly linearly;
- ACP, JSON-lines and Codex connections with a pending call, answered at exit or abandoned after
  the agent stops reading (with duplicate terminal signals): each call settles once, each output
  drain finishes once and leaves no listener or timer;
- an ACP start refused at sign-in keeps its own first cause and leaves no receipt or child.

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

* fix(agent-session): decide a failed start once from everything its adapter saw

A failed start was decided from whichever error reached the decision first, so a later or
poorer report could replace the one that explained it: the SDK's exit report hid the missing
CLI Orca's own exit record carried, and an output drain let a load deadline give way to an
unanswered exit. One shared rule now weighs every observation an adapter kept. The start may
run again only if every observation allows it, and the most specific one explains it: what the
user can act on, then a request deadline, then the agent's answer, then Orca's record of its
exit, then an SDK's report of that exit. Claude, Codex and Pi pass their exit records alongside
the operation's error instead of choosing between them.

An ACP agent that exited while its output drained no longer gets a replacement session after
its load fails. JSON-lines output that reports both its end and its close now starts one wait,
so the agent's exit can always cancel it.

Contracts at N and 10N: JSON-lines output ending while its root lives, real Claude and Pi
adapters retiring every start's receipt, and a user Stop whose cleanup is held then released.

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

* fix(acp): keep a missed saved-session load deadline instead of opening a replacement

A live agent that let session/load run past its deadline fell through to the
takeover path, and the replacement session/new answer then replaced the
deadline the user had to see. The takeover predicate now propagates any
provider request deadline unchanged, read through the existing typed timeout.

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-03 10:53:21 -08:00
Neil 865b9544ae refactor(ipc): group feature handlers and resource owners (#37823) 2026-11-03 10:24:48 -08:00
OrcaWin a38acbe354 test: remove 64 low-value test declarations (#37863) 2026-11-03 10:08:03 -08:00
Neil 5d5b4f4f3d refactor(ai-vault): organize provider scanners and history owners (#37742) 2026-11-03 01:05:52 -08:00
Neil c6b829ecf1 refactor(main): group WSL host and orcad lifecycle owners (#37728) 2026-11-02 23:58:18 -08:00
Neil 6d5edf8c33 refactor(main): organize WSL discovery filesystem and execution owners (#37722)
* refactor(main): organize WSL discovery filesystem and execution owners

* refactor(main): consolidate defining-owner path imports
2026-11-02 23:36:23 -08:00
Neil f3088d53c9 refactor(main): group terminal support by lifecycle owner (#37660) 2026-11-02 22:13:39 -08:00
Neil 0509a2d83a refactor: group local PTY provider and shell readiness modules (#37235) 2026-11-01 16:16:22 -08:00
Brennan Benson 9b15222da6 Keep OpenCode's default effort visible after a reply (#37159)
* Show the native default effort for OpenCode models

* Show the effort OpenCode 1.x actually runs when none is picked

OpenCode 1.x ACP runs a listed default variant, else the first listed
one, so declare that same variant instead of a no-override Default. The
draft and launch default stay as on main; the resting fallback now shows
it too. Shared declared-effort consumers expect no effort for a readback
without that model's menu.

* Name the recorded OpenCode listing test for what it checks
2026-11-01 15:51:59 -08:00
OrcaWinandOrcaWin b4640db629 test: remove 462 low-value test declarations (#37138)
* test: remove 462 low-value test declarations

* Shrink flaky test pattern baseline after audit896 test removal

* Remove two empty hook-only suites after audit896 test removal

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-01 21:28:12 +00:00
OrcaWinandOrcaWin ed3e82a2e7 test: remove 699 low-value test declarations and 116 suites (#37002)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-11-01 11:34:06 +00:00
Neil 89f9ce08de refactor(shared): organize session contracts and projections (#36979)
* refactor(shared): organize session contracts and projections

* chore: tighten dropped-path flaky pattern allowance

* docs: preserve current agent instructions with valid formatting
2026-11-01 03:14:46 -08:00
Neil 57454e6d7e refactor(agent-session): group lifecycle records and direct owners (#36909) 2026-11-01 01:24:37 -08:00
OrcaWin 30242d1759 test: remove 185 low-value test cases, including 30 suites (#36916) 2026-11-01 09:04:00 +00:00
OrcaWin b59ce5a6b5 test: remove 262 low-value test cases, including 39 suites (#36901) 2026-11-01 05:29:02 +00:00
OrcaWin 7ec9a6b1fc test: remove 247 low-value tests, including 22 suites (#36857)
* test: remove low-value suites and cases

* test: update wall-clock ratchet after low-value test removals
2026-11-01 02:54:00 +00:00
Brennan BensonandClaude Fable 5.1 2dcb0b70d0 Continue a usage-limited chat with another account or agent (#31241)
* 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

* Preserve unknown account model facts and legacy option replay

* Clarify terminal account-switch feedback in translated locales

* Offer usage-limit Continue Now only once the limit resets

* Keep usage-limit reset timers current and bounded

* Keep option mutation plans checked against their contract

* Cover unknown model choices across chat consumers

* Keep consumer fixtures aligned with canonical types

* Match the mobile picker label in its consumer test

* fix: clarify terminal scope in translated Claude account settings

* Update integration tests for current session and remote client contracts

* Keep native worker replies on their receiving account

* Preserve receiving accounts across cold starts and nested reports

* Preserve the delivery receiver when reading chat commands

* Clarify native reply matching and consolidate imports

* Resolve catalog scope without re-entering conversation queues

Give owned option mutations and delivery settlement a resolved catalog input while external reads acquire scope once. Preserve account routing, catalog lifetime and current response obligations.

* Align catalog and mobile test fixtures with current contracts

Explain the existing timeout budgets and provide the idle turn identity and truthful model-only picker label in the mobile fixture.

* Align receiving-account readers and fixtures with typed contracts

* Repair account-switch fixtures and measure receiving work

* Use the checked account-home path in catalog tests

* Restore executed-option recorder context

* Control receiving catalog deadline test clock

* Align unknown-model consumer fixtures with send capture

* Consolidate session host type imports

* Align cross-version catalog fixtures with host read contracts

* test(native-chat): bind Runs through the current start authority in receiving fixtures

Main now resolves a worker start lazily through bindRun with objective and task references, and creating a Run no longer unbinds a coordinator's earlier Runs; run-use does. The receiving fixtures follow the same production owners so every original scenario, input and bound is exercised unchanged. The receiving runtime subclass moves verbatim into its own support module.

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

* fix(native-chat): follow the selected account before its folder exists

A live Claude chat compared its account against the selected one only after that account's folder passed an availability check, so an account still being set up (or whose setup failed) left the chat silently answering on the previous account, and a resting chat refused its start before preparation could run. The retirement comparison and the start pre-read now ask the router for the selected route as identity, through the existing resolver purposes; catalog, create and probe reads keep checking availability. Preparation, typed launch failure and parking are unchanged.

Session History details show the account a chat was last launched under when the host recorded one, else its founding home.

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

* test(ai-vault): build the stale acquisition receipt without a type assertion

The History account case now reads the fixture receipt through the typed acquisition reader instead of spreading the record field through a cast; the three assertions and their inputs are unchanged.

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

* test(native-chat): narrow the rig acquisition link before relinking it

The account-setup cases spread an optional link, which typed its id as possibly undefined; the rig always links a handle, so a guard that cannot fire narrows it. No assertion or input changes.

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

* test(native-chat): follow main's chat admission in fixtures and bound the History account projection

Chat admission no longer reads an experimental host setting, so the continuation-context test drops the spy main dropped in its own fixtures. The two History consumers that install a minimal chat host give their fake store the record accessor and host id the real store has, since the projection now reads the acquisition receipt. An operation-count contract holds the production History projection to one roster read and one record lookup per owned row at 10 and 100 rows.

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

* test(native-chat): give the declared-effort catalog fake its capture port

The declared-effort fixture builds a catalog service without the capture member the options reader asks every catalog for, which failed its desktop, catalog and phone consumers; it now supplies the inert test operation like the other fakes. The History projection contract also drops an unused map parameter.

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

* Consume main's outcome change feed in the receiving-account index

Main's keyed journal records deliver each change after an epoch's frozen prefix as an
outcome sequence naming touched keys instead of typed rows. The receiving-account index
now re-reads those keys at their current values: queue cards by id, a deleted submission
retires its exact notice, and a deleted item drives the existing recovery rebuild, with
Stop marks still excluded. The in-process read row exposes the already-persisted
queue.cards keys and per-key deletion facts; itemIds and submissionIds keep listing every
touched key. The mobile unknown-consumer test mocks MobileSwitch as main's picker test does.

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

* test: validate historical usage-limit fixture before rendering

* fix: scope handoff choices and share account observation

* fix: align account menu lifetime and local projections

* test: preserve account observation contracts in quality checks

* fix: preserve typed account observation project coverage

* fix: restore handoff feedback for empty host inventory

* test: name exported handoff mocks with public types

* test: follow settings navigation consumption in feature tip adapter

* Keep usage-limit recovery actions beside their lead-in

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-31 19:06:53 -07:00
OrcaWin 7556133a5a test: remove 266 low-value cases including 11 whole suites (#36717)
* test: remove low-value suites and cases

* test: update wall-clock baseline after case removal
2026-10-31 17:10:11 +00:00
OrcaWin a0f75207ce test: remove 17 low-value suites and 133 individual cases (#36700) 2026-10-31 14:38:33 +00:00
OrcaWin effa751b93 test: remove 10 low-value suites and 130 individual cases (#36672)
* test: remove low-value suites and cases

* test: shrink two stale flaky-pattern baseline counts
2026-10-31 11:59:03 +00:00
OrcaWin 5edb1b6f9a test: remove 14 low-value suites and 119 individual cases (#36617)
* test: remove low-value suites and cases

* test: shrink flaky-pattern counts after case removals

* test: remove empty suite and stale release workflow fixture
2026-10-31 00:20:27 -07:00
Brennan Benson a62f1e4955 Keep declared default effort visible for every chat agent (#36455)
* Show declared default effort consistently across chat agents

* Leave unmappable reported effort defaults unknown

* Separate default effort context from launch policy

* Cover configured effort declarations without changing current input

* Fix declared effort context through live options readers

* Load declared effort fixtures outside test callbacks

* Combine host catalog test imports
2026-10-30 18:28:43 -07:00
Brennan Benson 98f5d13689 A kill that reached the agent ends it, so the next message after Stop goes through (#34653)
* fix(native-chat): a kill that reached the agent ends it, so the next message goes through

After Stop, tab close, idle rest or workspace sleep, Orca force-kills the
agent. It used to accept the old agent as gone only when it saw the exit
report within about a second; otherwise every later message re-ran the kill
and was refused with "Couldn't stop {agent} from before." A kill delivered to
the agent itself now ends it and releases the chat with kill-delivered
evidence; the refusal remains only when the kill could not reach the agent.

When writing the chat's journal fails and the following kill can't be
confirmed, recovery now records the close with its fault instead of silently
returning, so the turn no longer stays Working and later sends retry the stop.

Tracked in STA-12354 and STA-12355.

* Preserve provider kill evidence across cleanup retries

* Exercise ACP setup gate with real managed teardown

* fix: preserve Claude writer termination evidence through settlement

* test: consolidate termination evidence contracts

* fix: restore Pi connection exit listener contract

* test: load actual ACP teardown before timed cases

* fix: correct lifecycle contract typing and test boundaries

* test: make Claude piped fixture mock types portable

* test: expect supervised OpenCode probe teardown

* test: align remaining supervised teardown expectations

* fix: align Stop feedback with terminal writer evidence

* test: remove redundant mocked Codex continuation case

* fix: keep adapter declaration and Stop fixture checks portable

* test: keep Stop fixture clock unchanged

* test: read canonical provider handle when reopening Stop journal
2026-10-29 12:15:56 -07:00
OrcaWinandOrcaWin f4d19ca710 test: remove capability inventories and projection receipts (#36018)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 10:39:21 -07:00
Jinjing 2b73288a0b Recover native OpenCode failures in chat sessions (#35247)
- Read per-turn provider errors from OpenCode’s SQLite history
- Preserve quota, billing, access, and retry details over generic ACP errors
2026-10-28 17:29:10 -07:00
OrcaWinandOrcaWin 88e23db6b5 test: remove 16 low-value audience, notice and export cases (#35128)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-28 14:12:18 -07:00
Neil 43eb0b969c fix(opencode): give OpenCode 2 a private server only when another data dir holds the service port (#33784)
* fix(opencode): run managed OpenCode 2 accounts on a private server

OpenCode 2's background service binds one fixed port per machine, so a
second managed account's service could never start. Launch managed
accounts with --standalone, which picks its own port.

Fixes #33780

* chore(opencode): tighten standalone rewrite comments

* fix(opencode): use a private OpenCode 2 server only when another data dir holds the service port

Users with one managed account keep the shared background service. Orca
adds --standalone only when a live upstream registration
($XDG_STATE_HOME/opencode/service.json) belongs to a different data dir,
plus a short in-process claim for launches that start together.

* fix(opencode): judge resumed accounts by their applied data dir and claim the port only for real launches

Daemon spawns consume the resume request before the private-server check runs, so
derive the launch's own data dir from the applied account env when present. Only
take the shared-port claim when the --standalone rewrite can apply.
2026-10-26 23:06:43 -07:00
OrcaWinandOrcaWin 84494ce394 test: remove 338 low-value cases and 28 suites (#34234)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-26 22:58:55 -07:00
Brennan Benson 0266b5f95f fix(opencode): allow model picks when discovery is unavailable (#31985)
* fix(opencode): allow picked models across CLI updates

* test(opencode): prune obsolete timeout ratchet allowance

* fix(opencode): use resolved agents and refuse unsafe workers upfront

* fix(i18n): include OpenCode refusal messages in runtime catalog
2026-10-26 13:12:53 -07:00
Brennan Benson 407069bc63 Unify terminal starts under one host operation (#32076)
* Unify terminal starts under one host operation

* Pin winning geometry across a late terminal join

* Use terminal creation options type in launch race test

* Check closed panes after acquiring the terminal spawn lease

* Preserve terminal start resource and join boundaries

* Keep terminal attach regression within project boundaries

* Capture terminal spawn authority and preserve image coverage

* Use checked fixtures for terminal image replay regression

* test: expose persisted pane to main layout in attach race

* test: contract terminal spawn scaling and retention

* test: correct spawn scaling fixture types and CI selection

* test(terminal): cover exited prompt claims and adopted team cleanup

* test(pty): consolidate mock registry imports

* fix(pty): retain untyped IPC resume inputs in common contract
2026-10-26 00:25:37 -07:00
OrcaWinandOrcaWin de93f326ea test: remove low-value inventories, passthroughs and redundant cases (#33796)
* test: remove low-value inventories, passthroughs and redundant cases

* style: format test suites after pruning redundant cases

* test: remove obsolete workflow and flaky-test references

* test: prune deleted builder test from Windows shim allowlist

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-25 23:41:49 -07:00
Neil 22210eb3d1 fix(ai-vault): list OpenCode sessions from Orca-managed data accounts (#33658)
Managed OpenCode accounts launch with XDG_DATA_HOME=<account>/data, but
history discovery only read the app process's XDG data dir, so sessions
created after selecting an account never reached History or the vault index.
2026-10-25 19:39:40 -07:00
OrcaWinandOrcaWin 7d6603aa17 [comment audit] Complete repository-wide comment cleanup (#33249)
* [comment audit] Align legacy failure-read counts with cached display

* [comment audit] Condense shared provider lifecycle and browser recovery comments [skip ci]

* [comment audit] Condense shared generation, path and preview comments [skip ci]

* [comment audit] Condense host, file and Git contract rationale [skip ci]

* [comment audit] Tighten Git lifecycle and provider contract comments [skip ci]

* [comment audit] Clarify shared host authority and launch isolation [skip ci]

* [comment audit] simplify local access mobile and native chat contracts [skip ci]

* [comment audit] simplify native chat presentation and state contracts [skip ci]

* [comment audit] simplify native runtime and provider contracts [skip ci]

* [comment audit] simplify migration and orchestration contracts [skip ci]

* [comment audit] simplify plugin trust and process capture rationale [skip ci]

* [comment audit] simplify terminal delivery and remote compatibility rationale [skip ci]

* [comment audit] clarify remote recovery and launch wire rationale [skip ci]

* [comment audit] shorten shared RPC compatibility and runtime evidence comments [skip ci]

* [comment audit] simplify secure storage shell startup and sidebar rationale [skip ci]

* [comment audit] clarify sidebar, skill and SSH invariants [skip ci]

* [comment audit] condense structured chat delivery and timing rationale [skip ci]

* [comment audit] condense terminal replay and telemetry invariants [skip ci]

* [comment audit] clarify launch permission and terminal delivery rationale [skip ci]

* [comment audit] clarify workspace ownership and layout contracts [skip ci]

* [comment audit] wait for fitted and painted SSH terminal links

* [comment audit] clarify layout persistence and session ownership [skip ci]

* [comment audit] clarify host routing and workspace lifecycle contracts [skip ci]

* [comment audit] clarify startup persistence and app lifetime comments [skip ci]

* [comment audit] clarify recovery and activity boundaries [skip ci]

* [comment audit] condense activity and artifact invariants [skip ci]

* [comment audit] condense automation authority contracts [skip ci]

* [comment audit] simplify automation scheduling and history contracts [skip ci]

* [comment audit] clarify browser chrome and annotation lifecycles [skip ci]

* [comment audit] clarify browser routing and retained guest ownership [skip ci]

* [comment audit] clarify browser recovery and document ownership comments [skip ci]

* [comment audit] restore hosted runners required by native IME fixtures

* [comment audit] shorten preview, palette and dashboard invariants [skip ci]

* [comment audit] clarify terminal preview, dashboard and retention comments [skip ci]

* [comment audit] clarify diff-note recovery and editor lifecycle comments [skip ci]

* [comment audit] shorten rich-text and combined-diff ownership comments [skip ci]

* [comment audit] shorten autosave, draft recovery and model ownership comments [skip ci]

* [comment audit] shorten save-queue, notebook and Markdown constraints [skip ci]

* [comment audit] shorten Monaco, PDF and rich Markdown safeguards [skip ci]

* [comment audit] clarify rich Markdown source and selection safeguards [skip ci]

* [comment audit] clarify editor loading and emulator stream lifetimes [skip ci]

* [comment audit] trim emulator and feature tour narration [skip ci]

* [comment audit] clarify floating workspace and GitHub cache ownership [skip ci]

* [comment audit] trim provider controls and Linear filter explanations [skip ci]

* [comment audit] clarify pairing and chat resume lifetimes [skip ci]

* [comment audit] clarify chat delivery and transcript lifetimes [skip ci]

* [comment audit] clarify session options and host-owned status [skip ci]

* [comment audit] clarify draft durability and live-status precedence [skip ci]

* [comment audit] Trim chat send and model ownership explanations [skip ci]

* [comment audit] Shorten transcript ownership and send recovery comments [skip ci]

* [comment audit] Simplify native chat composer and transcript hook comments [skip ci]

* [comment audit] Shorten native chat scroll and structured session explanations [skip ci]

* [comment audit] Trim workspace picker and onboarding commentary [skip ci]

* [comment audit] Simplify pet rendering, review cache and quick open comments [skip ci]

* [comment audit] Trim sidebar and session history explanations [skip ci]

* [comment audit] Condense session resume and review checks comments [skip ci]

* [comment audit] Shorten checks state and file explorer refresh comments [skip ci]

* [comment audit] Trim plugin bridge and source-control action rationale [skip ci]

* [comment audit] Trim source-control listing and review rationale [skip ci]

* [comment audit] Shorten sidebar lifecycle and explorer safeguards [skip ci]

* [comment audit] Condense Settings account and appearance rationale [skip ci]

* [comment audit] Trim pairing and repository Settings explanations [skip ci]

* [comment audit] Condense Settings search SSH and terminal safeguards [skip ci]

* [comment audit] Shorten Settings voice and provider ownership comments [skip ci]

* [comment audit] Condense Settings draft persistence and host-state rationale [skip ci]

* [comment audit] Trim Settings hooks and sidebar setup rationale [skip ci]

* [comment audit] Condense sidebar deletion and board-filter safeguards [skip ci]

* [comment audit] Condense worktree cards, host ownership and Markdown contracts [skip ci]

* [comment audit] Condense sidebar drag, folder and filtering contracts [skip ci]

* [comment audit] Condense sidebar parity, sleep and host ownership contracts [skip ci]

* [comment audit] Prune focus-read baseline after comment cleanup

* [comment audit] Clarify sidebar visibility, board drops and agent evidence [skip ci]

* [comment audit] Tighten sidebar listing, drag and reveal contracts [skip ci]

* [comment audit] Clarify viewport geometry and skill update safeguards [skip ci]

* [comment audit] Tighten skill inventory, usage and host status comments [skip ci]

* [comment audit] Clarify usage ownership and resource kill safeguards [skip ci]

* [comment audit] Tighten tab selection, rename and search contracts [skip ci]

* [comment audit] Tighten tab-strip geometry and drag ownership comments [skip ci]

* [comment audit] Tighten Tasks recovery, pagination and mutation comments [skip ci]

* [comment audit] Tighten provider loading and terminal recovery comments [skip ci]

* [comment audit] Tighten completion, cadence and PTY ownership comments [skip ci]

* [comment audit] Clarify terminal restore and parked-pane boundaries [skip ci]

* [comment audit] Tighten PTY startup and replay explanations [skip ci]

* [comment audit] Clarify PTY identity and delivery ownership [skip ci]

* [comment audit] Shorten remote reconnect and input replay rationale [skip ci]

* [comment audit] Condense terminal parking clipboard and file link comments [skip ci]

* [comment audit] Clarify IME ownership and trim trace history [skip ci]

* [comment audit] Shorten pane recovery and parked watcher explanations [skip ci]

* [comment audit] Condense snapshot replay and visibility recovery rationale [skip ci]

* [comment audit] Shorten terminal parking and keyboard ownership rationale [skip ci]

* [comment audit] Trim renderer lifecycle and menu rationale [skip ci]

* [comment audit] Condense workspace cleanup ownership and settlement notes [skip ci]

* [comment audit] Clarify renderer hook evidence and source ownership [skip ci]

* [comment audit] Tighten IPC ownership and reconnect explanations [skip ci]

* [comment audit] Trim renderer focus, paste and attention comments [skip ci]

* [comment audit] Shorten scroll, locale and agent lifecycle comments [skip ci]

* [comment audit] Trim agent launch, resume and ownership commentary [skip ci]

* [comment audit] Shorten account, browser and editor comments [skip ci]

* [comment audit] Clarify host-mirror waits, previews and input ownership [skip ci]

* [comment audit] Condense launch recovery and editor tokenization comments [skip ci]

* [comment audit] Condense workspace selection and terminal pane rationale [skip ci]

* [comment audit] Condense terminal fitting and rendering recovery comments [skip ci]

* [comment audit] Condense terminal input and host routing explanations [skip ci]

* [comment audit] Condense ownership and sleeping-session recovery rationale [skip ci]

* [comment audit] Condense structured launch and terminal link explanations [skip ci]

* [comment audit] Condense terminal ownership and workspace file routing rationale [skip ci]

* [comment audit] Condense session persistence and workspace activation rationale [skip ci]

* [comment audit] Condense workspace routing and browser ownership rationale [skip ci]

* [comment audit] Condense mirror recovery and layout authority rationale [skip ci]

* [comment audit] Condense runtime transport and file safety rationale [skip ci]

* [comment audit] Condense runtime graph and structured session rationale [skip ci]

* [comment audit] Condense browser creation and remote tab recovery rationale [skip ci]

* [comment audit] Condense snapshot authority and publisher recovery rationale [skip ci]

* [comment audit] Condense frame, startup and provider cache rationale [skip ci]

* [comment audit] Condense host twin and agent lifecycle rationale [skip ci]

* [comment audit] Condense browser authority and editor cleanup rationale [skip ci]

* [comment audit] Condense editor buffer identity and review cache rationale [skip ci]

* [comment audit] Condense provider lifetime and repository ownership rationale [skip ci]

* [comment audit] Condense reconnect, hydration and terminal retirement rationale [skip ci]

* [comment audit] Condense recovery, reconciliation and persistence rationale [skip ci]

* [comment audit] Condense cleanup ownership and listing admission rationale [skip ci]

* [comment audit] Condense teardown ordering and terminal ownership rationale [skip ci]

* [comment audit] Condense recovery ledger and web host-boundary rationale [skip ci]

* [comment audit] Condense web reconnect and credential lifecycle rationale [skip ci]

* [comment audit] Condense cloud rollout and assignment safety rationale [skip ci]

* [comment audit] Condense relay session and database recovery rationale [skip ci]

* [comment audit] Condense relay placement and protocol compatibility rationale [skip ci]

* [comment audit] Condense build and packaging constraints [skip ci]

* [comment audit] Condense CI gates and validation isolation rationale [skip ci]

* [comment audit] Condense catalog identity and browser validation rationale [skip ci]

* [comment audit] Condense mobile browser and frame-budget rationale [skip ci]

* [comment audit] Shorten mobile route and browser test explanations [skip ci]

* [comment audit] Condense editor and session seam test rationale [skip ci]

* [comment audit] Trim session and terminal closure history [skip ci]

* [comment audit] Shorten terminal browser and census explanations [skip ci]

* [comment audit] Preserve root-only E2E diagnostic baseline

* [comment audit] Condense mobile seam and HTML preview test rationale [skip ci]

* [comment audit] Condense preview instrumentation and render harness rationale [skip ci]

* [comment audit] Condense bundle contracts and native-build constraints [skip ci]

* [comment audit] Shorten native packaging and CI routing rationale [skip ci]

* [comment audit] Condense release tooling and benchmark constraints [skip ci]

* [comment audit] Condense packaging and platform gate rationale [skip ci]

* [comment audit] Shorten mobile route and history rationale [skip ci]

* [comment audit] Condense mobile browser and component rationale [skip ci]

* [comment audit] Shorten drawer and workspace-form rationale [skip ci]

* [comment audit] Trim mobile review and editor-document explanations [skip ci]

* [comment audit] Condense editor lifecycle and Markdown explanations [skip ci]

* [comment audit] Trim mobile file, diagnostics and dictation commentary [skip ci]

* [comment audit] Simplify mobile host-list and workspace-view explanations [skip ci]

* [comment audit] Clarify mobile shell lifetime and bridge delivery constraints [skip ci]

* [comment audit] Condense bridge stream, native request and audio rationale [skip ci]

* [comment audit] Reduce bridge schema and page-client commentary [skip ci]

* [comment audit] Tighten mobile page bridge contracts [skip ci]

* [comment audit] Clarify mobile cache and session constraints [skip ci]

* [comment audit] Condense mobile route and lifecycle rationale [skip ci]

* [comment audit] Tighten mobile shell hook timing rationale [skip ci]

* [comment audit] Clarify route handoff and notification compatibility [skip ci]

* [comment audit] Clarify push registration and dictation cleanup constraints [skip ci]

* [comment audit] Condense keyboard geometry and native media ownership rationale [skip ci]

* [comment audit] Tighten mobile chat scroll and composer concurrency rationale [skip ci]

* [comment audit] Condense mobile reply compatibility and upload ownership rationale [skip ci]

* [comment audit] Condense optimistic echo and scroll ownership rationale [skip ci]

* [comment audit] Tighten stream replay and queued session ownership rationale [skip ci]

* [comment audit] Condense mobile composer and reply-schema constraints [skip ci]

* [comment audit] Clarify mobile transcript recovery and session ownership [skip ci]

* [comment audit] Clarify mobile queue and source-control compatibility [skip ci]

* [comment audit] Condense storage and task launch constraints [skip ci]

* [comment audit] Clarify task schemas and terminal document ownership [skip ci]

* [comment audit] Tighten terminal input and viewport rationale [skip ci]

* [comment audit] Shorten terminal and RPC recorder contracts [skip ci]

* [comment audit] Condense recorder engine and connection contracts [skip ci]

* [comment audit] Shorten host credential and relay recovery comments [skip ci]

* [comment audit] Tighten pairing recovery and bundle transport rationale [skip ci]

* [comment audit] Clarify RPC delivery and workspace catalog boundaries [skip ci]

* [comment audit] Condense catalog and relay entry contracts [skip ci]

* [comment audit] Shorten shutdown and SSH relay delivery contracts [skip ci]

* [comment audit] Condense WSL relay and E2E regression rationale [skip ci]

* [comment audit] Shorten cross-version harness and renderer fixture explanations [skip ci]

* [comment audit] Condense paired-host and E2E lifecycle rationale [skip ci]

* [comment audit] Shorten layout oracle and regression explanations [skip ci]

* [comment audit] Condense paired recovery and ownership regression contracts [skip ci]

* [comment audit] Shorten restart, sidebar and SSH lifecycle contracts [skip ci]

* [comment audit] Condense terminal rendering and IME regression rationale [skip ci]

* [comment audit] Shorten terminal recovery and benchmark contracts [skip ci]

* [comment audit] Condense tooling and Windows lifecycle proof rationale [skip ci]

* [comment audit] Condense workflow routing and release rationale [skip ci]

* [comment audit] Condense mobile security and installer contracts [skip ci]

* [comment audit] Shorten native rationale and stylesheet workarounds [skip ci]

* [comment audit] Shorten Windows visibility probe rationale [skip ci]

* [comment audit] Condense embedded release and signing rationale [skip ci]

* [comment audit] Retain current main test behavior in final reconciliation [skip ci]

* [comment audit] Complete final comment review across current source inventory

* [comment audit] Handle consolidated audit reports before final CI

* [comment audit] Preserve credential storage census detail [skip ci]

* [comment audit] Scale broad changed E2E selections with verified timing shards

* [comment audit] Align E2E assertions with browser close and settled session metadata

* [comment audit] Match existing E2Es to current resource and windowing contracts

* [comment audit] Observe the shared server outage notice in reconnect coverage

* [comment audit] Make existing renderer probes measure settled tab and PTY work

* [comment audit] Align palette E2E selector with task search

* [comment audit] Refresh remaining palette search selectors

* [comment audit] Keep selector correction within selected audit specs

* [comment audit] Await emoji fixture settings inside renderer evaluation

* [comment audit] Cancel fixture fit retries between terminal tests

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-25 04:05:46 -07:00
Neil e575cc19a3 fix(opencode): refuse model launches on OpenCode 2.x releases that drop the startup prompt (#33436)
OpenCode 2.x model-selection launches require 2.0.19+ (upstream #51938 waits for agent/model before auto-submitting --prompt) or a native-prompt version (2.0.12, 2.0.16), fixing a regression from #33307 where 2.0.14/15/17/18 accepted a picked model but silently dropped the first prompt.
2026-10-24 23:56:27 -07:00
OrcaWinandOrcaWin fdcf887bf0 chore(lint): fix suppressed lint violations instead of ignoring them (#33294)
* chore(lint): remove disable directives that suppress nothing

Each was reported unused by the oxlint config that owns its rule (root,
casting, react-doctor, anti-slop, native-plugins), including 17 file-level
react-doctor blanket disables whose rule no longer fires. An unused
react-hooks disable was masking a react/purity finding in
useAgentBucketCounts (compiler rules skip functions with hook
suppressions); suppress that one explicitly where the code explains it.

* test(tab-bar): use typed tab/file fixtures instead of @ts-expect-error partials

* chore(lint): fix misc suppressed lint violations instead of disabling

- consistent-type-imports: the "vi.importActual requires inline import()"
  rationale was wrong; use typed vi.mock(import(...), importOriginal) or a
  type-only namespace import.
- no-control-regex: source-control commit/push failure summaries, shell PATH
  hydration, and ipynb ANSI parsing reuse the shared ansi-escape-sequences
  stripper and control-character pattern instead of private copies.
- no-explicit-any / no-useless-spread / no-this-alias: typed `this` in
  bridge test mocks, drop blanket file-level disables, drop a this-alias.

* refactor(main): replace avoidable type assertions with checked narrowing

17 production cast suppressions in main/wsl-guest removed: untrusted IPC
and RPC payloads (Jira issue update, WSL guest plugin install, handshake
type) now narrow through isRecord/type guards and build typed results;
redundant casts dropped; hand-rolled object checks and errno casts use the
existing isRecord / hasErrorCode helpers.

* refactor(renderer,mobile): replace avoidable type assertions with checked types

13 production cast suppressions removed: RPC failures read through the
`ok` discriminant instead of casting to RpcFailure; react-native-web host
refs narrowed with instanceof HTMLElement; redundant reply/diff casts
become checked annotations; the TUI agent param uses z.custom(isTuiAgent)
like its sibling schemas; the agent-status slice cast that hid missing
actions is gone so the creator's return type checks the whole slice.

* chore(lint): drop dead tiptap wrapper; scope anti-slop mocking rule to test support

- safe-react-node-view-renderer patched handleSelectionUpdate, which
  @tiptap/react 3.31.3 no longer has, so it always returned early. Use the
  stock ReactNodeViewRenderer.
- The anti-slop test override only matched *.test.{ts,tsx}, forcing
  file-level no-module-mocking disables in test harnesses and fixtures.
  Match *-test-harness, *-test-fixture(s), .test-fixture and *.test.mjs,
  then drop those disables and the now-redundant per-file exemptions.

* test: replace repeated cast suppressions with typed fixtures (main/shared/e2e)

Net -119 cast directives. Typed fixtures replace recurring casts:
unusedSshConnection/unusedOrcadHostTransport placeholders, a typed
readPersistedState harness read (exposed a test treating optional
httpProxyUrl as always set), real Response objects in fetch spies, an
updater main-window fixture, a CDP webContents adapter, one shared
releaseModuleExport for cross-version tests, and requireOverlayDir in
place of `as string` on possibly-undefined overlay paths.

* fix(runtime): validate loaded device rows and host scope instead of casting

Two cast suppressions claimed checks that did not happen:
- device-registry-file-read: "normalizeLoadedDeviceRow re-validates every
  field" was false; deviceId, token, name and timestamps were never
  checked. Rows without an identity are now dropped and the file is set
  aside through the existing corrupt-file path (registry reads as
  doubtful, so no revocation verdicts); a non-string token is stripped
  so the row stays listed but cannot authenticate.
- client-ui: "only optionality differs" was false; any string reached
  persisted workspaceHostScope. Narrow it with isWorkspaceHostScope and
  ignore unknown scopes (wire schema unchanged for mixed versions). The
  remaining cast now states what it actually covers.

* test(runtime,ipc): drop redundant cast suppressions; typed runtime store fixture

-98 cast directives across runtime/ipc tests: 61 casts that typecheck
without the assertion; a typed vi.fn for scoped invalidation; a
partialRuntimeStore fixture in place of `store as never` for
OrcaRuntimeService; typed worker terminal/authority builders in the
incarnation-fallback suite (the old stub lacked runtimeId, ptyId,
worktreeId and launchTokenHash) plus removal of stacked duplicate
directives there.

* chore(lint): typed vi.mock imports and explicit listener snapshot in shared-bucket tests

Remaining files from the misc-rule pass that overlapped other buckets:
codex-accounts mocks use the typed vi.mock(import(...)) form instead of
a consistent-type-imports disable; the daemon late-exit fixture copies
its listener set with Array.from instead of a no-useless-spread disable.

* refactor(github,mobile): narrow routing settings type; drop remaining avoidable casts

- work-item-routing cast a one-field object to AppState['settings'] under
  a claim that readers only consume activeRuntimeEnvironmentId. Return the
  existing RuntimeFocusSettings pick instead and narrow the cache-key
  chain's parameters, so the compiler enforces that claim.
- mobile file preview reads refusals through the RpcResponse `ok`
  discriminant rather than a cast.
- terminal document host-notify accepts `unknown` errors, removing the
  message-bridge cast.
- native chat readability drops a redundant repo-list cast.

* test(renderer): replace repeated cast suppressions with typed fixtures

-140 cast directives (and ~150 unsuppressed casts of the same shapes):
- mockPanePtyArgs owns the connectPanePty fixture casts, so a wrong
  argument order or fixture is now a type error; drop binding casts for
  members PanePtyBinding already declares.
- Seed AppState tab rows with the typed makeTerminalTab; this exposed a
  split direction 'row' that is not a TerminalPaneSplitDirection.
- Partial GlobalSettings use getDefaultSettings overrides; Jira-only
  stores use createTestStore; runtime environment rows/statuses come from
  a typed paired-runtime-environment fixture.

* chore(lint): drop no-module-mocking disable now covered by the test-fixture glob

* test(e2e): fix all 221 grandfathered e2e type errors; baseline to zero

The e2e typecheck baseline grandfathered 221 errors in 119 files. About a
third were tests drifted from the current API, several of which would
fail or mislead at runtime:
- terminal-shortcuts called a nonexistent xterm buffer method;
- the daemon-lifecycle fake lacked terminateOwnedTree, hidden by importing
  its type from a module that does not export it;
- arguments in the wrong position (listProcesses(hostId, opts), a dropped
  pty.write inputKind, an extra toWebTerminalSurfaceTabId argument);
- removed enum values ('drawer', 'idle', 'editor',
  'session-insecure-origin') and a launch_source the telemetry schema
  rejects;
- missing required fields (turnScope, childWorkOpen, providerIdentity,
  reviewLookupOutcome, runtimeServiceAccount behind an `as RelayConfig`);
- dead reads (tab.customTitle, bucket.targets, changedPixels).
Also lifts variables that narrowed to `never` after poll-callback
assignment, and adds a typed xterm render-dimensions accessor. Includes
the cross-version suites' shared releaseModuleExport adoption.

* chore(typecheck): gate the now-clean e2e typecheck in local lint

The e2e baseline is empty, so the ratchet now rejects any tests/ type
error. CI already runs it via run-ratchets; add it to pnpm lint's
explicit ratchet list and replace the stale 'not yet clean' note.

* test(mobile): typecheck every mobile test; baseline 105 files -> 0

mobile/tests-typecheck-baseline.txt grandfathered 105 test files (531
errors) whose types CI never checked. Contract changes had landed without
these tests following, and type pins in them silently checked nothing.

- Root cause: salvagedOptional (src/shared/zod-salvage.ts) cast away
  zod's optional marker, so every reply type built on it claimed
  salvaged fields were always present. Return a real ZodOptional;
  runtime is unchanged (the outer optional short-circuits undefined).
- Production now takes the port it uses: RpcOperationSender instead of
  RpcClient for send-only callers, a narrow fetch signature, and only the
  request fields push-receive reads.
- findAllByHostType/findByHostType replace `'Text' as never` lookups;
  stubRpcClient gives tests a typed RpcClient.
- Real test bugs: settings-host-client-lifecycle "relay" hosts were
  direct hosts (relayHostId no longer exists); two toEqualTypeOf pins
  could never hold; a recovery hook ran with an undefined scope key;
  a create-PR test cast to a never-imported type; "no URL" assertions
  passed on null; plus stale required props, args and enum values.

* test(e2e): parse workerStart result instead of casting it

* test(runtime): typed partial runtime stores with production-shaped fixture data

Route every partial store passed to OrcaRuntimeService through
partialRuntimeStore with typed row builders, removing 60 cast directives
that hid fixture data production never produces:
- paired-client-navigation-test-harness keyed setWorktreeMeta writes by
  `[object Object]` (it took an id where the store takes a target), so
  reads never saw them;
- invalid worktree lineage origin/capture and incomplete workspace lineage;
- getWorkspaceSession returning null where the store returns the default
  session; getGitHubCache returning undefined;
- orcad migration states missing migrationId/manifest/receipt, with a
  toEqual pinned to that incomplete shape;
- partial repos, metadata, folders, project groups and notification rows.

* refactor(renderer): resolve suppressed React hook lint instead of disabling it

109 of 187 react-hooks/react-doctor suppressions fixed:
- ~95 exhaustive-deps disables only hid stable refs and setters passed
  through controller objects; list them (identity never changes, so
  nothing re-runs), plus a few real stale closures (tabId/worktreeId).
- Effects keyed on one value that read the latest props now use
  useEffectEvent (WebConnect, skill freshness, Bitbucket dialog seeding,
  Landing preflight, automation catalog, structured-session recovery,
  file explorer).
- The conditional layout-owner hook is selected once at module load from
  the build constant instead of a rules-of-hooks disable that also hid
  the whole controller from compiler and react-doctor rules.
- A hook disable was masking a react/purity Date.now() in the palette's
  recent-tabs memo; sample it when the snapshot is captured.
- Three identical debounced-search effects share
  useTaskSearchDebouncedApply; layout snapshot merge helpers move out to
  stay under max-lines.
Remaining suppressions are mount-once resources, invalidation epochs,
deliberately keyed fields, and test harnesses that mock the dispatcher.

* chore(ratchet): exempt test harnesses and fixtures from the focus-read ratchet

The ratchet skipped *.test-fixture.ts but scanned *-test-harness,
*-test-fixture(s) and *.test-support files. Those seed settings with
getDefaultSettings (which the ratchet discovers as a focus reader) and
never route host work, so 17 baseline entries were false positives, and
replacing a test's `settings: {...} as never` with typed defaults tripped
it. Match the repo's test-support names and prune (which also drops one
stale entry), and rename the frame-ordering harness to *-test-harness like
its siblings. A blanket "-harness" match would also exempt
e2e-terminal-pty-harness, which production imports, so the names stay
explicit.

* test: merge duplicate shared/constants imports

* revert(file-explorer): restore original tree load effects pending SSH e2e investigation

* test(runtime): drop RuntimeStore cast now that the fixture is typed

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-24 19:37:19 -07:00
Neilandggbdpq d170b5a806 fix(opencode): accept OpenCode release ranges for launch-time model selection (#33307)
OpenCode model selection accepts per-major floors (1.x >= 1.18.30, 2.x >= 2.0.14; prereleases and 3.x refused) instead of exact version allowlists, so current releases launch with a picked model again. Fixes #26611. Supersedes #26683, #31985.

Co-authored-by: ggbdpq <67929842+ggbdpq@users.noreply.github.com>
2026-10-24 16:59:04 -07:00
Brennan Benson 6059a5f7fa Native chat: a message is never marked not delivered after a crash, and reopening a chat stops reading the transcript (#30580)
* Native chat: never mark a message not delivered after a crash; reopening a chat stops reading the transcript

After a crash or restart, attach read a window of the agent's saved log and marked any
unconfirmed message missing from it as rejected "not delivered". Absence from a log Orca
does not own is not proof: the window's anchor moves every turn (STA-7416) and its text
filters drop tagged prompts (STA-7453), so messages the agent received were marked
undelivered and retyping them duplicated the question. The read also ran on every attach
(STA-7434).

Delete the inference: the provider history window and its adapter hooks (Claude window and
branch proof, OpenCode stored-messages reader), the submission matcher, and the attach step.
A send the crash boundary leaves unconfirmed stays an ordinary sent message; the interrupted
turn still ends through the existing settlement. Explicit live refusals are unchanged.

A queued card whose hand-off a restart left unconfirmed no longer counts as able to return
to the queue, so it stops keeping an idle chat loaded.

* test(native-chat): update restart fixture calls after history removal

* Hide rewind targets without a saved native boundary

* Run rewind boundary regression across host and renderer

* Keep incoming main package-manager lock unchanged

* Test recovered chat consumer outcomes without delivery inference

* Assign the complete cursor in recovered phone regression fixture

* Supply presentation capture in rewind boundary fixture
2026-10-24 00:27:01 -07:00
Neil 85e690ff60 fix(provider-process): kill a provider group its SIGKILLed supervisor leaves behind (#30997)
* fix(provider-process): kill a provider group its SIGKILLed supervisor leaves behind

* fix(provider-process): re-read a provider start in its read second; poll instead of sleeping in tests

* fix(provider-process): keep the report channel through the Codex session adapter; re-prove same-second starts

* fix(provider-process): never kill a leaderless provider group; list guard files in the CLI project
2026-10-19 22:03:22 -07:00
Kelvin Amoaba e43f3e7e04 feat(opencode): open OpenCode 2 in the chat view and list 2.x models before the first message (#28424) 2026-10-18 18:42:23 +00:00
Brennan Benson 002320c17d fix(native-chat): verify the actual CLI conversation during resume (#29124)
* fix(native-chat): identify the owner when resume create is refused

* test(native-chat): consolidate transcript refusal cases

* test(native-chat): keep ownership coverage at the launch boundary

* test(native-chat): update adoption fixture for early ownership admission

* test(native-chat): align resume admission assertions with host ownership

* test(native-chat): keep RPC coverage focused on ownership proof

* test(native-chat): assert blank request presence before optional source

* fix(native-chat): admit the actual CLI source during chat creation

* fix(native-chat): satisfy source admission lint checks

* test(native-chat): provide the waiting hook prompt

* test(native-chat): isolate source admission fixtures from host homes

* test(native-chat): canonicalize adoption fixture directories

* test(native-chat): preserve early ownership admission in source stack

* fix(native-chat): preserve resume refusal behavior and honest transcript feedback

* fix(native-chat): retain import read evidence in typed result

* fix(native-chat): preserve admitted source and prepared execution home

* fix(chat): retain source evidence for dispatched adoption

* fix(chat): keep source capture within module limits

* test(chat): allow host evidence in create routing

* fix(native-chat): admit an unsaved transcript under a linked account folder

A missing transcript stayed unresolved while its account root resolved through
symlinks, so containment failed and a not-yet-saved conversation showed a load
error instead of the unsaved notice.

* refactor(native-chat): move the newest-item import window into its own module

Keeps journal-legacy-import.ts under the line limit after the source
identity observer landed on top of the streaming import.

* fix(native-chat): restore the refusal error import lost in the main merge

* fix(native-chat): admit Pi transcripts against the root Session History walks

A PI_CODING_AGENT_DIR that already ends in sessions, or any custom folder,
made admission expect <dir>/sessions while the lookup searched <dir>, so a
found conversation was refused.

* refactor(native-chat): admit and look up CLI transcripts in one store per account

Each agent's import described where an account keeps its conversations twice,
once for the path check and once for the lookup, and the two could disagree
(the linked-folder and Pi custom-root refusals). The import now names one
conversation store per account; the create path resolves it once and both the
hook-path check and the fallback lookup judge that same store. OpenCode's
store is its exact database.
2026-10-16 21:14:03 -07:00
OrcaWinandOrcaWin fa59ed0295 test: advance mocked OpenCode probe close timers (#29772)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-16 10:27:31 -07:00
Neil b16a71c7fb ci: reuse Windows hook builds and shorten test setup and shutdown (#29439)
* ci: remove Windows build and persistence test overhead

* ci: collect unit phase diagnostics during PR checks

* test(ci): seed hook reuse fixture from the canonical prebuild

The hook reuse regression first built into a missing private --output, so it
always reached Cargo (74s warm on Windows). Build through the default output
instead, which reuses a warm canonical prebuild, then copy its executable and
fingerprint into the private fixture root.

* fix(lint): clear inherited max-lines and broad object tab parameter after main merge

Combine the duplicate shared/execution-host imports in runtime-host-services
(301 -> 300 lines) and type the overlap test's tab mapper with the
RuntimeMobileSessionClientTab owner type instead of object.

* fix(ci): align inherited runtime and workflow contracts

* test: establish changed runtime probe signatures deterministically

* test: await asynchronous daemon profile cleanup

* test: shut down owned daemons before deleting profiles

* test: clean up oracle daemons during final app close

* test: recognize verified Linux zombie exit during daemon teardown

* fix: preserve folder SSH ownership when project groups conflict
2026-10-16 02:52:22 -07:00
Neil 3074852b7c fix(orcad): seal integration credentials on the headless server instead of storing them in plaintext (#29412)
* fix(orcad): seal integration credentials on the headless server instead of storing them in plaintext

The Node SecretStore always reported encryption unavailable, so every
credential writer on orcad fell back to plaintext. orcad now seals with
AES-256-GCM using a host-owned master key kept in the OS keyring (macOS
Keychain, Linux Secret Service) when reachable at first start, else in a
0600 profile file bound to the machine ID. A key that cannot load fails
closed instead of downgrading. Existing plaintext credentials are sealed
on startup without loss.

* docs: describe how the headless server seals credentials and its limits

* fix(orcad): unique credential staging files, no keyring items for temp profiles, isolate startup test

* fix(orcad): keep the credential key with the credentials, one record per machine

* fix(orcad): never re-key over an unreadable record, serialize first-start key creation, refuse an unrestricted key file

* fix(orcad): verify a key record's Windows ACL and wait out a concurrent first start's keyring write

* fix(orcad): keep a keyring claim and fail closed when its store result is uncertain

* fix(credentials): restrict the staged file's Windows ACL before it replaces a credential

* fix(orcad): a temporary profile never creates a key in, or re-seals, the real credential home

* ci: baseline the two single-file credential ACL restrictions

* fix(credentials): stage Windows credentials born restricted and verify the key record asynchronously; document rollback

* test(bitbucket): inject the write failure into the Windows staging writer too
2026-10-15 23:18:05 -07:00
OrcaWinandNeil 16eaceb6a3 fix(orcad): orca serve owns its Claude and Codex accounts again (#29209)
* fix(orcad): orca serve owns its Claude and Codex accounts again (#28962)

orcad never wired account services, so every accounts.* RPC failed once
orca serve moved onto orcad. Build the same account services the desktop
builds (now in provider-account-services.ts), made Electron-free, and
install them in orcad except on a WSL host, whose desktop owns its accounts.

* test(orcad): keep account-services test off the real userData when XDG_CONFIG_HOME is set

* fix(orcad): structured Codex chats and session discovery follow this host's managed accounts

Create orcad's account services before the runtime so its structured Codex launch/read resolvers and catalog-probe prep are constructor deps, as on the desktop. A client-sent account home still wins, and a WSL host keeps them unset so the desktop-pushed CODEX_HOME applies. AI Vault session discovery now includes this host's managed Codex homes.

* fix(orcad): automatic Codex resumes follow the account home their session was recorded in

Share the desktop's resume launch prep as a factory and wire it into orcad's PTY registration and AI Vault resume, so a pane restored after an account switch resumes from its origin home. A client-sent account home keeps resuming from itself.

---------

Co-authored-by: Neil <neil@stably.ai>
2026-10-15 17:38:52 -07:00
Neil 1a19671ec5 test: remove low-value coverage and shorten expensive fixtures (#29135) 2026-10-15 04:19:24 -07:00
Brennan Benson 941a0f2a8a fix(opencode): refuse a picked OpenCode model in any \\wsl$ repo (#28236)
OpenCode in a \\wsl$ repo runs in WSL whatever the project's setting, and Orca can't verify a
model there yet, so picking one is refused, as it already is for a project set to WSL, instead
of being checked on Windows.
2026-10-14 13:10:31 -07:00
Brennan Benson 76d1c68ab5 Resume in New Native Chat for OpenCode (#28072)
* feat(chat): Resume in New Native Chat for OpenCode terminal conversations

An OpenCode conversation started in the terminal now offers "Resume in New Native Chat" in its
Session History row menu and its tab's right-click menu, as Claude, Codex, Grok and OMP do: a new
OpenCode chat takes it over, showing its history and continuing it. OpenCode 2.x rows
(`opencode2`) and 1.x rows both open an OpenCode chat.

Two pieces kept OpenCode off the shared adoption path. Its account is a locator, not a folder, so
the transcript import now works over the account the chat pins, whatever its kind; the folder
agents wrap their lookups in directoryTranscriptImport, unchanged. Its conversations live in a
database, so the journal import reads the found database with the reader the OpenCode transcript
view already uses. OpenCode refuses to reopen a session from another folder, so the workspace rule
covers it too.

* test(chat): Pi is now the agent with no transcript import

* fix(chat): find an OpenCode 2.x terminal tab's Session History row

The pane reports `opencode` while Session History lists the conversation as `opencode2`, so the pane
header's and tab menu's Resume in New Native Chat found no row. Match by the chat agent that takes the
conversation over.

* Fix OpenCode chat adoption environment and pane eligibility

* test(chat): adapt parent adoption fixtures to account identities

* test: keep only the tests that pin user-visible behavior

* refactor(chat): map a Session History row to its chat agent where the chat starts

Both Resume in New Native Chat callers repeated the row-to-chat agent lookup. The launch now
takes the row agent and maps it once, so the Session History actions file stays unchanged.
2026-10-14 00:25:08 -07:00
Brennan Benson 26a265d704 Host plans agent launches with the window's runtime rule and one runtime fact (C1) (#27692)
* feat(agent-launch): host plans agent launches with the window's runtime rule and one runtime fact

Host-started agent launches now pick their platform with the same rule the
window uses (project runtime, else a \\wsl$ path, else the host), and resolve
one runtime fact that supplies both the command quoting and the PTY shell.
Adds the agent.launch.terminal-inputs.v1 capability and its optional
title/extraAgentArgs/requestKind/terminalOnly fields; no sender yet.
OpenCode's createAgentSession stays on today's rules until C2 (temporary).

* fix(agent-launch): one shared runtime rule, a derived fact, and only quoted commands carry it

Round-1 review fixes for C1:
- Window and host read a workspace's runtime through one shared resolver
  (local-workspace-execution-runtime.ts); a repo-less \\wsl$ folder gets no
  runtime, as in the window.
- The fact is { platform, remote, pty } with the spawn's own PTY type; the
  quoting shell is derived from it, never stored.
- createAgentSession uses the same fact (its pre-C1 exception is deleted).
- Worktree startups quote from a fact for the repo and pass it on; a runtime
  that needs repair fails the startup, not the create. `shell` is required
  when building a launch command.
- The host planner stamps a fact only on commands quoted with it; a
  caller-quoted command keeps the spawn's own rule.
- Qoder probes where the process runs (\\wsl$ cwd, then a WSL shell).
- wslShellRule 'host-legacy' keeps today's WSL-shell outcome where no
  project chose a runtime (temporary, removed by C8).
- terminalOnly reaches the early-tab decision with an accurate receipt
  sentence; the unused client gate is removed.
- Adds one host C0 row for a \\wsl$ repo with no saved runtime.

* fix(agent-launch): round 2: keep request fields for C2, extend main's resolver, one answer per workspace

Problem: the first round still carried request fields and window-parity
switches that only the next step sends, added a new shared resolver that
also changed window code, and left some background launches using a
different runtime answer than the one they spawn with.

- Move the agent.launch request fields, their capability and fingerprint
  handling, and the prompt/Codex parity switches out to the next step;
  today's host behaviour is kept.
- Drop the shared resolver: main's resolveLocalWorkspaceRuntime now finds
  the project by repo id or source repos, folders borrow their single
  local repo, and a \\wsl$ path is not refused on a stale distro list.
  Window code is back to main.
- Agents started in an existing worktree use that worktree's answer; the
  phone's fallback paths spawn with the answer they quoted for, and a
  runtime that needs repair shows its message instead of a plain shell.
- The OpenCode model check looks where the agent will run.
- A Windows --shell in a \\wsl$ workspace names the path, not a runtime
  setting that cannot change it.
- The temporary folder rule names its follow-up, STA-10231.

* fix(agent-launch): OpenCode model picks in WSL folders keep today's Windows runtime

Problem: once a folder follows its repo's WSL runtime, an OpenCode launch
that picks a model would be checked and started inside WSL, where Orca
cannot yet verify OpenCode models, so picks that work today could be
refused.

Where main had no runtime for the scope (only folders), a model-picked
OpenCode launch keeps main's answer. Start, resume and the worker's model
check read the same answer. Temporary until OpenCode models are verified
inside WSL.

* fix(agent-launch): round 3: OpenCode keyed on the agent, new worktrees quoted for where they land

Problem: round 2's OpenCode exception keyed on a model pick, so a resumed
chat could run somewhere other than where it started, and the worker's
model check read WSL from the Terminal shell and refused folders that work
today. A new worktree's startup used the repo's answer even when the
worktree lands in a WSL share.

- In a folder whose repo runs in WSL, every OpenCode launch keeps main's
  Windows answer: create, resume and the worker's model check agree. The
  model check reads WSL from the path alone, as main did. STA-10251.
- A new worktree's startup is planned for its WSL-share base folder when
  one is set (newWorktreeLaunchScope).
- A \\wsl$ working directory runs in WSL whatever the project says, so
  non-OpenCode agents there are written for Linux.
- The planner test derives the answer instead of passing it in.
- Smaller shapes for the PTY settings type, the cache-less resolve,
  executionRuntimePlatform, spawnShellInputs and two comments.

* fix(agent-launch): round 3c: one labelled rule for where the path decides; OpenCode follows the WSL-share fix

Problem: OpenCode in a repo on a WSL share whose project is saved as
Windows host still got PowerShell quoting typed into WSL, because the
WSL-share fix skipped OpenCode. The fix and the two temporary parity
rules were also split across two returns, so deleting the temporary
ones could take the permanent fix with them.

- One expression decides when the path places the agent, each term
  labelled: WSL share + Windows host (permanent fix), folder + Windows
  host (STA-10231), OpenCode in a folder (STA-10251).
- OpenCode now gets the WSL-share fix too; a model pick there is refused,
  as main's model check already did.
- The OpenCode entry-point tests set a WSL Terminal shell, so the model
  check test fails if it reads WSL from that shell again.
- Tests trimmed with no coverage loss; the spawn-precedence unit test is
  dropped (the C0 WSL-share row covers the reachable case).

* fix(agent-launch): keep the window's WSL answer for panes the window spawns

Live Windows QA (Terminal shell wsl.exe, global default Windows host, repo
with no project setting) saw an agent command written with PowerShell
quoting typed into a WSL pane, so codex lost the apostrophes in its prompt.
The host wrote the command for its own answer (Windows, PowerShell), but on
routes where the window spawns the pane (the phone while a window is open,
a focused desktop chat create, `orca terminal create --command` in a repo)
the window spawned it by the Terminal shell, which is WSL. Quoting and the
pane came from two different answers.

Those routes ran in WSL with Linux-style quoting on main and worked, so the
temporary host-legacy term (STA-10231) now also covers them: when the window
spawns the pane, the path and Terminal shell decide, as on main. Background
routes keep the approved change (PowerShell instead of cmd.exe with
Linux-style quoting, which was broken on main). createTerminal and the
pre-launch planning share one `windowSpawnsTerminal` rule so they can't
disagree about who spawns the pane.

* Revert "fix(agent-launch): keep the window's WSL answer for panes the window spawns"

This reverts commit 3e4311db19.

* fix(agent-launch): report a runtime that needs repair as a refusal, not an unknown outcome

`orca agent launch` into a folder whose one repo is set to a WSL distro that
is no longer installed printed "Orca could not confirm the launch outcome;
the agent may already be running", although nothing had started. The host
knew the launch was refused before any spawn, but the refusal went out as
the generic `runtime_error`, which the CLI must treat as possibly started.

The launch planner now raises that refusal under its own code,
`project_runtime_repair_required`, with the same message, and the RPC layer
passes the code through. The CLI then prints the repair message as a plain
failure. Older CLIs read the unrecognised code as a failure too; a newer CLI
against an older host still gets `runtime_error`, as before.

* fix(agent-launch): say a repair refusal in plain words, and repeat them on a retry

The repair refusal from the last commit read "Project runtime requires repair
before terminal spawn: wsl-distro-missing", an internal reason code rather
than what happened and what to do. It now says, for example, "No agent was
started. Ubuntu is not installed in WSL. Choose an installed distro or switch
this project to Windows.", adding "This project follows the default in
Settings > Project Runtime." when the runtime came from the default.

Those sentences are the project settings page's own. They now live in one
shared module that maps each repair reason to the page's existing
translation key; the settings page passes its translator, and the host writes
English, since it also runs headless where the desktop's translations can't
load. The planner checks for a repair before the shell lookup, so the shared
spawn message, which window spawns still use, is untouched.

A retried launch (`--retry-launch`, or a phone resend) used to answer with
the bare error code. The failed launch record now keeps the refusal's words
and the retry repeats them.

* fix(agent-launch): test that a retry repeats a refusal's words, and keep the host's English equal to the window's

A retried launch now repeats a coded refusal's own words, but nothing tested
it. A new case refuses a launch with a coded error and checks the retry
answers with the same words.

The repair sentences live in one shared module whose English the host
writes and whose keys the settings page translates. The localization checks
can't see call sites outside the window and main, so the module's test now
checks each sentence against the window's English catalog for its key.

Smaller, behaviour-identical tidy-ups: the reason-to-words mapping is a
table, the refusal type fits on one line, and the length cap the retry
words share with folder refusals has a neutral name.

* refactor(agent-launch): keep main's behaviour where the stacked fixes change it

The repair refusal's own code and words, the \\wsl$ path's distro in the agent list,
--shell refusals for agents (decision and words), OpenCode's model check in a \\wsl$ repo,
and finding a repo's project by its id move to their own stacked PRs. Until they land,
each keeps main's behaviour with temporary code and a test that pins it.

A disabled agent is refused as disabled before its runtime is looked at again, as on main.

* fix(agent-launch): keep main's folder agent list when only the group names another host

The agent list for a folder reads the folder's own host pin, as on main; only launches also
read the containing group's host tag.

* ci: re-run checks now that main's capacity-capture replay fix (#28286) has landed

* test(agent-launch): give main's account-env startup test the launch runtime its build now returns
2026-10-13 15:00:32 -07:00
Neil 7246a0e269 Fix delayed agent launches such as sleep 30 && claude (#28205)
* fix(terminal): preserve preparation and discovery for delayed agent launches

* refactor(agents): centralize launch intent recognition

* refactor(agents): keep launch intent in one module apart from process recognition

Move recognizeAgentLaunchCommand next to the sleep-prefix scanner so the strict
process-table matcher is untouched, name the module away from the agent-launch
funnel files, share one executable-name normalizer, and colocate the
preparation tests with their modules.
2026-10-13 01:55:18 -07:00