agent-device 0.19.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +5 -1
  2. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.19.0.apk → agent-device-android-multitouch-helper-0.19.1.apk} +0 -0
  3. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.1.apk.sha256 +1 -0
  4. package/android-multitouch-helper/dist/{agent-device-android-multitouch-helper-0.19.0.manifest.json → agent-device-android-multitouch-helper-0.19.1.manifest.json} +4 -4
  5. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.19.0.apk → agent-device-android-snapshot-helper-0.19.1.apk} +0 -0
  6. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.1.apk.sha256 +1 -0
  7. package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.19.0.manifest.json → agent-device-android-snapshot-helper-0.19.1.manifest.json} +6 -6
  8. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+AXSnapshotFallback.swift +24 -7
  9. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +506 -119
  10. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +153 -48
  11. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +172 -0
  12. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +76 -5
  13. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +60 -52
  14. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SnapshotCapturePlan.swift +159 -56
  15. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +142 -0
  16. package/dist/apple-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +16 -14
  17. package/dist/src/android-adb.d.ts +1 -2
  18. package/dist/src/android-adb.js +1 -1
  19. package/dist/src/android-input-ownership.js +6 -0
  20. package/dist/src/android.js +1 -1
  21. package/dist/src/app-lifecycle.js +3 -3
  22. package/dist/src/apple-runner-options.js +1 -1
  23. package/dist/src/apps.js +5 -5
  24. package/dist/src/cli-help.js +131 -34
  25. package/dist/src/cli-runner.js +1 -1
  26. package/dist/src/cli.js +11 -11
  27. package/dist/src/client.js +2 -2
  28. package/dist/src/command-metadata.js +1 -1
  29. package/dist/src/command-schema.js +3 -3
  30. package/dist/src/device-input-state.js +2 -2
  31. package/dist/src/devices2.js +1 -1
  32. package/dist/src/find.js +1 -1
  33. package/dist/src/generic.js +1 -1
  34. package/dist/src/index.d.ts +199 -20
  35. package/dist/src/input-actions.js +3 -3
  36. package/dist/src/interaction-snapshot.js +1 -1
  37. package/dist/src/interaction.js +1 -1
  38. package/dist/src/interactor.js +2 -2
  39. package/dist/src/internal/bin.js +1 -1
  40. package/dist/src/internal/daemon.js +17 -15
  41. package/dist/src/lease.js +1 -1
  42. package/dist/src/linux.js +1 -1
  43. package/dist/src/metro.d.ts +0 -1
  44. package/dist/src/notifications.js +1 -1
  45. package/dist/src/points.js +1 -1
  46. package/dist/src/project-runtime.js +1 -1
  47. package/dist/src/providers.js +1 -1
  48. package/dist/src/react-native.js +1 -1
  49. package/dist/src/record-trace-recording.js +2 -2
  50. package/dist/src/record-trace.js +1 -1
  51. package/dist/src/registry.js +24 -23
  52. package/dist/src/reporting.js +3 -3
  53. package/dist/src/runner-client.js +1 -1
  54. package/dist/src/runtime.js +2 -2
  55. package/dist/src/sdk-android-adb.d.ts +2 -2
  56. package/dist/src/sdk-batch-runner.d.ts +0 -1
  57. package/dist/src/sdk-batch.js +2 -2
  58. package/dist/src/sdk-finders.d.ts +1 -2
  59. package/dist/src/sdk-finders.js +1 -1
  60. package/dist/src/sdk-io.d.ts +0 -1
  61. package/dist/src/sdk-remote-config.d.ts +1 -2
  62. package/dist/src/sdk-remote-config.js +1 -1
  63. package/dist/src/sdk-selectors.js +1 -1
  64. package/dist/src/selector-runtime.js +1 -1
  65. package/dist/src/selectors.d.ts +0 -1
  66. package/dist/src/selectors.js +1 -1
  67. package/dist/src/selectors2.js +1 -1
  68. package/dist/src/server.js +3 -3
  69. package/dist/src/session.js +10 -10
  70. package/dist/src/simctl.js +1 -1
  71. package/dist/src/simulator.js +1 -1
  72. package/dist/src/snapshot-diagnostics.js +2 -2
  73. package/dist/src/snapshot-helper.js +4 -4
  74. package/dist/src/snapshot-quality.js +1 -1
  75. package/dist/src/snapshot2.js +2 -2
  76. package/dist/src/tv-remote.js +14 -0
  77. package/dist/src/web.js +1 -1
  78. package/package.json +5 -4
  79. package/server.json +2 -2
  80. package/skills/agent-device/SKILL.md +8 -7
  81. package/android-multitouch-helper/dist/agent-device-android-multitouch-helper-0.19.0.apk.sha256 +0 -1
  82. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.19.0.apk.sha256 +0 -1
  83. package/dist/src/device-rotation.js +0 -14
  84. package/dist/src/logcat.js +0 -6
@@ -1,13 +1,37 @@
1
- import{D as e}from"./sdk-batch.js";import{g as t,p as n}from"./registry.js";import{n as r,r as i}from"./command-schema.js";const a=[{label:`agent-device help workflow`,description:`Start here for the core loop, command shape, refs/selectors, and verification`},{label:`agent-device help debugging`,description:`Use when logs, network, audio, perf memory, traces, alerts, or diagnostics matter`},{label:`agent-device help react-native`,description:`Use when the target app is React Native, Expo, or a dev client`},{label:`agent-device help react-devtools`,description:`Use when inspecting components, props/state/hooks, renders, or profiles`},{label:`agent-device help cdp`,description:`Use when investigating JS heap growth, heap snapshots, or retainers`},{label:`agent-device help physical-device`,description:`Use when using a connected phone/tablet or iOS signing setup`},{label:`agent-device help remote`,description:`Use when working through cloud config, tenants, leases, or local tunnels`},{label:`agent-device help web`,description:`Use when automating a browser through agent-device sessions`},{label:`agent-device help macos`,description:`Use when targeting desktop, frontmost app, or menu bar surfaces`},{label:`agent-device help dogfood`,description:`Use when producing exploratory QA evidence`}],o=[`agent-device is the default automation surface for app/device workflows across supported targets.`,`Default to agent-device for installs, opens, snapshots, interactions, screenshots, logs, network/perf evidence, and verification.`,`Use raw adb, simctl, xcrun, or platform scripts only when this help calls out a tool gap or platform setup step.`,`Start with agent-device help workflow to understand the core loop and how to use the tool.`,`Core loop: open <app> -> snapshot -i (interactive tree with @refs) -> press/click/fill <target> --settle (returns the settled diff with fresh @refs) -> repeat. Verify with diff snapshot -i.`],s=[`Planning output contract: when asked to plan commands, output command lines only: no prose, numbering, Markdown fences, pipes, or shell helpers.`,`Default loop: devices/apps -> open -> snapshot -i -> press/fill/get/is/wait/find -> verify with diff snapshot -> close.`,`Verify a mutation with diff snapshot (or diff snapshot -i), not a full snapshot: it prints only the added/removed/changed lines since the last snapshot in this session, so confirming an action costs a few lines instead of the whole tree.`,`Collapse act+observe into one call with --settle on press/click/fill/longpress: the response waits for the UI to go quiet and carries the settled diff with fresh refs (settled: false plus a hint on never-quiet content; the action itself never fails). Tune with --settle-quiet <ms> and --timeout <ms>.`,`Treat the --settle diff as the post-action observation: if it already shows the next target or final evidence, act on that fresh ref or answer from it instead of taking another snapshot.`,`Network-backed or debounced results may arrive after the --settle quiet window; follow the settled action with wait text "Expected result" or wait <selector> instead of polling full snapshots.`,`Use selectors or refs as positional targets: id="submit", label="Allow", role=button label="Send", or @e12 from snapshot -i. Do not write role names as selector keys, such as button="Search".`,`Pin a ref to the snapshot that minted it with ~s<n> (n = refsGeneration in the snapshot response): press @e12~s4. Pinned refs get exact staleness warnings instead of the coarse tree-changed one; plain refs stay valid input.`,`Plain snapshot reads state; snapshot -i refreshes current interactive refs only.`,`Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions.`,`Read-only visible/state question: use snapshot/get/is/find; use snapshot -i only when refs are needed.`,`Anti-pattern: snapshot -i followed by snapshot -i | grep ... or hiding command output with 2>/dev/null | jq ...; inspect raw agent-device output first, since hints and errors are part of the planning contract.`,`Truncated text/input preview: expand first with snapshot -s @e12, not get text.`,`React Native apps: read help react-native for Metro, DevTools routing, and RN-specific blockers; use react-native dismiss-overlay for LogBox/RedBox overlays.`,`React Native JS memory leaks: read help cdp; use heap usage samples for a quick signal, then snapshot diff/leak-triplet for retained object proof.`,`Android RN/Expo Metro: direct Android localhost URL opens with a port auto-configure host reachability.`,`Expo Go/dev clients: use the provided URL when given; on iOS use open "Expo Go" <url> --platform ios, then snapshot -i --platform ios to verify project UI. Do not use plain snapshot or snapshot --diff for this recovery check. Android URL opens infer the foreground package for logs/perf when possible.`,`Install flows: install/install-from-source first, then open the installed id with --relaunch.`,`Text: fill 'id="field-email"' "qa@example.com" replaces; type appends after press.`,`Clearing text: do not use fill <target> ""; use a visible clear/reset control or report that clearing is unsupported.`,`Android IME capture: if fill says input was captured by the keyboard/IME, inspect keyboard state and switch/disable handwriting before retrying; do not loop fill/type.`,`Implicit default sessions are scoped to the current worktree; if a prompt names a Session, include --session <name> on every command in that flow.`,`Run mutating commands serially within one session; parallelize only read-only commands or separate sessions/devices.`,`Clipboard limits: iOS Allow Paste cannot be automated through XCUITest; prefill with clipboard write. Android non-ASCII should use fill/type, not raw adb input.`,`After mutation: refs are stale. If the next target is known, use its selector directly; otherwise refresh with snapshot -i, scoped with -s when a stable container is known. Use press/click for taps.`,`Raw coordinates are fallback-only: use snapshot -i --json rects when iOS refs no-op or child refs are missing, then verify the action with diff snapshot -i or snapshot --diff.`,`Sparse or AX-unavailable snapshot: use screenshot for visual truth, press the visible coordinate to leave the bad screen, then retry AX with snapshot -i.`,`macOS context menus use click <ref> --button secondary, then snapshot -i. Longpress is for mobile hold gestures, not macOS secondary-click menus.`,`Remote lifecycle: use connect, then open, commands, close, and disconnect. Cloud, remote-config, direct proxy, and limrun use the same flow.`,`Direct proxy: run agent-device connect proxy --daemon-base-url <proxy-agent-device-url> before using a shared Mac proxy. Device leases are automatic on open and expire after five minutes of inactivity.`,`Batch JSON steps use "command" and structured "input"; legacy "positionals"/"flags" steps still run in CLI but are deprecated until the next major version.`,`Navigation: app-owned back uses back; system back uses back --system.`,`Web browser sessions: read help web; first slice is web setup if needed -> web doctor -> open <url> --platform web -> snapshot -i -> click/fill/get/is/find/wait/screenshot -> close.`,`Verification commands must name the expected text/selector; bare screenshots/snapshots are not enough.`,`Debug evidence: Session state contains request diagnostics and runner.log; use logs clear --restart/mark/path, trace, and network dump --include headers for app evidence.`,`Full operating guide: agent-device help workflow. Exploratory QA: agent-device help dogfood.`],c=[`Default config files: ~/.agent-device/config.json, ./agent-device.json`,`Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file.`],l=[{label:`AGENT_DEVICE_SESSION`,description:`Explicit session name`},{label:`AGENT_DEVICE_PLATFORM`,description:`Default platform binding`},{label:`AGENT_DEVICE_SESSION_LOCK`,description:`Bound-session conflict mode`},{label:`AGENT_DEVICE_DAEMON_BASE_URL`,description:`Connect to remote daemon`},{label:`AGENT_DEVICE_DAEMON_AUTH_TOKEN`,description:`Remote daemon service/API token`},{label:`AGENT_DEVICE_CLOUD_BASE_URL`,description:`Bridge/control-plane API origin for cloud auth and /api-keys`}],u=[`agent-device open Settings --platform ios`,`agent-device open https://example.com --platform web`,`agent-device open TextEdit --platform macos`,`agent-device snapshot -i`,`agent-device react-devtools get tree --depth 3`,`agent-device cdp memory usage sample --gc --label baseline`,`agent-device fill @e3 "test@example.com"`,`agent-device replay ./session.ad`,`agent-device test ./suite --platform android`],d={workflow:{summary:`Normal agent-device bootstrap, exploration, and validation loop`,body:`agent-device help workflow
1
+ import{er as e}from"./tv-remote.js";import{h as t,v as n}from"./registry.js";import{n as r,r as i}from"./command-schema.js";const a=[{label:`agent-device help manual-qa`,description:`Follow a manual test script with exact interactions and verification`},{label:`agent-device help dogfood`,description:`Explore an app and report issues with evidence`},{label:`agent-device help validate`,description:`Validate code changes, perf, visuals, logs, and cleanup`},{label:`agent-device help workflow`,description:`Full app automation reference for commands, refs, selectors, and waits`},{label:`agent-device help debugging`,description:`Use when logs, network, audio, perf memory, traces, alerts, or diagnostics matter`},{label:`agent-device help tv`,description:`Use when navigating Android TV or tvOS focus-first surfaces`},{label:`agent-device help react-native`,description:`Use when the target app is React Native, Expo, or a dev client`},{label:`agent-device help react-devtools`,description:`Use when inspecting components, props/state/hooks, renders, or profiles`},{label:`agent-device help cdp`,description:`Use when investigating JS heap growth, heap snapshots, or retainers`},{label:`agent-device help physical-device`,description:`Use when using a connected phone/tablet or iOS signing setup`},{label:`agent-device help remote`,description:`Use when working through cloud config, tenants, leases, or local tunnels`},{label:`agent-device help web`,description:`Use when automating a browser through agent-device sessions`},{label:`agent-device help macos`,description:`Use when targeting desktop, frontmost app, or menu bar surfaces`}],o=[`Write full command lines starting with agent-device; do not output pseudo commands, helper prose, pipes, grep, jq, or hidden stderr.`,`Default app loop: agent-device open <app> -> agent-device snapshot -i -> agent-device press/fill/click <target> --settle -> continue from that settled diff -> agent-device close.`,`Use --settle on every mutating app action that supports it: press, click, fill, longpress.`,`The settled diff is the next snapshot. Do not run wait stable or snapshot after settled:true unless the diff lacks the next target/evidence.`,`If --settle prints not settled, follow its hint before the next ref-based action.`,`Use refs or selectors as targets: @e12, label="Search", role=button label="Follow".`,`Pick the help mode below when the task is manual QA, dogfooding, engineering validation, or debugging.`],s=[`Planning output contract: when asked to plan commands, output command lines only: no prose, numbering, Markdown fences, pipes, or shell helpers.`,`If you did not use --settle, verify a mutation with diff snapshot (or diff snapshot -i), not a full snapshot: it prints only the added/removed/changed lines since the last snapshot in this session.`,`Network-backed or debounced results may arrive after the --settle quiet window; follow the settled action with wait text "Expected result" or wait <selector> instead of polling full snapshots.`,`Pin a raw CLI ref to the response that minted it with ~s<n> (n = refsGeneration or settle.refsGeneration): press @e12~s4. Pinned refs get exact staleness warnings instead of the coarse tree-changed one; plain refs stay valid input.`,`Plain snapshot reads state; snapshot -i refreshes current interactive refs only.`,`Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions.`,`Read-only visible/state question: use snapshot/get/is/find; use snapshot -i only when refs are needed.`,`Anti-pattern: snapshot -i followed by snapshot -i | grep ... or hiding command output with 2>/dev/null | jq ...; inspect raw agent-device output first, since hints and errors are part of the planning contract.`,`Truncated text/input preview: expand first with snapshot -s @e12, not get text.`,`React Native apps: read help react-native for Metro/Re.Pack, DevTools routing, and RN-specific blockers; use react-native dismiss-overlay for LogBox/RedBox overlays.`,`React Native JS memory leaks: read help cdp; use heap usage samples for a quick signal, then snapshot diff/leak-triplet for retained object proof.`,`Android RN/Expo/Re.Pack dev server: direct Android localhost URL opens with a port auto-configure host reachability.`,`Expo Go/dev clients: use the provided URL when given; on iOS use open "Expo Go" <url> --platform ios, then snapshot -i --platform ios to verify project UI. Do not use plain snapshot or snapshot --diff for this recovery check. Android URL opens infer the foreground package for logs/perf when possible.`,`Install flows: install/install-from-source first, then open the installed id with --relaunch.`,`Text fields: use fill <target> <text> --settle to replace a field value. Use type <text> only to append after focusing a field with press.`,`Clearing text: do not use fill <target> ""; use a visible clear/reset control or report that clearing is unsupported.`,`Android IME capture: if fill says input was captured by the keyboard/IME, inspect keyboard state and switch/disable handwriting before retrying; do not loop fill/type.`,`Implicit default sessions are scoped to the current worktree; if a prompt names a Session, include --session <name> on every command in that flow.`,`Run mutating commands serially within one session; parallelize only read-only commands or separate sessions/devices.`,`Clipboard limits: iOS Allow Paste cannot be automated through XCUITest; prefill with clipboard write. Android non-ASCII should use fill/type, not raw adb input.`,`After mutation: refs are stale. If the next target is known, use its selector directly; otherwise refresh with snapshot -i, scoped with -s when a stable container is known. Use press/click for taps.`,`Raw coordinates are fallback-only: use snapshot -i --json rects when iOS refs no-op or child refs are missing, then verify the action with diff snapshot -i or snapshot --diff.`,`Sparse or AX-unavailable snapshot: use screenshot for visual truth, press the visible coordinate to leave the bad screen, then retry AX with snapshot -i.`,`macOS context menus use click <ref> --button secondary, then snapshot -i. Longpress is for mobile hold gestures, not macOS secondary-click menus.`,`Remote lifecycle: use connect, then open, commands, close, and disconnect. Cloud, remote-config, direct proxy, and limrun use the same flow.`,`Direct proxy: run agent-device connect proxy --daemon-base-url <proxy-agent-device-url> before using a shared Mac proxy. Device leases are automatic on open and expire after five minutes of inactivity.`,`Batch JSON steps use "command" and structured "input"; legacy "positionals"/"flags" steps still run in CLI but are deprecated until the next major version.`,`Navigation: app-owned back uses back; system back uses back --system.`,`TV targets are focus-first: read help tv; use tv-remote press up|down|left|right|select to move D-pad/remote focus, tv-remote longpress <button> for a held remote button, and activate focused controls before assuming press/click @ref works.`,`Web browser sessions: read help web; first slice is web setup if needed -> web doctor -> open <url> --platform web -> snapshot -i -> click/fill/get/is/find/wait/screenshot -> close.`,`Verification commands must name the expected text/selector; bare screenshots/snapshots are not enough.`,`Debug evidence: Session state contains request diagnostics and runner.log; use logs clear --restart/mark/path, trace, and network dump --include headers for app evidence.`,`Full operating guide: agent-device help workflow. Exploratory QA: agent-device help dogfood.`],c=[`Default config files: ~/.agent-device/config.json, ./agent-device.json`,`Use --config <path> or AGENT_DEVICE_CONFIG to load one explicit config file.`],l=[{label:`AGENT_DEVICE_SESSION`,description:`Explicit session name`},{label:`AGENT_DEVICE_PLATFORM`,description:`Default platform binding`},{label:`AGENT_DEVICE_SESSION_LOCK`,description:`Bound-session conflict mode`},{label:`AGENT_DEVICE_DAEMON_BASE_URL`,description:`Connect to remote daemon`},{label:`AGENT_DEVICE_DAEMON_AUTH_TOKEN`,description:`Remote daemon service/API token`},{label:`AGENT_DEVICE_CLOUD_BASE_URL`,description:`Bridge/control-plane API origin for cloud auth and /api-keys`}],u=[`agent-device open Settings --platform ios`,`agent-device open https://example.com --platform web`,`agent-device open TextEdit --platform macos`,`agent-device snapshot -i`,`agent-device react-devtools get tree --depth 3`,`agent-device cdp memory usage sample --gc --label baseline`,`agent-device fill @e3 "test@example.com"`,`agent-device replay ./session.ad`,`agent-device test ./suite --platform android`],d={"manual-qa":{summary:`Follow manual test scripts with exact interactions and verification`,body:`agent-device help manual-qa
2
+
3
+ Use this when asked to follow a manual QA script, test case, checklist, acceptance flow, or user-provided instructions.
4
+
5
+ Contract:
6
+ Execute the script. Do not explore unrelated screens, read app source, invent missing requirements, or broaden scope.
7
+ Stop and report ambiguity when a required target or expected result is not visible after the documented recovery steps.
8
+
9
+ Loop:
10
+ 1. Open the requested app; use --relaunch only when the script needs fresh state.
11
+ 2. Run snapshot -i to get current refs for the next step.
12
+ 3. Run press/fill/click/longpress <ref-or-selector> --settle for each mutating step.
13
+ 4. Treat a settled:true diff as the next observation. Do not add wait stable or another snapshot when the diff already shows the next target or expected result.
14
+ 5. If --settle prints not settled, follow its hint before the next ref-based action.
15
+ 6. Verify named expectations with wait text/selector, get, is, find, or the settled diff. A bare screenshot/snapshot is not verification for a named expectation.
16
+ 7. Close the session when the script ends.
17
+
18
+ Targets:
19
+ Prefer refs from the latest snapshot -i or settled diff. Use durable selectors when the label/id is known: label="Search", id="submit", role=button label="Follow".
20
+ For text fields, use fill <target> <text> --settle to replace the field value; use type only to append to an already-focused field.
21
+ Do not use placeholders such as @ref, @eN, <button>, or <selector> in a final command plan. If the ref is unknown, first run snapshot -i.
22
+ Coordinates are fallback-only after refs/selectors fail or accessibility omits the target; use screenshot or snapshot -i --json to choose a visible center point.
23
+
24
+ Recovery:
25
+ Network/typeahead result missing: wait text "Expected result" or wait <selector>.
26
+ Keyboard blocks target: keyboard dismiss when supported, then snapshot -i.
27
+ Sparse or recovered accessibility snapshot: use screenshot as visual truth, leave the bad screen if needed, then retry snapshot -i.
28
+ Non-hittable success hint: verify with the settled diff or snapshot; retarget by a better ref/selector if the UI did not change.`},workflow:{summary:`Normal agent-device bootstrap, exploration, and validation loop`,body:`agent-device help workflow
2
29
 
3
30
  Version-matched operating guide for normal agent-device work.
4
31
 
5
32
  Core loop:
6
- devices/apps -> open -> snapshot or snapshot -i -> get/is/find/wait or press/fill/scroll/back -> verify with diff snapshot -> close
7
- After a mutating command, prefer diff snapshot (or diff snapshot -i) over a full snapshot to verify the effect: it diffs the rendered snapshot lines against the previous one in this session and prints only what changed, so verification does not re-pay the cost of the whole tree.
8
-
9
- Fresh machine or first iOS run:
10
- Run agent-device doctor --platform ios first. Besides preflight checks it warms the iOS XCTest runner build cache in the background, so the first open skips the runner build (~10s). To block until fully warm instead, run agent-device prepare ios-runner.
33
+ Start with the top-level Agent Starting Point for the default settle-first loop. This topic is the full reference for command shapes, refs, selectors, waits, recovery, and platform limits.
34
+ If you intentionally skip --settle or use a command that does not support it, verify a mutation with diff snapshot (or diff snapshot -i) instead of a full snapshot: it diffs the rendered snapshot lines against the previous one in this session and prints only what changed.
11
35
 
12
36
  Command shape:
13
37
  Plans should use agent-device commands, not raw platform tools, pseudo commands, package-manager aliases, or helper prose.
@@ -19,7 +43,7 @@ Command shape:
19
43
  Snapshot refs look like @e12. After snapshot -i, use the exact @eN ref from that output.
20
44
  If the exact ref is not known yet, first output snapshot -i, then use a concrete example shape like press @e12 in the next command; do not write @<ref>, @ref, @Label_Name, or @eN placeholders.
21
45
  Close means agent-device close. App-owned back means back; system back means back --system.
22
- Taps are press or click; tap is an alias for press. Gestures use swipe, longpress, or gesture <pan|fling|swipe|pinch|rotate|transform>. Use gesture swipe left|right for reliable in-page horizontal swipes, and gesture swipe right-edge for left-edge navigation/back gestures. Android swipe, pinch, rotate, and transform use provider-native touch injection when available, then the bundled touch helper. iOS simulator transform uses private XCTest synthesis for a continuous two-finger pan/scale/rotation path; otherwise it reports UNSUPPORTED_OPERATION.
46
+ Taps are press or click; tap is an alias for press. On Android TV and tvOS, read help tv and use tv-remote press up|down|left|right|select to move D-pad/remote focus before activating controls; use tv-remote longpress <button> for a held remote button. Gestures use swipe, longpress, or gesture <pan|fling|swipe|pinch|rotate|transform>. Use gesture swipe left|right for reliable in-page horizontal swipes, and gesture swipe right-edge for left-edge navigation/back gestures. Android swipe, pinch, rotate, and transform use provider-native touch injection when available, then the bundled touch helper. iOS simulator transform uses private XCTest synthesis for a continuous two-finger pan/scale/rotation path; otherwise it reports UNSUPPORTED_OPERATION.
23
47
 
24
48
  Bootstrap:
25
49
  agent-device devices --platform ios
@@ -46,17 +70,17 @@ Snapshots and refs:
46
70
  @e13 [textinput] label="Notes" preview="Leave at side..." truncated -> snapshot -s @e13 before reading.
47
71
  @e14 [cell] label="Profiles" focused -> tvOS focus is currently on this row.
48
72
  [off-screen below] 4 items: "Privacy", "About" -> scroll down, then snapshot -i; those are hints, not refs.
49
- Re-snapshot after navigation, submit, typing/fill, modal/list/reload/dynamic changes when you need new refs.
73
+ For press/fill/click/longpress, prefer --settle and continue from its settled diff when it exposes the next target or evidence. Refresh with snapshot -i only when you did not settle, settle printed not settled, or the settle output lacks what you need.
50
74
  Anti-pattern: snapshot -i followed by snapshot -i | grep ..., or adding 2>/dev/null | jq ... before reading the raw command output.
51
75
  Refs from the first snapshot remain valid until you press, click, fill, type, scroll, go back, wait for async UI, or otherwise change app state.
52
- A --settle response is the observation for that mutation. If its diff already shows the next target or final evidence, use that fresh ref or answer from the diff instead of taking a follow-up snapshot.
53
- After a mutation, prefer a known selector/label directly (for example press 'label="Send"') because interaction commands refresh interactive state internally. If you need to discover the new control, use snapshot -i, or snapshot -i -s "Composer" when a stable container label/id can scope the refresh.
76
+ After a mutation, prefer a known selector/label directly (for example press 'label="Send"') because interaction commands refresh interactive state internally. If you need to discover a new control not shown by settle, use snapshot -i, or snapshot -i -s "Composer" when a stable container label/id can scope the refresh.
54
77
  If typing/fill opened the keyboard or changed layout and the next target has no stable selector, run snapshot -i, use the fresh ref, then verify with wait/find or diff snapshot -i.
55
78
  For a targeted query, use find/get/is. If you truly need the full tree again, pass --force-full.
56
79
  Off-screen summaries are scroll hints; use scroll, not swipe, then snapshot -i.
57
80
  Missing target in a long list: use a short manual scroll + snapshot loop with a max attempt count. If a named target is summarized as off-screen below/above, use scroll down/up, then snapshot -i; do not use scroll bottom/top because the target may appear before the absolute list edge. Use scroll bottom/top only when the task explicitly asks for the list edge. Edge scrolls verify hidden content with snapshots and stop when no matching hidden content remains.
58
81
  Truncated text/input previews: do not use get text first; expand with snapshot -s @ref (for example snapshot -s @e7), then read the scoped output.
59
82
  Rare iOS accessibility gaps: if a row ref is shown disabled/hittable:false and press @ref reports success but no UI change, or a horizontal tab/filter bar is collapsed into one composite/seekbar with no child refs, run agent-device snapshot -i --json to read rects, compute the target center, press x y, then diff snapshot -i. Coordinates are fallback-only; document why you used them.
83
+ TV focus gaps: read help tv. If a fresh snapshot exposes focused nodes, verify with is focused <selector>; use wait focused=true only on apps where repeated snapshots preserve focus metadata. If the app exposes only a surface view or focus metadata is transient, use screenshot/snapshot diff as visual truth and tv-remote press directions/select; do not switch to raw adb keyevent in command plans.
60
84
 
61
85
  Selectors:
62
86
  Use selectors as positional targets: id="field-email" or label="Allow".
@@ -100,7 +124,7 @@ Read-only and waits:
100
124
  For network-backed search/typeahead, --settle confirms the local UI quieted after fill/press; use wait text "Expected result" or wait <result selector> for server-loaded content that can arrive later.
101
125
  agent-device find "Increment" press --json
102
126
  For async/list text presence, prefer wait text over is visible when no interaction is needed.
103
- wait stable [quietMs] [timeoutMs] (defaults 500/10000) replaces guessed sleeps between actions and snapshots in the core loop: it polls the interactive-only tree and resolves once two or more consecutive captures are unchanged for quietMs, or fails with the standard wait-timeout shape plus the last capture stats (captures, nodeCount) on timeout; use it after relaunch/navigation instead of a fixed wait <ms> before the next snapshot or action.
127
+ wait stable [quietMs] [timeoutMs] (defaults 500/10000) is a fallback for open/relaunch/navigation, unsupported mutating commands, or a mutation where you intentionally did not use --settle. Do not insert wait stable after press/fill/click/longpress --settle when the settled diff already shows what changed. wait stable polls the interactive-only tree and resolves once two or more consecutive captures are unchanged for quietMs, or fails with the standard wait-timeout shape plus capture stats (captures, nodeCount).
104
128
  Use snapshot -i only when refs are needed for an action or targeted query.
105
129
  Ambiguous find: add --first or --last. If info is not visible/exposed, report that gap instead of typing/searching/navigating to reveal it.
106
130
 
@@ -113,6 +137,7 @@ Navigation and gestures:
113
137
  If app-owned back is ambiguous or has just misrouted, prefer a visible nav/back button ref, tab-bar ref, or deep link over repeated back/system back.
114
138
  App-owned action sheets, menus, and camera/scan screens are normal UI. After opening one, run snapshot -i or wait for the option, press by label/ref, handle visible permission sheets through UI or platform-supported native alerts, then wait for a concrete result before returning to chat/form state.
115
139
  Keep count/pause/pattern on one swipe; flags are --count, --pause-ms, --pattern ping-pong.
140
+ For repeated iOS gesture smoke checks, use press <x> <y> --count <n> --jitter-px <n> for tap series and swipe <x1> <y1> <x2> <y2> --count <n> for drag series.
116
141
  longpress accepts coordinates, @refs, or selectors. Prefer @ref/selector from snapshot -i; use coordinates only as a fallback when accessibility refs miss the exact target. Duration and gesture scale/center are positional:
117
142
  agent-device longpress 300 500 800
118
143
  agent-device longpress @e12 800
@@ -145,7 +170,7 @@ Validation and evidence:
145
170
  agent-device press 124 817
146
171
  agent-device snapshot -i
147
172
  Startup/CPU/memory/frame first pass: perf metrics --json (bare perf and metrics are aliases). Focused frame/jank health: perf frames --json. Memory-only sample: perf memory sample --json returns compact JSON with bounded top offenders. Heap/memgraph artifact escalation: perf memory snapshot --out heap.artifact; use --kind android-hprof on Android or --kind memgraph on supported Apple simulator/macOS app sessions. Android native profiling: perf cpu profile start|stop|report --kind simpleperf --out <path>; Android native traces: perf trace start|stop --kind perfetto --out <path>. Artifact collectors return compact state/path/size metadata only; raw heap/profile/trace files stay on disk. Treat native perf output as the agent evidence: for example, a Perfetto stop can return state=stopped, outPath=/tmp/app.perfetto-trace, sizeBytes=5392410, and method=adb-shell-perfetto while the 5.3 MB raw trace stays in the artifact. This is better than raw dumps for agents because it is stable, bounded, and keeps large artifacts out of context. heapprofd is deferred until Perfetto plumbing is available. Replay maintenance: replay -u ./flow.ad.
148
- Recording: record start/stop. Use --max-size to cap the longest edge and --quality medium|high to choose output quality across Android and Apple targets. By default, stop burns touch overlays into the video; use record start --hide-touches for the fastest raw recording. Android record start publishes a durable device manifest. Android adb screenrecord has a 180s platform limit, so longer Android recordings are returned as multiple MP4 chunks while the daemon stays alive; after daemon restart, record stop recovers only manifest-owned chunks and warns when gesture overlays are unavailable. For gesture-heavy iOS simulator proof videos, prefer --hide-touches because overlay timing depends on a stable runner session while gestures are executing. Tracing: trace start ./trace.log, trace stop ./trace.log. Paths are positional.
173
+ Recording: record start/stop. The default scope is app and expects an active session created by open <app>; this keeps app proof videos tied to the intended app session. Use record start --scope device/system to explicitly request whole-screen capture where the selected backend supports it, such as recordings that intentionally span multiple apps, home screen, settings, or app transitions. Use --max-size to cap the longest edge and --quality medium|high to choose output quality across Android and Apple targets. By default, stop burns touch overlays into the video; use record start --hide-touches for the fastest raw recording. Android record start publishes a durable device manifest. Android adb screenrecord has a 180s platform limit, so longer Android recordings are returned as multiple MP4 chunks while the daemon stays alive; after daemon restart, record stop recovers only manifest-owned chunks and warns when gesture overlays are unavailable. For gesture-heavy iOS simulator proof videos, prefer --hide-touches because overlay timing depends on a stable runner session while gestures are executing. Tracing: trace start ./trace.log, trace stop ./trace.log. Paths are positional.
149
174
  Stable known flow: batch ./steps.json, not workflow batch.
150
175
  Inline batch JSON example:
151
176
  agent-device batch --steps '[{"command":"open","input":{"app":"settings"}},{"command":"wait","input":{"kind":"duration","durationMs":100}}]'
@@ -183,12 +208,12 @@ Validation and evidence:
183
208
  agent-device test ./e2e/maestro --maestro --device udid1,emulator-5554 --shard-all 2
184
209
 
185
210
  React Native dev loop:
186
- JS-only change with Metro connected:
211
+ JS-only change with Metro or Re.Pack connected:
187
212
  agent-device metro reload
188
213
  agent-device find "Home"
189
214
  Do not use agent-device reload. Use open --relaunch for native startup reset.
190
- React Native apps: use help react-native for Metro/Fast Refresh, DevTools routing, and RN-specific blockers; use react-native dismiss-overlay for LogBox/RedBox overlays.
191
- Android RN/Expo Metro: direct Android URL opens to localhost/127.0.0.1/[::1] with a port auto-configure host reachability. Manual adb reverse tcp:<port> tcp:<port> is only needed for app/package launches or unsupported flows where the app cannot reach local Metro.
215
+ React Native apps: use help react-native for Metro/Re.Pack Fast Refresh, DevTools routing, and RN-specific blockers; use react-native dismiss-overlay for LogBox/RedBox overlays.
216
+ Android RN/Expo/Re.Pack dev server: direct Android URL opens to localhost/127.0.0.1/[::1] with a port auto-configure host reachability. Manual adb reverse tcp:<port> tcp:<port> is only needed for app/package launches or unsupported flows where the app cannot reach the local dev server.
192
217
  Expo Go is a host shell. Use a provided project URL instead of inventing a bundle id; if no URL is provided but a target/app name is provided, open that target and do not inspect project files to find one. On iOS, prefer host + URL when the host shell is known because direct URL open can report success while leaving the runner/shell focused; verify with snapshot -i after opening:
193
218
  agent-device open "Expo Go" exp://127.0.0.1:8081 --platform ios
194
219
  agent-device snapshot -i --platform ios
@@ -200,7 +225,9 @@ React Native dev loop:
200
225
  agent-device open exp://127.0.0.1:8081 --platform android
201
226
  Android URL/deep-link opens infer the foreground package after launch when possible, so logs/perf can remain package-bound. If perf still says no package is associated, open the host package/app id first, then open the URL in the same session.
202
227
  If apps lookup misses the project but shows Expo Go/dev-client and a project URL is available, open the URL/host shell; if no URL is available, ask instead of inventing an app id.
203
- Expo Dev Client/development builds: open the installed dev-client app id/name; if a dev-client URL is provided, open that URL next. For Metro setup use metro prepare --kind expo.
228
+ Expo Dev Client/development builds: open the installed dev-client app id/name; if a dev-client URL is provided, open that URL next. For Expo setup use metro prepare --kind expo.
229
+ Re.Pack/Rspack apps: use metro prepare --kind repack, or rely on auto-detection when @callstack/repack is in the selected package.json. The command name remains metro for compatibility, but prepare/reload use the shared React Native dev-server /status, /reload, and bundle URL protocol. prepare runs react-native rspack-start when rspack.config.* exists, and react-native webpack-start when webpack.config.* exists.
230
+ Module Federation super-apps: treat the native host and each JS-only remote as separate dev-server endpoints. Prepare or reload the host/root with its port, and pass a remote's --bundle-url or --metro-port when you need to target that remote's Re.Pack server.
204
231
 
205
232
  Guarantees:
206
233
  Statements of fact for agents to reason from without probing them via trial commands. Each is backed by source in the agent-device repo; behavior changes land with an updated statement here.
@@ -213,12 +240,48 @@ Guarantees:
213
240
  Wait: wait text|selector|@ref polls on a fixed interval (300ms) up to a timeout (10s default, override with the trailing timeoutMs positional) by re-capturing state each poll; it does not push/subscribe. Timing out raises a command failure rather than returning a not-found result.
214
241
 
215
242
  Escalate:
243
+ help manual-qa scripted manual QA and acceptance checks
244
+ help dogfood exploratory QA report workflow
245
+ help validate engineering self-validation loops
216
246
  help debugging logs, network, alerts, traces, flaky runtime failures
247
+ help tv Android TV and tvOS focus-first remote navigation
217
248
  help react-devtools React Native performance, profiling, props/state/hooks, slow renders, rerenders
218
- help react-native React Native app automation hazards, overlays, Metro, and routing
249
+ help react-native React Native app automation hazards, overlays, Metro/Re.Pack, and routing
219
250
  help remote remote/cloud config, tenant, lease, local service tunnels
220
- help macos desktop, frontmost-app, menu bar surfaces
221
- help dogfood exploratory QA report workflow`},debugging:{summary:`Targeted failure evidence without dumping stale context`,body:`agent-device help debugging
251
+ help macos desktop, frontmost-app, menu bar surfaces`},tv:{summary:`Android TV and tvOS focus-first remote navigation`,body:`agent-device help tv
252
+
253
+ Use this when the target is Android TV, Apple TV, or tvOS. TV surfaces are focus-first: move focus with remote/D-pad buttons, then activate the focused control.
254
+
255
+ Core loop:
256
+ agent-device open Settings --platform android --target tv --session tv
257
+ agent-device snapshot -i --platform android --target tv --session tv
258
+ agent-device tv-remote press down --platform android --target tv --session tv
259
+ agent-device is focused 'label="Profiles"' --platform android --target tv --session tv
260
+ agent-device tv-remote press select --platform android --target tv --session tv
261
+ agent-device screenshot ./tv-focus.png --overlay-refs --platform android --target tv --session tv
262
+
263
+ Buttons:
264
+ tv-remote press up|down|left|right|select|menu|home|back
265
+ tv-remote longpress select
266
+ tv-remote press select --duration-ms 500
267
+ ok, center, and enter are input aliases for select; command output still reports button: "select".
268
+ longpress is CLI sugar for --duration-ms 500. --duration-ms overrides that preset.
269
+ --duration-ms holds a tvOS remote button for that duration. On Android TV, any positive duration maps to the ADB longpress form because Android input keyevent has no exact hold duration.
270
+
271
+ Android TV:
272
+ Android TV uses ADB keyevents behind agent-device tv-remote. Keep command plans on agent-device; do not switch to raw adb keyevent.
273
+ Use --target tv when a host has both phone/tablet and TV emulators/devices.
274
+
275
+ tvOS:
276
+ tvOS is driven by the Siri Remote focus engine, not coordinate taps.
277
+ back maps to the Menu remote button; home maps to the Home remote button.
278
+ Use --platform ios --target tv for Apple TV simulators and devices.
279
+
280
+ Focus and visual truth:
281
+ If snapshot -i exposes a focused node, verify it with is focused <selector>.
282
+ Use wait focused=true only when repeated snapshots preserve focus metadata for the app.
283
+ If the app exposes only a surface view, or focus metadata is transient, use screenshot --overlay-refs, screenshot, or diff snapshot as visual truth and keep moving focus with tv-remote.
284
+ Do not assume press/click @ref works on Android TV or tvOS until the desired element is focused.`},debugging:{summary:`Targeted failure evidence without dumping stale context`,body:`agent-device help debugging
222
285
 
223
286
  Use this when behavior fails, hangs, times out, throws alerts, or needs runtime evidence.
224
287
 
@@ -236,6 +299,12 @@ Logs:
236
299
  agent-device open MyApp --platform ios --relaunch --launch-console ./artifacts/app.console.log
237
300
  --launch-console is only for direct iOS simulator app launches, not URL opens.
238
301
 
302
+ Events:
303
+ Use events for a compact session timeline without dumping full app logs.
304
+ agent-device events
305
+ agent-device events 50 100
306
+ Events preserve command names, status, durations, paths, session/device/app identifiers, refs/selectors, and coordinates. Typed text, clipboard writes, push/event payloads, raw unknown command arguments, and matching raw message fragments are replaced with length-only placeholders. --no-record suppresses action.recorded entries, but request start/finish entries still record command, status, and timing.
307
+
239
308
  Network:
240
309
  Use network dump for recent session HTTP traffic parsed from app logs.
241
310
  agent-device network dump --include headers
@@ -450,20 +519,16 @@ Choose the next help topic:
450
519
  Remote/cloud config, leases, and local service tunnels: help remote.
451
520
 
452
521
  React Native dev loop:
453
- Before QA/dogfood runs, use doctor to separate environment setup from app failures (on iOS simulators doctor also warms the runner build cache in the background):
454
- agent-device doctor --platform android
455
- agent-device doctor --platform ios
456
- agent-device doctor --platform android --app com.example.app
457
- agent-device doctor --remote --remote-config ./remote.json
522
+ Do not run doctor as routine QA/dogfood prep. Use doctor only when the user asks for setup diagnostics or a command failure points to an unhealthy device, runner, dev-server, or remote environment.
458
523
  For "start from screen X" flows, prefer open --relaunch before the first snapshot so the app does not reuse a prior in-progress navigation state.
459
- JS-only change with Metro connected:
524
+ JS-only change with Metro or Re.Pack connected:
460
525
  agent-device metro reload
461
526
  agent-device find "Home"
462
527
  Do not use agent-device reload. Use open --relaunch for native startup reset.
463
- Android RN/Expo Metro: direct Android localhost URL opens with a port auto-configure host reachability. For app/package launches, run metro prepare when the app cannot reach local Metro.
464
- Verify Metro from the same host context that owns Metro. If a sandboxed shell cannot curl localhost:8081/status but an unrestricted host shell can, Metro is running and the sandbox probe is not authoritative.
465
- adb reverse only affects Android device-to-host traffic. It does not prove host-to-Metro reachability, and it does not fix a redbox caused by a stale or wrong Metro/app state.
466
- Multiple local worktrees can reuse one native iOS simulator build by running each worktree's Metro on a different port and opening the same installed app on different simulators with explicit runtime hints:
528
+ Android RN/Expo/Re.Pack dev server: direct Android localhost URL opens with a port auto-configure host reachability. For app/package launches, run metro prepare when the app cannot reach the local dev server.
529
+ Verify Metro/Re.Pack from the same host context that owns the dev server. If a sandboxed shell cannot curl localhost:8081/status but an unrestricted host shell can, the dev server is running and the sandbox probe is not authoritative.
530
+ adb reverse only affects Android device-to-host traffic. It does not prove host-to-dev-server reachability, and it does not fix a redbox caused by a stale or wrong bundle/app state.
531
+ Multiple local worktrees can reuse one native iOS simulator build by running each worktree's dev server on a different port and opening the same installed app on different simulators with explicit runtime hints:
467
532
  agent-device open "React Navigation Example" --platform ios --device "iPhone 17" --session rn-a --metro-host 127.0.0.1 --metro-port 8081 --relaunch
468
533
  agent-device open "React Navigation Example" --platform ios --device "iPhone 17 Pro" --session rn-b --metro-host 127.0.0.1 --metro-port 8082 --relaunch
469
534
  iOS simulator opens write React Native's per-simulator debug server settings before launch, so those ports do not conflict across simulators. Use separate sessions/devices, close both sessions when done, and rebuild only for native changes or dependency changes that affect the binary. One simulator cannot run two copies of the same bundle id.
@@ -721,7 +786,7 @@ Coverage:
721
786
  Navigation, forms, empty/error/loading states, offline or retry behavior, permissions, settings, accessibility labels, orientation/keyboard, and obvious performance stalls.
722
787
  React Native warning/error overlays can be real findings or test blockers. Capture them, use react-native dismiss-overlay if unrelated, re-snapshot, and report them.
723
788
  Expo Go/dev-client shells: use the provided exp:// or dev-client URL and record whether the shell, project load, or app UI is being tested. On iOS dogfood, prefer agent-device open "Expo Go" <url> when Expo Go is the known shell, then snapshot -i to confirm the project UI rather than the runner splash.
724
- Android RN/Expo Metro: direct Android localhost URL opens with a port auto-configure host reachability.
789
+ Android RN/Expo/Re.Pack dev server: direct Android localhost URL opens with a port auto-configure host reachability.
725
790
  Categories: visual, functional, UX, content, performance, diagnostics, permissions, accessibility.
726
791
  Severity: critical blocks a core flow/data/crashes; high breaks a major feature; medium has friction or workaround; low is polish.
727
792
 
@@ -752,12 +817,44 @@ Report shape:
752
817
 
753
818
  Rules:
754
819
  Findings must come from observed runtime behavior, not source reads.
755
- Re-snapshot after each mutation.
820
+ After each mutation, use the --settle diff as evidence when available; otherwise re-snapshot.
756
821
  Keep commands in the report reproducible; use selectors or refs from fresh snapshots, not guessed coordinates.
757
822
  Prefer refs for exploration and selectors for deterministic replay.
758
823
  Use logs, network, screenshot --overlay-refs, trace, perf metrics, perf frames, or react-devtools only when they add evidence to a specific issue.
759
824
  Never delete screenshots, videos, traces, or report artifacts during a session.
760
- Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`}};function f(e){let t=e.endsWith(`?`),n=t?e.slice(0,-1):e;return t?`[${n}]`:`<${n}>`}function p(e,t,n){let r=n.endsWith(`?`),i=r?n.slice(0,-1):n,a=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i),o=a||t.usageOverride!==void 0&&t.usageOverride.startsWith(`${e} ${i}`);return r?a?`[${i}]`:o?i:`[${i}]`:o?i:`<${i}>`}function m(e,t){if(t.usageOverride)return t.usageOverride;let n=(t.positionalArgs??[]).map(f),r=(t.allowedFlags??[]).flatMap(e=>h(e).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`);return[e,...n,...r].join(` `)}function h(e){return t().filter(t=>t.key===e)}function g(e,t){return t.listUsageOverride?t.listUsageOverride:[e,...(t.positionalArgs??[]).map(n=>p(e,t,n))].join(` `)}function _(){let t=C(e().map(e=>{let t=r(e);return{name:e,schema:t,usage:g(e,t)}})),i=b(`Global Flags:`,y(n)),d=S(`Agent Starting Point:`,o),f=S(`Agent Quickstart:`,s);return`agent-device <command> [args] [--json]
825
+ Escalate to help debugging or help react-devtools when runtime symptoms require those tools.`},validate:{summary:`Engineering self-validation with device evidence and cleanup`,body:`agent-device help validate
826
+
827
+ Use this when validating a code change, release candidate, performance fix, visual behavior, logging path, replay, or device-facing regression.
828
+
829
+ Contract:
830
+ Prove the changed behavior through public agent-device surfaces. Do not validate against stale dist output, a retained stale daemon, or a runner built before the change.
831
+ Keep evidence reproducible: exact commands, target device/app, observed output, artifact paths, and cleanup status.
832
+
833
+ Before device verification:
834
+ If TypeScript runtime or CLI output changed, run pnpm build first, then pnpm clean:daemon so bin/agent-device.mjs uses current dist and no stale daemon is serving old code.
835
+ If Apple runner code changed, run pnpm build:xcuitest and avoid inherited retained runners from older source.
836
+ Use open --relaunch when startup state matters. Use a purpose-specific --session for multi-step validation.
837
+
838
+ Loop:
839
+ 1. Build or prepare the changed surface with the repo command that owns it.
840
+ 2. Open the target app/device state explicitly.
841
+ 3. Use snapshot -i and press/fill/click/longpress --settle for UI-driving steps.
842
+ 4. Use the settled diff as evidence when it shows the changed behavior; otherwise verify with wait/get/is/find, screenshot, logs, network, perf, or trace based on the claim.
843
+ 5. Record timings, token/output size, screenshots/videos, logs, or perf artifacts only when they answer the validation question.
844
+ 6. Close sessions and release leases before finishing.
845
+
846
+ Evidence:
847
+ CLI/runtime freshness: pnpm build, pnpm clean:daemon, then agent-device --version or the command under test.
848
+ Apple runner freshness: pnpm build:xcuitest, then a live agent-device command on the target simulator/device.
849
+ Visual claim: screenshot, optionally screenshot --overlay-refs when target mapping matters.
850
+ Runtime/logging claim: logs clear --restart, logs mark, reproduce, logs path.
851
+ Network claim: network dump --include headers when headers are relevant.
852
+ Performance claim: perf metrics, perf frames, perf memory sample, or trace artifacts with bounded output.
853
+ Replay/regression claim: replay or test through the public command path.
854
+
855
+ Report:
856
+ Summarize what changed, exact validation commands, pass/fail observations, artifact paths, and residual risk.
857
+ If live validation is blocked, state the blocker, device/session, and exact next command needed.`}};function f(e){let t=e.endsWith(`?`),n=t?e.slice(0,-1):e;return t?`[${n}]`:`<${n}>`}function p(e,t,n){let r=n.endsWith(`?`),i=r?n.slice(0,-1):n,a=/^[a-z-]+(?:\|[a-z-]+)+$/i.test(i),o=a||t.usageOverride!==void 0&&t.usageOverride.startsWith(`${e} ${i}`);return r?a?`[${i}]`:o?i:`[${i}]`:o?i:`<${i}>`}function m(e,t){if(t.usageOverride)return t.usageOverride;let n=(t.positionalArgs??[]).map(f),r=(t.allowedFlags??[]).flatMap(e=>h(e).map(e=>e.usageLabel??e.names[0])).map(e=>`[${e}]`);return[e,...n,...r].join(` `)}function h(e){return n().filter(t=>t.key===e)}function g(e,t){return t.listUsageOverride?t.listUsageOverride:[e,...(t.positionalArgs??[]).map(n=>p(e,t,n))].join(` `)}function _(){let n=C(e().map(e=>{let t=r(e);return{name:e,schema:t,usage:g(e,t)}})),i=b(`Global Flags:`,y(t)),d=S(`Agent Starting Point:`,o),f=S(`Agent Quickstart:`,s);return`agent-device <command> [args] [--json]
761
858
 
762
859
  CLI to automate supported app, device, desktop, and web targets for AI agents.
763
860
 
@@ -765,7 +862,7 @@ ${d}
765
862
 
766
863
  ${x(`Agent Workflows:`,a)}
767
864
 
768
- ${t}
865
+ ${n}
769
866
 
770
867
  ${i}
771
868
 
@@ -776,7 +873,7 @@ ${S(`Configuration:`,c)}
776
873
  ${x(`Environment:`,l)}
777
874
 
778
875
  ${S(`Examples:`,u)}
779
- `}function v(){return _()}function y(e){return t().filter(t=>e.has(t.key)&&t.usageLabel!==void 0&&t.usageDescription!==void 0)}function b(e,t){return x(e,t.map(e=>({label:e.usageLabel??``,description:e.usageDescription??``})))}function x(e,t){if(t.length===0)return`${e}\n (none)`;let n=Math.max(...t.map(e=>e.label.length))+2,r=[e];for(let e of t)r.push(` ${e.label.padEnd(n)}${e.description}`);return r.join(`
876
+ `}function v(){return _()}function y(e){return n().filter(t=>e.has(t.key)&&t.usageLabel!==void 0&&t.usageDescription!==void 0)}function b(e,t){return x(e,t.map(e=>({label:e.usageLabel??``,description:e.usageDescription??``})))}function x(e,t){if(t.length===0)return`${e}\n (none)`;let n=Math.max(...t.map(e=>e.label.length))+2,r=[e];for(let e of t)r.push(` ${e.label.padEnd(n)}${e.description}`);return r.join(`
780
877
  `)}function S(e,t){return t.length===0?`${e}\n (none)`:[e,...t.map(e=>` ${e}`)].join(`
781
878
  `)}function C(e){return x(`Commands:`,e.map(e=>({label:e.usage,description:e.schema.summary??e.schema.helpDescription})))}function w(e){let t=T(e);if(t)return t;let n=i(e);if(!n)return null;let r=m(e,n),a=y(new Set(n.allowedFlags??[])),o=[];a.length>0&&o.push(b(`Command flags:`,a));let s=o.length>0?`\n\n${o.join(`
782
879
 
@@ -1,2 +1,2 @@
1
- import{Rn as e}from"./device-rotation.js";import{n as t}from"./registry.js";import{t as n}from"./cli-output.js";import{n as r}from"./command-surface.js";function i(t,n,r){if(t.json){e({success:!0,data:n});return}let i=r?.();i&&a(i)}function a(e){process.stdout.write(e.endsWith(`
1
+ import{Kn as e}from"./tv-remote.js";import{n as t}from"./registry.js";import{t as n}from"./cli-output.js";import{n as r}from"./command-surface.js";function i(t,n,r){if(t.json){e({success:!0,data:n});return}let i=r?.();i&&a(i)}function a(e){process.stdout.write(e.endsWith(`
2
2
  `)?e:`${e}\n`)}const o=t();function s(e,t,n){let r=o[e];if(!r)throw Error(`Missing CLI reader for command: ${e}`);return r(t,n)}async function c(e){return(await l(e)).result}async function l(e){let t=s(e.command,e.positionals,e.flags),i=await r(e.client,e.command,t);return{result:i,cliOutput:n({name:e.command,input:t,result:i})}}export{i,l as n,s as r,c as t};