Files
orca/src/cli/specs/browser-basic.ts
T
Brennan BensonandOrca 1f43346c5f fix(resource-usage): hydrate pty-registry at boot; render · remote only for SSH repos (#1667)
* WIP: Changes before auto-review fixes

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

* fix: address auto-review-fix-multi-agent findings

- Replace local ORCA_WORKTREE_ID_SEPARATOR with shared WORKTREE_ID_SEPARATOR
- Make hydrateLocalPtyRegistryAtBoot idempotent (one-shot per process,
  but stays retry-eligible until daemon provider is available)
- Strengthen daemon-pty-adapter strict-parser test to actually exercise
  the new short-circuit (test would have passed under the old loose
  parser too without the change)
- Add eslint-disable max-lines directive to oversized merge test file

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

* chore: archive auto-review context to .context/

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

* fix: address auto-review-fix findings

Drop the destructive reconcileOnStartup call from boot-time PTY registry
hydration: a transient listRepoWorktrees failure (returns [] and only
warns) would otherwise let the reconcile pass kill live local sessions.
The boot path is now read-only against the daemon — listSessions() only.

Also: tighten parsePtySessionId to reject degenerate `::` halves; replace
stale pty.ts:1005 references and a misleading local-unknown comment in
the hydrate module; narrow Store dependency to Pick<Store, 'getRepos'>;
log adapter listSessions failures instead of silently swallowing them;
re-anchor design-doc references on stable symbols and align §1b/§1c/§1d
with the implementation.

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

* docs(resource-usage): update remote badge spec

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

* test(resource-usage): cover boot hydration failure modes + warm-reattach e2e

Adds the regression coverage flagged in PR #1667's test plan that wasn't
already locked down.

vitest (`hydrate-local-pty-registry.test.ts`):
  - daemon offline at first call → no-op, hasHydrated stays false so a
    later macOS dock re-activation can retry.
  - listSessions rejection caught and logged, does not throw.
  - pid-write ordering: a pre-existing registry entry with pid=12345 is
    not clobbered by a stale `pid: null` from listSessions (§1d).
  - SSH-gate: a session whose repo has a non-null connectionId stays out
    of the registry, mirroring the spawn-time gate in pty.ts.
  - Happy-path: a local session is registered with the daemon's pid.

Playwright e2e (`resource-usage-warm-reattach.spec.ts`):
  Full quit→relaunch cycle against the same userDataDir; asserts that
  on the second launch the snapshot includes the warm-reattached PTY
  with a real pid before any pane mount, and that the seeded repo
  resolves as local (no connectionId). Mirrors the existing
  terminal-restart-persistence pattern.

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

* fix(test): satisfy Pick<Store, 'getRepos'> in hydrator vitest

CI typecheck failed because FakeStore's getRepos returned objects missing
Repo's required fields (path, displayName, badgeColor, addedAt). Fill with
placeholder values; the hydrator only reads id + connectionId, but the
type signature still has to line up.

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

* chore(resource-usage): drop bug-doc files; strip dead doc refs from comments

Remove docs/resource-usage-remote-mislabel.md (new in this PR) and revert
docs/resource-usage-merge-spec.md to the PR-base state. Strip the
matching `docs/...md §N` pointers from code/test comments, keeping the
surrounding "why" explanations intact so readers still get the
warm-reattach mislabel context.

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

---------

Co-authored-by: Orca <help@stably.ai>
2026-05-10 17:17:52 -07:00

239 lines
8.6 KiB
TypeScript

import type { CommandSpec } from '../args'
import { GLOBAL_FLAGS } from '../args'
export const BROWSER_BASIC_COMMAND_SPECS: CommandSpec[] = [
{
path: ['snapshot'],
summary: 'Capture an accessibility snapshot of the active browser tab',
usage: 'orca snapshot [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'worktree']
},
{
path: ['screenshot'],
summary: 'Capture a viewport screenshot of the active browser tab',
usage: 'orca screenshot [--format <png|jpeg>] [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'format', 'worktree']
},
{
path: ['click'],
summary: 'Click a browser element by ref',
usage: 'orca click --element <ref> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'worktree']
},
{
path: ['fill'],
summary: 'Clear and fill a browser input by ref',
usage: 'orca fill --element <ref> --value <text> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'value', 'worktree']
},
{
path: ['type'],
summary: 'Type text at the current browser focus',
usage: 'orca type --input <text> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'input', 'worktree']
},
{
path: ['select'],
summary: 'Select a dropdown option by ref',
usage: 'orca select --element <ref> --value <value> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'value', 'worktree']
},
{
path: ['scroll'],
summary: 'Scroll the browser viewport',
usage: 'orca scroll --direction <up|down> [--amount <pixels>] [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'direction', 'amount', 'worktree']
},
{
path: ['goto'],
summary: 'Navigate the active browser tab to a URL',
usage: 'orca goto --url <url> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'url', 'worktree']
},
{
path: ['back'],
summary: 'Navigate back in browser history',
usage: 'orca back [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'worktree']
},
{
path: ['reload'],
summary: 'Reload the active browser tab',
usage: 'orca reload [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'worktree']
},
{
path: ['eval'],
summary: 'Evaluate JavaScript in the browser page context',
usage: 'orca eval --expression <js> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'expression', 'worktree']
},
{
path: ['wait'],
summary: 'Wait for element, text, URL, load state, JS condition, or timeout',
usage:
'orca wait [--selector <sel>] [--timeout <ms>] [--text <text>] [--url <pattern>] [--load <state>] [--fn <js>] [--state <hidden|visible>] [--worktree <selector>] [--json]',
allowedFlags: [
...GLOBAL_FLAGS,
'selector',
'timeout',
'text',
'url',
'load',
'fn',
'state',
'worktree'
]
},
{
path: ['check'],
summary: 'Check a checkbox/radio by ref',
usage: 'orca check --element <ref> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'worktree']
},
{
path: ['uncheck'],
summary: 'Uncheck a checkbox/radio by ref',
usage: 'orca uncheck --element <ref> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'worktree']
},
{
path: ['focus'],
summary: 'Focus a browser element by ref',
usage: 'orca focus --element <ref> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'worktree']
},
{
path: ['clear'],
summary: 'Clear an input element by ref',
usage: 'orca clear --element <ref> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'worktree']
},
{
path: ['select-all'],
summary: 'Select all text in an input by ref',
usage: 'orca select-all --element <ref> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'worktree']
},
{
path: ['keypress'],
summary: 'Press a key (Enter, Tab, Escape, ArrowDown, etc.)',
usage: 'orca keypress --key <name> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'key', 'worktree']
},
{
path: ['pdf'],
summary: 'Export the active browser tab as PDF',
usage: 'orca pdf [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'worktree']
},
{
path: ['full-screenshot'],
summary: 'Capture a full-page screenshot (beyond viewport)',
usage: 'orca full-screenshot [--format <png|jpeg>] [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'format', 'worktree']
},
{
path: ['hover'],
summary: 'Hover over a browser element by ref',
usage: 'orca hover --element <ref> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'worktree']
},
{
path: ['drag'],
summary: 'Drag from one element to another',
usage: 'orca drag --from <ref> --to <ref> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'from', 'to', 'worktree']
},
{
path: ['upload'],
summary: 'Upload files to a file input element',
usage: 'orca upload --element <ref> --files <path,...> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'element', 'files', 'worktree']
},
{
path: ['tab', 'list'],
summary: 'List open browser tabs',
usage: 'orca tab list [--worktree <selector|all>] [--show-profile] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'worktree', 'show-profile']
},
{
path: ['tab', 'show'],
summary: 'Show one browser tab by page id',
usage: 'orca tab show --page <id> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'worktree']
},
{
path: ['tab', 'current'],
summary: 'Show the current browser tab',
usage: 'orca tab current [--worktree <selector|all>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'worktree']
},
{
path: ['tab', 'switch'],
summary: 'Switch the active browser tab',
usage: 'orca tab switch (--index <n> | --page <id>) [--worktree <selector>] [--focus] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'index', 'worktree', 'focus']
},
{
path: ['tab', 'create'],
summary: 'Create a new browser tab in the current worktree',
usage: 'orca tab create [--url <url>] [--worktree <selector>] [--profile <id>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'url', 'worktree', 'profile']
},
{
path: ['tab', 'profile', 'list'],
summary: 'List browser session profiles available to browser tabs',
usage: 'orca tab profile list [--json]',
allowedFlags: [...GLOBAL_FLAGS]
},
{
path: ['tab', 'profile', 'create'],
summary: 'Create a browser session profile for browser tabs',
usage: 'orca tab profile create --label <name> [--scope <isolated|imported>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'label', 'scope']
},
{
path: ['tab', 'profile', 'delete'],
summary: 'Delete a browser session profile used by browser tabs',
usage: 'orca tab profile delete --profile <id> [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'profile']
},
{
path: ['tab', 'profile', 'set'],
summary: 'Switch a browser tab to a different browser profile',
usage: 'orca tab profile set (--page <id> | --worktree <selector>) --profile <id> [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'profile', 'worktree']
},
{
path: ['tab', 'profile', 'show'],
summary: 'Show the browser profile bound to a tab',
usage: 'orca tab profile show --page <id> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'worktree']
},
{
path: ['tab', 'profile', 'use-default'],
summary: 'Switch a browser tab back to the default browser profile',
usage: 'orca tab profile use-default --page <id> [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'worktree']
},
{
path: ['tab', 'profile', 'clone'],
summary: 'Clone a browser tab into a different browser profile',
usage: 'orca tab profile clone --profile <id> [--page <id>] [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'profile', 'worktree']
},
{
path: ['tab', 'close'],
summary: 'Close a browser tab',
usage: 'orca tab close [--index <n>] [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'index', 'worktree']
},
{
path: ['exec'],
summary: 'Run any agent-browser command against the active browser tab',
usage: 'orca exec --command "<agent-browser command>" [--worktree <selector>] [--json]',
allowedFlags: [...GLOBAL_FLAGS, 'command', 'worktree']
}
]