mirror of
https://github.com/stablyai/orca.git
synced 2026-09-25 08:02:31 +00:00
8331fe5995a4ec7a11c92ea2de9e4bbe77eee5fa
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
650dd48ec9 |
feat(cli): add orca account add / account list for headless hosts (Claude + Codex) (#9177)
* feat(cli): add `orca account add` / `account list` for headless hosts The desktop "Add account" UI is disabled when the renderer drives a remote runtime (isRemoteAccountScope === kind:'environment'), so a headless server reached from a remote desktop/web client has no way to register managed Claude accounts. Add a host-local CLI path that reuses the existing capture logic: - ClaudeAccountService.addAccountFromConfigDir(): register a managed account by capturing credentials from an already-authenticated CLAUDE_CONFIG_DIR instead of spawning the interactive browser login (extracted persist/rollback helpers shared with the existing add flow) - RPC accounts.addClaudeFromConfigDir, bridged via OrcaRuntime; rejected for mobile device tokens (host-local only) - `orca account add` runs `claude login` in the user's own terminal into a temp CLAUDE_CONFIG_DIR, then registers it via the local runtime; `orca account list` lists managed accounts Switching (select) already works from a remote client; only adding was blocked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(cli): support Codex in `orca account add` / `account list` Mirror the Claude headless-account CLI for Codex: - CodexAccountService.addAccountFromHome(): register a managed Codex account by importing auth.json from an already-authenticated CODEX_HOME, reusing a shared persist helper extracted from doAddAccount (no interactive login spawned here) - RPC accounts.addCodexFromHome + OrcaRuntime.addCodexAccountFromHome bridge, rejected for mobile device tokens (host-local only) - `orca account add --agent claude|codex` (default claude); `orca account list` now renders both Claude and Codex managed-account blocks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: cover headless account-add capture paths (Claude + Codex) - ClaudeAccountService.addAccountFromConfigDir: registers a managed account by capturing an authenticated CLAUDE_CONFIG_DIR; rejects and rolls back when the dir has no .credentials.json - CodexAccountService.addAccountFromHome: imports auth.json from an authenticated CODEX_HOME into a managed account; rejects when auth.json is missing Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: address CodeRabbit review on headless account-add flows - CLI login spawn uses a shell on Windows so `.cmd` agent shims resolve without ENOENT (args are fixed literals, no injection risk) - Claude capture skips the `.credentials.json` precheck on macOS, where creds live in the Keychain and captureAuthFromConfigDir reads them - Claude add rollback is best-effort: a failed rematerialization no longer skips managed-auth cleanup or masks the original add error - Codex persist restores the prior account/selection if a post-write sync or rate-limit refresh fails, so a failure can't leave a dangling managed account - Codex sync passes the account's selection target (correct runtime for WSL) - Add JSDoc to the new public service methods and CLI functions Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(cli): harden headless account capture * fix(cli): correct account command flag surface and interrupt cleanup - `account` commands no longer accept or advertise the browser `--page` flag; `supportsBrowserPageFlag` allow-listed them by omission, so `orca account list --page x` was silently accepted and `--help` rendered a browser-only option - account specs declare GLOBAL_FLAGS, so `--help`/`--json` render in the Options block like every other command - `--agent` on `account add` documents the account provider instead of the terminal TUI-agent meaning inherited from the shared flag table - a SIGINT/SIGTERM during the interactive login now removes the temp login dir (and restores the macOS Keychain item) before exiting 130; Node terminates without unwinding `finally`, which stranded live OAuth credentials on disk * perf(cli): stop `account list` forcing a provider usage refresh `accounts.list` awaited refreshAccountsForMobile(), which runs fetchAll({ force: true }) — bypassing both the poll throttle and the per-provider Retry-After gate — then O(N) serial per-account round trips. `orca account list` renders only emails and the active ids, so all of that work was discarded. The RPC now takes `refreshUsage` (default true, so mobile and web keep the forced lane) and the CLI opts out. Older hosts declare `params: null` and ignore the field, so a newer CLI degrades to the previous behavior rather than failing. Also documents on `account list` that `--environment` does not retarget it, matching the host-local behavior of shouldIgnoreRemoteSelection. * fix(cli): survive repeated and hangup signals during account add withInterruptCleanup latched cleanup behind a boolean, so a second signal got an already-resolved promise and its process.exit fired while the first cleanup was still inside a Keychain call (3s each) — the temp dir's OAuth credentials and the swapped macOS Keychain item both survived. Memoize the cleanup promise so every signal awaits the same run, and register with `on` instead of `once` so a second Ctrl-C cannot fall through to Node's terminate-immediately default mid-cleanup. Handle SIGHUP too. This flow exists for headless/SSH hosts, where the most likely interrupt is the connection dropping, which hangs up the login's terminal and previously ran no cleanup at all. Warn when the interrupt lands after sign-in completed: the runtime finishes the add independently of this process, so exiting 130 silently would tell the user it was cancelled when the account may exist. Reject a valueless `--agent`; the parser turns it into boolean true, which silently ran a full OAuth login for Claude when the user asked for another provider. Also lock two behaviors the refactor changed but left uncovered: a WSL Codex add must sync the WSL runtime lane rather than the default host lane, and rename the account-spec help test to describe the Options block it actually asserts rather than the usage string it never reads. * fix(build): bundle the main modules the account CLI imports electron-vite cleans out/main and emits only its declared entries, and `build:desktop` runs it after `build:cli`, so the tsc-emitted copies of `claude-accounts/keychain`, `codex-cli/command` and `win32-utils` were deleted before packaging. Both `orca account add` and `orca account list` then died at require time with "Cannot find module '../../main/claude-accounts/keychain'" — reproduced against a real `--serve` host. `agent-hooks/managed-agent-hook-controls` already carried an entry for exactly this reason; these three were missing. Adds a parity test so any future CLI import of a `src/main` module fails in CI rather than at a user's shell after packaging. * test: cover the desktop add-path behavior this PR changes Both changes ride in the persist/rollback helpers the existing GUI add flow shares with the new headless path, and neither had coverage: - Claude: rollbackAddAccount now guards forceMaterializeCurrentSelection- ForRollback, so a rejecting rematerialization no longer replaces the real add error nor skips safeRemoveManagedAuth. Asserts the original error surfaces and the throwaway auth dir is gone. - Codex: the desktop add now passes the account's selection target to syncForCurrentSelection, matching reauthenticate and select. Asserts the host target alongside the existing WSL assertion. Both fail when the corresponding change is reverted. * fix(cli): close the remaining account-add interrupt and preflight gaps The round-1 interrupt fix detached the signal handlers before running the finally-path cleanup, so the very window it was meant to protect — the two serial 3s `security` calls plus rmSync on the success/error path — was still covered only by Node's terminate-immediately default. Both review lanes reproduced it independently. Await cleanup first, detach in a nested finally, and stop a cleanup failure from replacing the error that actually explains why the add failed. Do not burn the interactive login when the runtime is unreachable. The RuntimeClient is lazily constructed and the first call was the registration RPC itself, so "Requires the Orca runtime to be running" was discovered only after the user completed a full OAuth round trip. Preflight with the now-cheap `accounts.list { refreshUsage: false }`. Reject `--environment` / `--pairing-code` on `account add`. shouldIgnoreRemoteSelection pins account commands to the local runtime, so `orca account add --environment homelab` silently registered the account on the laptop instead of the headless host it names. Survive a daemon that cannot spawn `claude`. `allowFailure` is honored in onClose but not onError, and unlike the GUI flow nothing has run `claude` in the daemon before this point — so a launchd/systemd daemon with a minimal PATH hard-failed an add the user had already signed in for, even though identity resolves fine from the config dir's oauthAccount. Also align the `--agent` help description with the global flag column. * fix(cli): reject runtime selectors on `account list` too `orca account list --environment homelab` was accepted and silently listed the LOCAL machine's accounts, because shouldIgnoreRemoteSelection pins account commands to the local runtime. Documenting that in --help does not reach someone who already typed the flag, and answering with the wrong host's accounts is the specific wrong answer they would act on. `account add` already errors; this makes the new command group internally consistent. The other groups in shouldIgnoreRemoteSelection keep their existing silent-ignore behavior — changing those is not this PR's job. * test: harden account-add signal tests and cover cleanup failure - Identify the handler under test by set difference instead of `process.listeners(sig).at(-1)`. Vitest installs its own once-wrapped SIGINT teardown, so the positional lookup could grab the wrong listener; the helper also asserts exactly one new listener was added. - Mock rmSync while keeping the real implementation by default, so the temp-dir assertions elsewhere stay honest. - Cover that a cleanup failure in the `finally` does not replace the error explaining why the add failed. Fails when that guard is removed. Completes the review loop's final round; the loop died on an API error before it could commit this, and its `import()` type annotation would have failed oxlint. * fix(cli): harden interactive account add * test(cli): make account cancellation coverage portable * fix(cli): preserve merged skills runtime modules --------- Co-authored-by: Dominik <marketing@gavaplast.sk> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> |
||
|
|
e2b4bc2c2c |
feat(cli): make the CLI self-correcting and self-describing for agents (#6303)
* feat(cli): make the CLI self-correcting and self-describing for agents Agents build a generalized model of how CLIs work and apply it to every tool. When orca diverged — `rm` where git uses `remove` — a reasonable first guess (`orca worktree remove`) dead-ended on a bare "Unknown command" with no path forward. This makes the CLI degrade gracefully when the orca-cli skill isn't loaded in context. - First-class CommandSpec.aliases, resolved to the canonical path before dispatch (no new handler registrations). `worktree remove`/`delete` now resolve to `rm`; the ad-hoc `terminal focus` duplicate spec/handler is migrated onto the mechanism. - Did-you-mean suggestions on unknown commands and unknown flags, ranked by edit distance over the live registry, surfaced in both stderr and --json error.data (reusing the existing nextSteps channel). - `orca agent-context [--json]`: a versioned, machine-readable dump of the command schema. Pure local read (no RPC), so it works over SSH and when the app isn't running. - CI guards: specs<->handlers parity, and a vocabulary policy that fails on new off-policy deletion/read verbs (existing ones grandfathered). * Address PR review feedback (#6303) - agent-context now emits each command's effective flag set (globals + conditional --page), not just allowedFlags, so the schema no longer under-reports --json/--help. Shared as effectiveAllowedFlags() between validation and the schema. - Collision check now covers alias paths too, so a duplicate alias that would silently shadow a real command fails the build. * fix(cli): harden agent recovery and introspection Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com> Co-authored-by: Orca <help@stably.ai> |
||
|
|
42b2ecc5c6 |
feat(emulator): Android emulation via scrcpy (cross-platform, iOS parity) (#6434)
* docs: add Android emulation design spec Adds the design for first-class Android emulator support as a cross-platform peer of the iOS simulator feature: an extracted EmulatorBackend interface (iOS + Android), full AVD lifecycle management via the Android SDK, a live scrcpy H.264 pane decoded in-renderer with WebCodecs, the full control surface (tap/gesture/type/buttons/rotate), accessibility tree, app install/launch, runtime permissions, logcat, and a dedicated orca-emulator-android skill. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(emulator): add EmulatorBackend interface + backend/codec session tags First step of multi-backend emulator support: introduce the EmulatorBackend type and tag each session with its backend kind + stream codec, defaulting to ios/mjpeg so existing serve-sim behavior is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(emulator): extract IosEmulatorBackend and make the bridge a router Move the serve-sim/simctl device + helper + input mechanics out of EmulatorBridge into IosEmulatorBackend (implementing EmulatorBackend). The bridge now owns the session registry and lifecycle orchestration and routes each command to the backend that owns the target device. iOS behavior is unchanged; the existing bridge tests pass untouched and the backend gains its own input-op coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): add pure Android leaf modules (sdk/adb/avd/scrcpy/input/ax) Dependency-injected building blocks for the Android emulator backend, each unit- tested in isolation: SDK + tool discovery, adb device/output parsing, AVD list + boot arg building, scrcpy control-socket byte encoders, normalized<->pixel + keycode mapping, and a uiautomator XML accessibility-tree parser. Not yet wired; AndroidEmulatorBackend composes these in the next phase. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(emulator): gate availability on the iOS backend + lock it with tests inspectEmulatorAvailability now decides iOS host support via the registered iOS backend instead of a bare platform literal, routing the decision through the multi-backend seam. Output shape and all messages are unchanged (the settings pane still reads simctl/serveSim). Adds the previously-missing regression tests covering the unsupported, ready, no-devices, and tool-failure paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): add Android app/permissions/logcat arg builders Pure adb arg-builders + a logcat line parser for app install/launch, runtime permission grant/revoke/reset, and logcat capture. Unit-tested in isolation; wired into AndroidEmulatorBackend's capability verbs in a later phase. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): AndroidEmulatorBackend device management + unified device list Adds the Android backend (registered alongside iOS in the bridge): SDK-gated host support, device/AVD discovery and merge, AVD boot + boot-completion wait, shutdown, and tap/swipe/type/button/rotate/exec via `adb shell input` so control works without the scrcpy server (the live H.264 stream lands in the streaming phase). Surfaces everything through a new cross-platform `orca emulator devices` command (RPC emulator.listDevices -> bridge.listAllDevices) with a platform column. Device inventory is split into its own module to keep files focused. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): Android capability verbs (install/launch/permissions/ax/logcat) Wires the Android capability operations into AndroidEmulatorBackend and exposes them through a capability-gated bridge router (runCapability), RPC, and CLI: - orca emulator install/launch/permissions/ax/logcat Capabilities are advertised per backend; calling one on a backend that lacks it (e.g. iOS) fails with emulator_unsupported instead of a silent no-op. Input ops and capability ops are split into focused modules to keep files under the line cap; the runtime shares one target-param type. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(skill): add orca-emulator-android skill + cross-ref from iOS skill Documents the cross-platform Android emulator control surface (devices, input, hardware buttons, rotate, install/launch, permissions, ax, logcat) driveable via the orca CLI today, and notes the live visual pane is in development. Points the iOS skill's "when not to use" at the new Android skill. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): Android live-pane streaming scaffolding (scrcpy + WebCodecs) Builds the H.264 video path as scaffolding: scrcpy frame/codec-meta parsing, server-deploy arg builders, control-protocol encoders (committed earlier), the stream session (server + sockets), a video pub/sub registry, the emulator:videoStream* IPC channel, and a renderer WebCodecs->canvas hook. Pure framing/deploy/registry are unit-tested; the socket/WebCodecs/jar integration is clearly flagged UNVERIFIED and the remaining wiring (startSession, preload, pane codec branch, packaging the jar) is documented in docs/android-emulation-streaming.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: fix streaming notes doc path in video-stream hook comment Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(emulator): add diagnostic probes for Android testing Adds an emulator-probe logger (console + temp file at os.tmpdir()/orca-android-emu-probe.log) and wires probes at four layers so errors surface during manual testing: every emulator.* RPC call + error (RPC dispatcher), every adb/emulator command + non-zero exit (command runner), and the scrcpy session + video-stream IPC lifecycle. Temporary diagnostics; remove or gate behind a flag once the Android pane is validated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): show Mobile Emulator settings cross-platform + aggregate Android availability The Mobile Emulator settings section is no longer macOS-gated (Android works on Windows/Linux), and inspectEmulatorAvailability now aggregates the iOS and Android backends: Android devices/AVDs appear in the device list and a host without iOS gets the Android setup message instead of "requires macOS". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): show Mobile Emulator sidebar nav entry on non-mac desktops The settings sidebar nav registered the Mobile Emulator entry behind isMac, so it stayed hidden on Windows/Linux even after the section content was ungated. Widen it to showDesktopOnlySettings to match the section. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): wire Android startSession to scrcpy + client-downloaded jar AndroidEmulatorBackend.startSession now boots the device, ensures the scrcpy server jar (downloaded by the client into the per-user cache on first use, not bundled), starts a ScrcpyStreamSession, and feeds its H.264 frames to the video registry; stopHelperForDevice tears it down. Sessions carry their backend kind so worktree-active routing picks the right backend. Boot, host SDK discovery, and the stream starter are split into focused modules to stay under the line cap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): stop the iOS backend from claiming Android devices off-mac iOS ownsDevice now returns false unless the host supports it, so on Windows an Android serial routes to the Android backend instead of erroring with "requires macOS". Backend-for-device fallback prefers a host-supported backend. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): scrcpy scid 31-bit + retry video socket until server delivers Two fixes validated against a real emulator: scrcpy parses scid as a signed 32-bit hex int, so mask to 31 bits + pad to 8 digits (8-byte values overflowed and the server exited). And adb accepts the forwarded TCP connection before the server's abstract socket exists then resets it, so retry the video socket until it actually delivers the dummy byte before connecting control. H.264 meta now arrives (576x1280). Adds socket/server-exit diagnostics probes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): render the Android H.264 pane via WebCodecs Wires the live Android pane end-to-end: preload exposes emulator video stream APIs; the pane's device list uses the unified emulator.listDevices (Android + iOS); and emulator-screen-stream-content renders a WebCodecs <canvas> for scrcpy:// sessions (H.264, SPS/PPS prepended to the first keyframe) instead of the MJPEG <img>. The video hook reports the stream size for the device frame. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): buffer the current GOP for late video subscribers The renderer subscribes after attach already started the scrcpy stream, so the registry now caches the current GOP (keyframe + following deltas) alongside the codec meta and config, and replays it on subscribe. A pane opened mid-stream decodes from the keyframe immediately instead of showing black until scrcpy's next periodic keyframe (~10s). Refreshes the now-validated session doc comment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): show New Mobile Emulator tab action off macOS The tab create menu and its dropdown item gated the New Mobile Emulator action on isMacOs, hiding it on Windows/Linux where Android emulation is now supported. Gate on mobileEmulatorEnabled + onNewSimulatorTab (already cross-platform) so the action appears wherever a mobile emulator backend is available. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): open the Mobile Emulator tab off macOS openMobileEmulatorTab and ensureSimulatorTab both returned null unless the host was macOS, so the New Mobile Emulator action no-opped on Windows/Linux even though the menu entry showed. Drop the isMacOsHost early-returns; the mobileEmulatorEnabled setting and backend availability already gate the feature. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): resolve a default attach device across backends emulatorAttach with no device fell back only to the iOS listSimulators picker (empty on Windows/Linux), so the pane's no-device launch flow errored. Extract resolveDefaultAttachDevice: iOS default first, else the first booted (else first) device across host backends, so Android attaches without an explicit device. Split into its own module to stay under the line cap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): render the pane off macOS instead of an unavailable wall EmulatorPane short-circuited to the "macOS only" EmulatorUnavailablePane on any non-Mac host, blocking the now-working Android pane. Always render the pane content; its device discovery and error surface handle a missing backend. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): let attach boot a shut-down AVD with a stale active session getReusableActiveForWorktree called resolveDeviceId on the requested device, which throws for a not-yet-booted Android AVD, aborting the attach. Guard it so a resolve failure means "not the active device" and the attach falls through to a fresh boot — so picking a shut-down AVD in the pane and hitting Connect boots it via ensureBooted instead of erroring. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): launch the AVD detached instead of via execFile bootAndroidDevice started the emulator through the command runner (execFile with a timeout + 1MB stdout maxBuffer), which kills the long-running, verbose emulator process — so booting an AVD from the pane never actually came up. Spawn it detached with no stdio and unref it so it outlives the call, mirroring how the scrcpy server is launched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): dedupe concurrent attaches into one scrcpy stream Extract AndroidStreamController to own the per-serial scrcpy lifecycle and dedupe starts: concurrent attaches (e.g. the pane's auto-attach racing the tab launch) now share one in-flight start and reuse the live stream instead of spawning a second scrcpy server that fights for the port and kills the first. Also initialize the registry GOP buffer in register() (latent type error). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): boot the AVD headless without a console window The detached spawn opened a Windows console (showing the emulator's verbose qemu/netsim logs) and a redundant native emulator window. Pass windowsHide and run the emulator with -no-window so it boots headless — the scrcpy pane is the view, matching how iOS hides Simulator.app. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): boot the AVD with a hidden console, not detached detached: true sets DETACHED_PROCESS, which gives the console-subsystem emulator no console — so it and its qemu/netsim children pop their own visible cmd window that windowsHide can't suppress. Drop detached and rely on windowsHide (CREATE_NO_WINDOW = hidden console) + unref; spawn already keeps it alive past the launch call, and managed emulators are shut down on app quit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): keep Android emulators alive when switching devices Attaching a different device shut down the active one (shutdownDevice: true), which for Android meant killing the running emulator and cold-booting the target (~60s) on every switch — and switching back. Add bridge.stopActiveForSwitch: Android emulators stay running for instant switch-back, while iOS simulators are still replaced. Switching to an already-running emulator is now immediate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * perf(emulator): only resize the video canvas when dimensions change The decoder output handler set canvas.width/height on every frame, which reallocates the canvas backing store and forces an object-contain reflow each frame — a needless per-frame cost. Resize only when the frame dimensions actually change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): genericize copy + add Android Studio setup link Replace iOS-only wording (Xcode/Simulator/iPhone) in the pane and settings with backend-neutral copy so Android reads correctly on every platform. When no emulator is available, the Mobile Emulator settings now show a "Download Android Studio" link plus setup guidance (ANDROID_HOME / default install path). Removes the now-unused, macOS-only EmulatorUnavailablePane. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): show emulator SDK status in settings The backend availability now reports the resolved Android SDK path, aggregated into emulator.availability as an `android` block. The Mobile Emulator settings render an "Emulator SDKs" card showing Android SDK (detected at <path> / not found, with a Download Android Studio link) and, on macOS, iOS Simulator (Xcode) status — mirroring the agent-control card. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(emulator): locate a custom Android SDK folder from settings Add an androidSdkPath setting and a "Locate SDK folder…" / Clear action in the emulator SDK status card. The path is applied as the highest-priority discovery candidate (falls back if invalid), and the backend's SDK is re-resolved on use via a new AndroidSdkState — so locating or installing the SDK takes effect on Refresh without restarting Orca. Guards the status card against older runtimes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): settle the scrcpy video socket once to stop retry storms A failed TCP connect emits both 'error' and 'close', so retry ran twice and scheduled openVideoSocket(attempt+1) twice — fanning out into an exponential connection storm while waiting for the server to start listening. A runaway chain could then hit attempt 100 and fail/close a stream that had already connected. Replace the delivered flag with a single settled latch so each socket retries (or delivers) exactly once. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): address CodeRabbit review findings - avd-boot: handle spawn 'error' (an unhandled ChildProcess error crashed the main process); validate the target is a known AVD before launching. - capability-ops: propagate adb non-zero exits for launch/permission/logcat and check the uiautomator dump before reading (avoids stale XML). - scrcpy-video-registry: actually replay the buffered GOP on subscribe so late subscribers decode immediately. - android-sdk-state: re-resolve host discovery every call so a changed SDK path takes effect live (no restart). - android-sdk-discovery: require both adb and the emulator binary. - emulator-bridge: fall back to the platform-primary backend (Android off-mac) so setup errors aren't iOS/CoreSimulator on Windows/Linux. - scrcpy-server-download: dedupe concurrent first-use downloads + add a timeout. - scrcpy-stream-session: idle-socket connect timeout; surface control-socket errors instead of swallowing them. - android-exec: pass the whole command so the device shell parses quotes/pipes. - avd-manager: match emulator log prefixes exactly (keep AVD names like PixelWARNINGTest). - permissions: `pm reset-permissions` is global and takes no package argument. - stream controller/starter: drop stale handles for dead streams; idempotent teardown. use-emulator-video-stream: stopVideoStream returns Promise. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(emulator): populate the GOP buffer and reuse live scrcpy streams Self-audit follow-ups in the same class as the CodeRabbit GOP-replay finding: - scrcpy-video-registry: pushFrame never wrote to entry.gop, so the replay loop added for late subscribers iterated an empty array — a no-op. Build the GOP on ingest (start at each keyframe, append following deltas; don't buffer deltas before the first keyframe). Adds tests for population, reset, and the pre-keyframe guard. - android backend: isSessionReusable was stubbed to always return false with a "no persistent stream yet" note, but scrcpy streams are persistent now — so every renderer remount tore down and respawned the server. Reuse a live stream (scrcpyVideoRegistry.has) so remounts reconnect, matching iOS. The device-mismatch check still runs first, so device switching is unaffected. - Refresh stale comments that implied unfinished/unverified work. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: Changes before auto-review fixes Co-authored-by: Orca <help@stably.ai> * Refine mobile emulator availability settings Co-authored-by: Orca <help@stably.ai> * Address emulator review follow-ups Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com> Co-authored-by: Orca <help@stably.ai> |
||
|
|
3a2d39cb37 |
Support full Linear task workflows from the CLI (#5323)
Co-authored-by: Orca <help@stably.ai> |
||
|
|
62600ef808 | Fix orchestration payloads on Windows (#4608) | ||
|
|
ffbc4c3cfb | fix: tighten CLI contract validation (#3874) | ||
|
|
563d4ff64b | fix(cli): allow flag values that start with -- via --flag=value (#2892) | ||
|
|
0f54103dda |
Add native computer-use automation (#1683)
Co-authored-by: Orca <help@stably.ai> |