Commit Graph
42 Commits
Author SHA1 Message Date
Jinwoo Hong 573537ecd4 feat(cli): make terminal close the canonical workspace teardown (#18073)
* fix(runtime): recover stale session owners and await retirement

* fix(runtime): preserve session hydration and smoke compatibility

* test(runtime): cover empty and unindexed session owners

* feat(cli): make terminal close the canonical workspace teardown

* fix(preload): align ssh termination result type

* test(runtime): assert folder hydration owner

* fix(runtime): fence legacy terminal stop by worktree host

* fix(preload): reconcile ssh result import with main

* fix(runtime): keep same-id sibling hosts out of workspace close

The stale-owner fallback in the session controller re-routed any worktree whose
catalog partition had no tabs to whichever other partition held tabs. Only
`runtime:` environment ids rotate across relay restarts; `repoId::path` legitimately
repeats across hosts, so an SSH workspace close could retire the local copy's
tabs and resume records, or flip owners mid-close and strand the SSH PTY.

Restrict the fallback to runtime hosts, and pin the session partition once per
workspace close so record clearing targets the partition that owned the tabs.

* test(runtime): give the cross-host close fixture a real resume record

* fix(preload): take main's ssh-bridge import order so the merge stays duplicate-free
2026-09-03 03:58:45 -04:00
Jinwoo Hong b44ef1e59d fix(skills): narrow computer-use discovery boundary (#17736)
* fix(skills): narrow computer-use discovery boundary

* chore: remove merge-formatting noise

* fix(skills): name browser page automation surfaces
2026-08-31 18:57:52 -04:00
NeilandBrennan Benson fbe94ceff6 fix: close readiness gaps found by merged-change audit (#17159)
* fix(ssh): fence stale kills and retired pane replay

* fix(ssh): support cancellable interactive authentication

* fix(ssh): await remote catalog before snapshot adoption

* fix(pty): contain Windows ConPTY input failures

* fix(power): avoid redundant macOS display blocking

* perf(editor): narrow markdown override subscriptions

* fix(quick-open): close directory handles after reads

* refactor(linux): remove unused proc socket scanner

* fix(usage): apply flat Sonnet 4.6 pricing

* ci: prime Node next native test cache

* docs(skills): resolve snapshot cleanup data path

* fix(ssh): recover install locks after host reboot

* test(ssh): recognize boot-aware install locks

* test(ssh): prove previous-boot lock recovery live

* test(wire): pin pre-metadata release coverage

* fix(terminal): preserve remote tab ownership through recovery races

* test(runtime): fence replaced terminal handles in agent guard

* fix(ssh): preserve remote snapshot authority across polls

* fix(pty): contain late ConPTY output EPIPE

* test(pty): register Windows exit watcher before kill

* fix: close SSH and tab readiness race gaps

* fix(tabs): retain headless order and placeholder titles

* fix(build): avoid parallel electron-vite config race

* test(windows): avoid MSYS temp path rewriting

* test(windows): avoid killing exited PTY

* fix(pty): avoid late ConPTY input teardown race

* fix(terminal): sync reconnect error ownership after commit

* fix(runtime): use canonical worktree identity comparison

* test(ssh): assert complete cold-hydration baseline

* test(windows): invoke quoted retention fixture via PowerShell

* test(windows): read ConPTY grid through mode con

* fix(terminal): publish PTY replacements atomically

* fix(terminal): infer stale identity on reattach

* fix(terminal): fence stale pane PTY callbacks

* fix(terminal): fence stale pane binds after rebind

* fix(terminal): reject stale pane transport callbacks

* fix(terminal): fence mirrored reattach spawn callbacks

* fix(terminal): replace stale pane PTYs on remount

* fix(ci): size the Windows launcher-compile test budget from measurement

`native-smoke (windows-latest)` fails ~4.5% of runs on
`preserves a multiline argument through the compiled remote launcher`
with "Test timed out in 15000ms" — on unrelated PRs, for reasons that
have nothing to do with them. Across 176 sampled attempts it is the only
red that job produced, and it hit seven different PRs in two days:
#16900, #16904, #16915, #16955 (twice), #16979, #17014, #17085.

The test is six process creations: powershell.exe forks csc.exe, then
the freshly compiled orca.exe forks node.exe, twice. Hosted Windows
runners periodically slow process creation down, and this test amplifies
that far harder than anything else in the job. Comparing the 80 attempts
where it ran under 3s against the 12 where it ran over 12s, its own
median goes 2198ms -> 15917ms (7.2x) while the same file's
powershell-only test moves 556 -> 686ms (1.2x), the cmd.exe and Git Bash
process tests in the neighbouring file move 1.4x, and the other 35 files
put together move 1.5x.

Measured across those 176 attempts: 1881ms to 35438ms, p50 4264ms,
correlation +0.881 with the job's total Vitest duration. 8 of 176 (4.5%)
exceeded the 15s cap; 2 of 176 (1.1%) also exceeded the shared 30s
testTimeout, so deleting the override and inheriting the config is not
enough on its own. 60s clears all 176 with 1.7x headroom on the worst.

This is slow, not hung. Every body here is synchronous spawnSync, so
Vitest cannot interrupt one — the timer fires only after the body
returns and the reported duration is real elapsed time. That is why a
failure reads `× ... 22464ms` under `Test timed out in 15000ms`. The
work finished; the stopwatch was short. Seven reruns at one identical
head measured 2053 / 4680 / 5551 / 8732 / 13506 / 14868 / 21937ms — the
last of those would have been red on code that had not changed.

The 15s came from #8897, which raised this test off Vitest's built-in 5s
default because the job then ran bare `pnpm vitest run`. #8909 landed
3h27m later and pointed the job at config/vitest.config.ts, which is the
real fix for that. The constant stayed behind and has been the binding
budget ever since.

* fix(terminal): fence stale remount reattach ownership

* fix(terminal): reconcile mounted pane identity after replacement

* fix(terminal): fence stale reattach fallback ownership

* fix(terminal): fence deferred SSH reattach ownership

* fix(terminal): fence stale split pane ownership callbacks

* fix(terminal): keep stale spawns from consuming startup

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-08-31 08:17:40 -07:00
Brennan Benson cc6b600e21 Fix orchestration CLI recovery, settled-Dispatch mail, and guide defects (#16919)
* Fix orchestration CLI recovery, settled-Dispatch mail, and guide defects

Five reported orchestration CLI defects, verified individually before fixing.
Two were real code defects, one was a docs error, one was correct as-is, and
one was correct on both ends except for its recovery wording.

- Mail addressed to a settled `dispatch:<id>` was accepted and silently dropped.
  Local sends bypassed the settlement check the federated branch already had, so
  the caller was told success for a delivery no worker would ever read. Reject
  with `dispatch_inactive` and name the Run mailbox to use instead.

- A lost mutation response offered no read-only way to ask whether it took
  effect. `--retry-request` does dedupe correctly, but the recovery guidance
  emitted a query command only when the payload carried a dispatch id, which is
  exactly what a lost response lacks. Add read-only
  `orca orchestration request-show --request <id>` over the durable receipt
  ledger, and always emit a read-only step before the keyed retry.

- The bundled `orca-cli` guide documented `check --unread --inject`, a flag the
  parser rejects. Correct it to `--format` and add a ratchet that runs every
  orchestration invocation in the bundled guides through the real CLI parser.

- `check --json` is one stdout document and its keepalives are stderr-only; the
  reported `Extra data: line 2` came from merging the streams. Document the
  contract rather than changing the wire.

- A rejected lifecycle message is loud on both ends already, but the rejection
  never named the flag that supplies the missing capability. Name it.

* Harden orchestration mutation recovery guidance
2026-08-30 18:12:58 -07:00
Neil 2b0ee06205 docs(env-recipes): warn that snapshotting a started runtime bakes its identity (#17001)
Snapshotting a VM on which `orca serve` has already run captures the
runtime's user-data dir into the image. Every VM booted from that image
then shares one pairing identity and one agent-session-authority key,
which defeats the per-device token design.

Confirmed by booting two VMs from one such snapshot: both emitted
identical deviceToken and pairedDeviceId.

Adds the rule to the base-snapshot section and repeats it for the
agent-auth layer, which is the likelier place to start the runtime by
hand while smoke-testing. Says to delete the whole user-data dir rather
than a named file list, since that list drifts as Orca adds state.
2026-08-28 02:37:55 -07:00
Jinjing c4b39295c1 style: format codebase (#16935)
* style: format codebase

* style: format codebase

* refactor: extract skill install dialog footer and content

Extract footer and content sections from SkillInstallDialog and
SkillInstallManagementDialog into separate components for improved
maintainability and clarity of component responsibilities.
2026-08-28 00:59:21 -07:00
Brennan Benson 9135b6f004 feat(orchestration): surface nested worker depth and propagate it across hosts (#16669)
* feat(orchestration): surface nested worker depth and propagate it across hosts

Builds on the depth enforcement in the previous commit, which shipped with the
setting reachable only by editing settings.json and with workers never told they
could nest.

Adds the Settings -> Agents control (a 1/2/3 select rather than a free-form
number, which bounds the value without inventing a numeric input primitive). The
key stays absent from the SettingsUpdate RPC schema, matching agentSkillSharingEnabled:
settings.update is reachable from the CLI, so an RPC-writable depth would let a
worker raise its own cap.

Adds a SUB-DISPATCH block to the dispatch preamble, emitted only when the worker
actually has budget left. A worker told it "usually cannot" delegate still tries and
then reports the refusal as a blocker, so the section is omitted entirely rather
than softened.

Propagates depth to federated worker hosts. Previously the home side computed and
stored a depth the remote host never received, so a remote attachment always read
as depth 1. That is correct at the default cap and wrong as soon as the cap is
raised — precisely when someone starts relying on nesting. The field is optional,
so an older Run home simply omits it and the attachment's NOT NULL DEFAULT 1 keeps
the fail-closed behaviour. Enforcement still runs on the executing host against
that host's own cap, consistent with the SSH execution boundary.

* fix(orchestration): close nested depth readiness gaps

* fix(settings): defer nested depth translations

* fix(orchestration): drop federated depth keys that main already landed

The enforcement PR's review pass added the same federated depth propagation
before it merged, so replaying this branch onto main produced duplicate object
keys. Keep main's versions -- its schema entry validates an integer >= 1 rather
than any finite number.

* fix(settings): label nested worker depth select

* fix(settings): move nested depth to orchestration

* fix(settings): refine nested depth placement
2026-08-26 16:16:05 -07:00
Brennan Benson 8a07bbd8cf fix(orchestration): enforce nested worker depth instead of an accidental fence (#16668)
* fix(orchestration): enforce nested worker depth instead of an accidental fence

Orca documented that "dispatched workers cannot spawn their own sub-workers
(worker-start is coordinator-fenced)". No such check existed. What existed was a
single Run-binding check in the workerStart RPC: a worker's terminal is not bound
to a Run, so worker-start happened to fail. The rule was emergent, asserted by no
test, and written in no doc — and it leaked. A worker could run-create its own
Run, task-create, and worker-start: now bound, the check passed.

Replace it with a real, configurable depth cap.

Depth is derived from the caller's own active Dispatch rather than from Run
binding, which is what dissolves the run-create bypass: creating a Run does not
stop you being a worker. Enforcement lives in a single dispatch-row writer that
owns all three INSERTs that mint a live worker — the generic claim, the supervised
worker-start path (including every retry), and the remote attachment. Two of those
were missed by earlier drafts of this change, so `creator` and `maxDepth` are
required parameters: a new spawn path cannot compile without deciding, and a
boundary test refuses the SQL anywhere else.

Schema v30 adds depth to dispatch_contexts and remote_dispatch_attachments,
NOT NULL DEFAULT 1 and backfilled to 1 so an unstamped or pre-upgrade row fails
closed rather than reading as a root coordinator. The attachment pane indexes
widen to the five states in which a remote worker may still be running:
loss of contact is not evidence of process death, so an unverifiable worker still
counts as a nesting parent.

Also adds the caller-evidence assertion that workerStart was the only Run-scoped
verb to skip, so a declared --from cannot name another terminal's pane and inherit
its depth.

Default is 1, so behaviour is unchanged unless the new setting is raised. Two
limitations are deliberate and documented rather than papered over: this is a
guardrail and not a security boundary, since a caller whose launch evidence is
unverifiable (any ordinary restored terminal) can declare another handle; and it
is enforced at supervised dispatch creation, so a settled worker whose process is
still alive counts as a root again.

* fix(orchestration): share caller resolution and pin worker gaps

* refactor(orchestration): make the caller resolver's pane contract explicit

Overloads so requireStablePane callers get a non-null string instead of casting,
and rename the attestation opt-out to say what it means: the caller asserts it
itself. A flag called assertEvidence:false reads as "attestation optional",
which is the hole this helper exists to close.

* fix(orchestration): propagate dispatch depth to federated workers

* chore(cli): refresh bundled orchestration guide
2026-08-26 13:22:09 -07:00
Jinwoo HongandJinwoo-H a9781a4118 STA-4150: client-hosted remote browser (consolidated) (#15448)
Co-authored-by: Jinwoo-H <jinwoo@stably.ai>
2026-08-25 15:36:51 -07:00
Brennan Benson 3fca1d1648 fix(linear): unbound list-issues by default, surface truncation, bind cursor workspace (#15824)
Fixes STA-5076.

list-issues capped at 50 by default and hard-clamped at 250, with hasMore buried
under result.meta and no stderr warning for --json, so a page that stopped early
read as a complete answer. Omitting --limit now walks Linear's pages until they
run out (meta.limit is null), and --limit <n> is the only cap, paging past
Linear's 250-per-request maximum to reach it. result.truncated sits next to
result.issues and is set only when a cap actually held results back; human output
prints "truncated: showing N".

The read still has to fit the CLI's 60s RPC budget, so a 20s wall-clock deadline
and a 200-page ceiling stop the walk early and report truncated with a
continuation cursor rather than failing the command.

Also:
- issued --cursor values bind the resolved workspace, so call -> nextCursor ->
  call works without --workspace; raw Linear cursors still need one and now carry
  nextSteps
- issued cursors whose payload smuggles back `all` or an empty workspace are
  rejected at decode, since either would widen the read past the bound workspace
- JSON issue rows carry priorityLabel (none/urgent/high/medium/low), matching
  orca linear priority set
- truncated and priorityLabel are optional on the wire, so a host that predates
  either is not read as "complete"; readers fall back to meta.hasMore
- the truncation line prints the rows actually rendered, so a remote result with
  no meta.returned cannot print "showing undefined"
2026-08-21 14:28:55 -07:00
Brennan Benson 2a760e310b fix(computer): report unasserted accessibility actions (#15028)
* fix(computer): report unasserted accessibility actions

* fix(computer): fail closed on missing action metadata

* Fix merged tab search test fixture
2026-08-18 11:29:26 -07:00
Brennan Benson fc8b92e507 docs(computer): explain screenshot file requirements (#15054)
* docs(computer): clarify screenshot output requirements

* fix(cli): do not advertise an unshipped --probe flag

The capabilities help line referenced --probe, which does not exist yet;
it ships in a later change. Advertising it here would be false until then.

* fix(cli): align computer-use screenshot guidance

* docs(computer): document inline screenshot fallback

* docs(computer): keep screenshot summary accurate

* docs(computer): keep screenshot guidance general
2026-08-18 01:18:56 -07:00
Jinwoo Hong 0bedeea642 fix(orchestration): expose unsupervised dispatch lanes (#15105) 2026-08-17 13:53:26 -07:00
Jinwoo Hong fa9b20cb41 feat(skills): reland private bundle sharing safely (#14934) 2026-08-16 13:45:54 -07:00
Jinjing 763b1febeb Revert "feat(skills): add private bundle sharing (#14401)" (#14913)
This reverts commit 757fae28d7.
2026-08-16 10:39:57 -07:00
Jinwoo HongandE2E Test 757fae28d7 feat(skills): add private bundle sharing (#14401)
Co-authored-by: E2E Test <e2e@test.local>
2026-08-16 02:36:18 -07:00
Brennan Benson 66dfdc456f feat(computer-use): support macOS middle click and stop the silent left-click fallback (#14721)
* feat(computer-use): support macOS middle click and gate the AX click path

`--mouse-button middle` already validated end-to-end through the CLI, the
zod schema, and the provider validator, and both the Windows and Linux
providers honored it. Only the macOS provider rejected it outright with
"middle-click is not yet supported", so the flag was a dead end on the one
platform that has no fallback.

Two changes:

- Add `.middle` to the macOS button mapping. macOS has no dedicated middle
  event family, so it rides `otherMouseDown`/`otherMouseUp` with the button
  number carried by `mouseButton: .center`; that constructor argument is
  honored for exactly the `otherMouse*` types, so no extra field write is
  needed.
- Validate the requested button before the accessibility fast path, and skip
  that path for buttons it cannot express. Previously the raw string was read
  unvalidated, and `performClickAction` only special-cased `right`, so
  `click --mouse-button middle --element-index N` (no modifiers, count 1) fell
  through to `AXPress` — a left click — and reported success with
  `path: "accessibility"`. Any unrecognized button string did the same. This
  matches guards the Windows and Linux providers already had.

The button enum moves into `OrcaComputerUseMacOSCore` so it is unit-testable;
`main.swift` keeps only the CoreGraphics mapping.

Also documents `--mouse-button` in the computer-use skill guide, which never
mentioned the flag, so agents on Windows and Linux had no way to discover it.

* test(computer-use): cover macOS middle click in the real-desktop e2e suite

* test(computer-use): prove macOS middle-click delivery
2026-08-15 00:41:45 -07:00
Jinwoo Hong 500b72d8ef fix(vm): harden provisioned root ownership and cleanup (#14477)
* fix(vm): verify provisioned root ownership

* test(vm): retry transient removal menu

* test(vm): stabilize provisioned root teardown

* fix(vm): clarify recipe-owned cleanup

* fix(vm): pin provisioned root source commit

* fix(vm): make runtime cleanup user-cancellable
2026-08-14 19:04:55 -04:00
Jinwoo Hong 77b37d85e2 feat(vm): create workspaces from provisioned SSH roots (#14359)
* feat(vm): use recipe-provisioned SSH roots

* fix(vm): preserve ordinary create failure timing

* test(vm): prepare provisioned root SSH fixture

* ci(vm): enable SSH setup for provisioned root E2E
2026-08-13 16:23:22 -07:00
erishandJinwoo-H 1f4b731f7c fix(skills): use exported recipe id in environment guide (#14280)
* fix(skills): use exported recipe id in environment guide

* fix(skills): keep recipe-derived Vercel names valid

---------

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
2026-08-13 14:18:57 -07:00
Brennan Benson cbca291aa7 fix(orchestration): preserve direct user authority after worker_done (#14192)
* fix(orchestration): preserve direct user authority

* test(orchestration): assert settled dispatch boundaries
2026-08-13 12:00:04 -07:00
Jinwoo Hong d349f9a972 Use provider-neutral Opus alias in orchestration guide (#14119) 2026-08-12 16:03:29 -07:00
JinjingandOrca 3ec48a74d5 Gate artifact publishing behind off-by-default capability (#13368)
* fix(artifacts): gate agent artifact publishing behind an off-by-default capability

Public artifact sharing was reachable by any agent through `orca artifacts
share`: the Artifacts settings toggle only controlled sidebar visibility, and
nothing in the main process checked a capability before minting a public URL.

Add `artifactSharingEnabled` (default off) and enforce it in
ArtifactCloudService.share/update — before auth, network, or the share-record
write — so the CLI, relay-forwarded remote CLI, and IPC paths are all denied.
The denial carries a stable `artifact_sharing_disabled` code plus next steps
through the RPC error allowlist, so the CLI prints actionable guidance.

list, unshare, and delete stay ungated: turning publishing off must not strand
already-published links. The capability is absent from the `settings.update`
RPC schema, so an agent cannot grant it to itself — only the desktop UI can.

Co-authored-by: Orca <help@stably.ai>

* fix(artifacts): gate agent artifact publishing behind an off-by-default

Publishing is blocked until enabled in Settings → Artifacts. CLI preflights the capability before reading files to avoid unnecessary uploads. RPC surface rejects capability grants so callers cannot self-grant. UI shows opt-in workflow and recovery path when publishing is off. Web clients mirror the host's setting read-only.

---------

Co-authored-by: Orca <help@stably.ai>
2026-08-09 13:19:08 -07:00
Jinwoo Hong c991bb27d3 Add account-backed artifact sharing (#13012) 2026-08-07 23:02:29 -07:00
Jinwoo Hong b0ba51831c Add per-worker model and effort overrides (#12851) 2026-08-05 21:17:45 -07:00
Brennan Benson 39c3c58d55 perf(runtime): gate terminal.list visual layouts (#12450)
* perf(runtime): gate terminal.list visual layouts and stop the false writable claim

visualLayouts is ~31% of a large terminal.list payload (44,208 B of 137,412 B on a live 134-terminal remote runtime) and has exactly one consumer: the human-readable CLI formatter. Gate it behind an includeVisualLayouts request param that defaults to included, so pre-flag clients are unaffected, and have every --json/internal caller opt out.

Also drop the record-backed builder's writable, which was a verbatim copy of connected. terminal.show now states writability explicitly as exactly what terminal.send's PTY gate enforces.

* test(runtime): type the payload-size fixture arrays for tsc

* fix(runtime): preserve terminal list compatibility

* test(runtime): guard terminal list optimization

* fix(cli): preserve agent access to terminal layouts
2026-08-04 17:50:52 -07:00
Brennan BensonandOrcaWin f4b2b782b5 feat(orchestration): coordinator-driven release of settled worker terminals (STA-905) (#12355)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-08-03 17:17:26 -07:00
OrcaWin 9a2676023c fix(orchestration): prefer current authority over legacy fallback (#11737) 2026-07-31 01:56:13 -07:00
Neil d0f341ad69 fix(computer-use): make modifier clicks interruption-safe (#11451)
* fix(computer-use): make modifier clicks interruption-safe

* fix(computer-use): pace modified Windows multiclicks

* fix(computer-use): address modifier safety review
2026-07-29 18:29:10 -07:00
Neil 78b8a37aed fix(cli): keep automated worktree creation in background (#11445) 2026-07-29 17:45:57 -07:00
OrcaWinandOrcaWin 363e478909 fix(orchestration): preserve active workers across updates (#11271)
* fix(orchestration): preserve active workers across updates

* test(ssh): model absent legacy adoption

* test(orchestration): align compatibility contracts

* fix(windows): escape updater PowerShell booleans

* fix(windows): restore stock uninstall process check

* fix(orchestration): keep recovery off renderer startup barrier

* fix(orchestration): harden legacy recovery migration

* fix(orchestration): close recovery review gaps

* fix(orchestration): complete legacy worker cutover recovery

* fix(orchestration): preserve legacy workers across updates

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-29 11:31:35 -07:00
OrcaWinandOrcaWin 77d4c64f7a Improve orchestration migration safety for live legacy workers (#11107)
* fix(orchestration): clarify legacy migration safety

* fix(cli): sanitize legacy formatted messages

* test(runtime): allow near-cap fuzz under shard load

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-07-28 00:36:25 -07:00
OrcaWin cd05f2ff93 Implement robust orchestration primitives and connected-server workers (#9925) 2026-07-27 12:31:37 -07:00
Jinjingand5Hyeons 4a9affd6e5 fix(emulator): iOS ax via plain-JSON serve-sim helper (supersedes #10007) (#10029)
* Revert "Enable accessibility tree (`ax`) command on iOS emulator sessions (#10007)"

This reverts commit 43ae014a64.

* fix(emulator): expose iOS accessibility tree

* fix(emulator): support device-only iOS AX

* fix(emulator): normalize iOS ax to 0..1 and heal missing axUrl

serve-sim's helper /ax reports element frames in absolute pixels, but
tap/gesture take normalized 0..1 coords. Normalize the raw AX node tree
into a compact nested shape whose frames are 0..1 over the device screen
(first root's frame), mirroring serve-sim's own normalizeAxTree, so agents
can feed ax output straight back into input commands.

Also heal sessions that were registered without an axUrl: #9924 only
derived /ax at parse time, so already-active sessions had no endpoint.
The bridge now derives it from the session's mjpeg stream URL, guarded to
the /stream.mjpeg suffix so a non-mjpeg URL never fabricates a bogus /ax.

* docs(emulator): mark ax working on iOS with correct raw-AX-tree shape

Both skill guides and the CLI summary described iOS ax as unsupported (or,
via the reverted #10007, as a normalized "screen + elements" shape that
never matched the endpoint). ax works on both backends: Android via
uiautomator, iOS via the serve-sim helper. Document the real iOS output —
a raw AX node tree (labels, roles, nested children) with frames normalized
to 0..1 — and regenerate the bundled skill guides.

* chore(skills): regenerate skill bundle manifests

CI verify failed because generated skill artifacts were stale after version/skill revision bumps.

* fix(emulator): read ax from explicit device without active session

Fall back to udid-keyed session lookup when a worktree has no active emulator,
allowing `--device` targeting to work the same way for ax as it does for tap/type.
Also clarify in docs that AX frames are normalized 0..1 with top-left origin,
and show how to tap an element at its frame center (x+width/2, y+height/2).

* fix(emulator): cap iOS AX tree at 500 nodes

Unbounded accessibility trees can flood agent output. Enforce a 500-node limit (matching serve-sim's snapshot cap) and mark truncated parents so consumers know the tree was cut.

---------

Co-authored-by: 5Hyeons <ohs2251@naver.com>
2026-07-22 21:30:53 -07:00
Jinjing 43ae014a64 Enable accessibility tree (ax) command on iOS emulator sessions (#10007)
* Enable accessibility tree (`ax`) command on iOS emulator sessions

Fetch the accessibility tree from serve-sim's /ax endpoint, which requires an
active session but provides the same UI snapshot capability as Android's
uiautomator output. Derive the endpoint from the stream URL when not explicitly
provided by the helper, and route through the bridge to pass session context to
the backend.

* Add ax command routing and backend integration tests

Tests verify accessibility tree routes through EmulatorBridge,
Android backend ignores iOS-specific ax URLs, and ax endpoints
are derived from serve-sim stream URLs.
2026-07-22 17:10:54 -07:00
Brennan Benson 1a9e819c40 feat(skills): land remaining hybrid stubs (#9846)
* feat(skills): land remaining hybrid stubs

* fix(build): exclude skill stub sources from packages
2026-07-22 11:43:01 -07:00
Brennan Benson a10a2ba53c feat(linear): add MCP-style save issue (#9670)
* feat(linear): add MCP-style save issue

* fix(linear): harden save issue parity

* fix(linear): close save issue contract gaps

* docs(linear): bundle project discovery with save issue
2026-07-21 13:25:22 -07:00
Brennan Benson 87af1c8673 feat(linear): add complete issue relations (#9674)
* feat(linear): add complete issue relations

* fix(linear): harden relation reads and writes

* fix(linear): classify ambiguous relation writes
2026-07-21 13:21:19 -07:00
Brennan Benson 42a4f017b4 feat(linear): add MCP-compatible issue listing (#9672) 2026-07-21 13:16:44 -07:00
Brennan Benson be066fe8e9 feat(linear): expose issue activity history (#9667) 2026-07-21 13:13:05 -07:00
Jinjing a6df23c762 Tighten orchestration worktree isolation policy (#9482)
* docs(orchestration): require true isolation for worker worktrees

* docs(orchestration): deduplicate parallel worker guidance

* docs(orchestration): clarify isolation exceptions

* docs(orchestration): clarify checkout preference

* Tighten orchestration worktree isolation policy guidance

- Clarify that same-worktree workers remain orchestration children
  despite appearing as peers in the sidebar
- Define new-worktree creation as required only for explicit requests
  or concrete filesystem/checkout conflicts, not convenience
- Distinguish stacked worktrees from independent ones via --no-parent
- Rename agent-first guidance to reflect conditional requirement

* Release orchestration skill v25 with tightened worktree policy
2026-07-19 17:17:40 -07:00
Brennan Benson 31f643ca42 Add version-matched skill guides to the CLI (#8624)
* Add version-matched bundled skill guides

* Clarify skill freshness rollout PRs

* Add canonical skills show alias

* fix(skills): address guide review feedback

* fix(skills): make guide commands cross-platform

* fix(skills): apply the ORCA convention to the emulator guides

Review follow-up: the emulator guides still instructed literal
`orca emulator ...` in sh fences with no Linux disambiguation, so on
unmanaged Linux they could launch the GNOME screen reader — the exact
failure the executable-selection preamble prevents. Both emulator
guides now carry the preamble and ORCA placeholder across fences,
tables, and prose, and the cross-platform safety test covers all four
converted guides. Also replaces computer-use's "unless a block names a
shell" carve-out, which contradicted its own POSIX example, with the
unconditional placeholder rule.
2026-07-14 02:17:55 -07:00