@swmansion/argent 0.28.1-next.8 → 0.29.0

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 (54) hide show
  1. package/agents/argent-environment-inspector.md +7 -7
  2. package/agents/references/quality-control-checklist.md +14 -14
  3. package/assets/manifest.json +2 -2
  4. package/bin/argent-android-devtools-0.3.0.apk +0 -0
  5. package/bin/darwin/ax-service +0 -0
  6. package/bin/darwin/simulator-server +0 -0
  7. package/bin/darwin/tvos-ax-service +0 -0
  8. package/bin/darwin/tvos-hid-daemon +0 -0
  9. package/bin/linux/simulator-server +0 -0
  10. package/bin/linux-arm64/simulator-server +0 -0
  11. package/bin/tcp/ax-service +0 -0
  12. package/bin/win32/simulator-server.exe +0 -0
  13. package/dist/cli-cmds.mjs +4 -1
  14. package/dist/client.d.ts +18 -0
  15. package/dist/client.js +3 -0
  16. package/dist/installer.mjs +9 -2
  17. package/dist/mcp-server.mjs +13 -1
  18. package/dist/tool-args.generated.d.ts +87 -77
  19. package/dist/tool-server.cjs +948 -370
  20. package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
  21. package/dylibs/libKeyboardPatch.dylib +0 -0
  22. package/dylibs/libNativeDevtoolsIos.dylib +0 -0
  23. package/dylibs/tcp/libArgentInjectionBootstrap.dylib +0 -0
  24. package/dylibs/tcp/libKeyboardPatch.dylib +0 -0
  25. package/dylibs/tcp/libNativeDevtoolsIos.dylib +0 -0
  26. package/dylibs/tvos/libArgentInjectionBootstrap.dylib +0 -0
  27. package/dylibs/tvos/libKeyboardPatch.dylib +0 -0
  28. package/dylibs/tvos/libNativeDevtoolsIos.dylib +0 -0
  29. package/package.json +1 -1
  30. package/rules/argent.md +16 -16
  31. package/skills/argent-android-emulator-setup/SKILL.md +9 -9
  32. package/skills/argent-create-flow/references/flow-yaml.md +11 -11
  33. package/skills/argent-create-flow/references/live-authoring.md +11 -11
  34. package/skills/argent-create-flow/references/reliability-and-recovery.md +13 -13
  35. package/skills/argent-device-interact/SKILL.md +47 -47
  36. package/skills/argent-device-interact/references/chromium.md +1 -1
  37. package/skills/argent-device-interact/references/gesture-examples.md +7 -7
  38. package/skills/argent-device-interact/references/secrets.md +6 -6
  39. package/skills/argent-lens/SKILL.md +21 -21
  40. package/skills/argent-metro-debugger/SKILL.md +24 -24
  41. package/skills/argent-metro-debugger/references/failure-scenarios.md +11 -11
  42. package/skills/argent-metro-debugger/references/source-maps.md +4 -4
  43. package/skills/argent-native-profiler/SKILL.md +13 -13
  44. package/skills/argent-qa-flows/SKILL.md +3 -3
  45. package/skills/argent-react-native-app-workflow/SKILL.md +18 -18
  46. package/skills/argent-react-native-optimization/SKILL.md +12 -12
  47. package/skills/argent-react-native-optimization/references/fix-reference.md +10 -10
  48. package/skills/argent-react-native-optimization/references/lint-rules.md +1 -1
  49. package/skills/argent-react-native-profiler/SKILL.md +25 -25
  50. package/skills/argent-react-native-profiler/references/diagnostic-tools.md +19 -19
  51. package/skills/argent-screen-recording/SKILL.md +14 -14
  52. package/skills/argent-test-ui-flow/SKILL.md +9 -9
  53. package/skills/argent-tv-interact/SKILL.md +19 -19
  54. package/bin/argent-android-devtools-0.2.0.apk +0 -0
@@ -8,7 +8,7 @@ These tools can be called independently without starting a profiling session.
8
8
  { "port": 8081, "device_id": "<UDID>", "top_n": 20 }
9
9
  ```
10
10
 
11
- Call `react-profiler-renders`. Returns render counts and durations per component — useful for spotting hot components before a full profile.
11
+ Call `react-profiler-renders`. Returns render counts and durations per component, useful for spotting hot components before a full profile.
12
12
 
13
13
  ## Component hierarchy
14
14
 
@@ -16,7 +16,7 @@ Call `react-profiler-renders`. Returns render counts and durations per component
16
16
  { "port": 8081, "device_id": "<UDID>", "max_depth": 10, "filter": "MyComponent" }
17
17
  ```
18
18
 
19
- Call `react-profiler-fiber-tree`. Inspect `useMemoCache` presence to confirm React Compiler is active for a given component. If `useMemoCache` is absent, the compiler bailed out for that component — memoization hints are safe to propose.
19
+ Call `react-profiler-fiber-tree`. Inspect `useMemoCache` presence to confirm React Compiler is active for a given component. If `useMemoCache` is absent, the compiler bailed out for that component; memoization hints are safe to propose.
20
20
 
21
21
  ## Console logs
22
22
 
@@ -24,7 +24,7 @@ Call `react-profiler-fiber-tree`. Inspect `useMemoCache` presence to confirm Rea
24
24
  { "port": 8081, "device_id": "<UDID>" }
25
25
  ```
26
26
 
27
- Call `debugger-log-registry`. When connected (`status: "connected"`) it returns a summary with entry counts by level, message clusters, and the log file path. Use `Grep` on the log file to filter by level or search for specific messages. When the debugger is unreachable it does not fail — it returns `{ status: "not_connected", reason, detail, guidance }` with no log file; follow the `guidance` (do not retry in a loop, and do not try to grep a file in this state).
27
+ Call `debugger-log-registry`. When connected (`status: "connected"`) it returns a summary with entry counts by level, message clusters, and the log file path. Use `Grep` on the log file to filter by level or search for specific messages. When the debugger is unreachable it does not fail: it returns `{ status: "not_connected", reason, detail, guidance }` with no log file; follow the `guidance` (do not retry in a loop, and do not try to grep a file in this state).
28
28
 
29
29
  ---
30
30
 
@@ -40,16 +40,16 @@ These require a completed profiling session (`react-profiler-stop` + `react-prof
40
40
 
41
41
  Call `profiler-cpu-query`. Modes:
42
42
 
43
- - `top_functions` — global CPU hotspots. Add `time_window_ms: { start, end }` to filter.
44
- - `time_window` — CPU breakdown for a specific time range (e.g. during a slow commit).
45
- - `call_tree` — callers and callees of a specific `function_name`.
46
- - `component_cpu` — aggregate CPU during all commits of a `component_name`.
43
+ - `top_functions`: global CPU hotspots. Add `time_window_ms: { start, end }` to filter.
44
+ - `time_window`: CPU breakdown for a specific time range (e.g. during a slow commit).
45
+ - `call_tree`: callers and callees of a specific `function_name`.
46
+ - `component_cpu`: aggregate CPU during all commits of a `component_name`.
47
47
 
48
48
  > **Component names:** pass the name exactly as the report shows it. The report strips
49
49
  > `Forget(...)` / `Memo(...)` / `ForwardRef(...)` wrappers and marks them with a
50
50
  > `[React Compiler]` / `[React.memo] `/ `[forwardRef]` tag; both that displayed name and the
51
51
  > underlying wrapped name resolve. If a name maps to several distinct fibers the tool lists
52
- > the exact names to retry with rather than merging them — a combined total would not describe
52
+ > the exact names to retry with rather than merging them; a combined total would not describe
53
53
  > any real component.
54
54
 
55
55
  ## Commit query
@@ -60,10 +60,10 @@ Call `profiler-cpu-query`. Modes:
60
60
 
61
61
  Call `profiler-commit-query`. Modes:
62
62
 
63
- - `by_component` — all commits where a component rendered.
64
- - `by_time_range` — commits in a `time_range_ms` window.
65
- - `by_index` — full detail of a single `commit_index`.
66
- - `cascade_tree` — parent-child re-render cascade for a commit.
63
+ - `by_component`: all commits where a component rendered.
64
+ - `by_time_range`: commits in a `time_range_ms` window.
65
+ - `by_index`: full detail of a single `commit_index`.
66
+ - `cascade_tree`: parent-child re-render cascade for a commit.
67
67
 
68
68
  ## iOS Instruments query
69
69
 
@@ -73,10 +73,10 @@ Call `profiler-commit-query`. Modes:
73
73
 
74
74
  Call `profiler-stack-query` after `native-profiler-analyze`. Modes:
75
75
 
76
- - `hang_stacks` — full CPU context during a specific hang.
77
- - `function_callers` — who calls a specific native `function_name`.
78
- - `thread_breakdown` — CPU time split by thread, optionally filtered.
79
- - `leak_stacks` — memory leak details, optionally filtered by `object_type`.
76
+ - `hang_stacks`: full CPU context during a specific hang.
77
+ - `function_callers`: who calls a specific native `function_name`.
78
+ - `thread_breakdown`: CPU time split by thread, optionally filtered.
79
+ - `leak_stacks`: memory leak details, optionally filtered by `object_type`.
80
80
 
81
81
  ## Combined report
82
82
 
@@ -94,8 +94,8 @@ Call `profiler-combined-report` when both React Profiler and iOS Instruments ran
94
94
 
95
95
  Call `profiler-load`. Modes:
96
96
 
97
- - `list` — show all saved profiling sessions (React + iOS) in `/tmp/argent-profiler-cwd/`.
98
- - `load_react` — reload a React profiler session by `session_id` + `device_id`. Populates the `port:device_id`-keyed in-memory cache for `profiler-cpu-query` and `profiler-commit-query` (which must be called with the same `device_id` afterward).
99
- - `load_native` — re-parse native profiler XML by `session_id` and `device_id`. Populates session for `profiler-stack-query`.
97
+ - `list`: show all saved profiling sessions (React + iOS) in `/tmp/argent-profiler-cwd/`.
98
+ - `load_react`: reload a React profiler session by `session_id` + `device_id`. Populates the `port:device_id`-keyed in-memory cache for `profiler-cpu-query` and `profiler-commit-query` (which must be called with the same `device_id` afterward).
99
+ - `load_native`: re-parse native profiler XML by `session_id` and `device_id`. Populates session for `profiler-stack-query`.
100
100
 
101
101
  Use this to revisit an earlier profiling session without re-profiling. Each `react-profiler-analyze` run saves raw data with a unique timestamp.
@@ -5,19 +5,19 @@ description: Record a video of an iOS simulator or Android emulator/device scree
5
5
 
6
6
  ## 1. Tools
7
7
 
8
- - `screen-recording-start` — start capturing the screen of a booted device to a video file. Frames come from the same simulator-server backend that `screenshot` and the interaction tools already use, and are encoded live to h264 mp4 (constant 30 fps, device-native resolution).
9
- - `screen-recording-stop` — stop the capture, finalize the container, and retrieve the video as a downloadable artifact (`video.hostPath` for co-located clients).
8
+ - `screen-recording-start`: start capturing the screen of a booted device to a video file. Frames come from the same simulator-server backend that `screenshot` and the interaction tools already use, and are encoded live to h264 mp4 (constant 30 fps, device-native resolution).
9
+ - `screen-recording-stop`: stop the capture, finalize the container, and retrieve the video as a downloadable artifact (`video.hostPath` for co-located clients).
10
10
 
11
- One recording per device at a time; different devices can record concurrently. Recording does not disturb anything else reading the device — a preview window can stay open on the same screen.
11
+ One recording per device at a time; different devices can record concurrently. Recording does not disturb anything else reading the device: a preview window can stay open on the same screen.
12
12
 
13
13
  ---
14
14
 
15
15
  ## 2. Critical: never leave a recording running
16
16
 
17
- A recording does not stop itself before its `timeLimitSeconds` cap, so a forgotten one keeps capturing until the cap fires — holding the recording session, wasting disk, and delaying the video you are waiting on (and with `trimStatic: false` it comes back padded with dead air). Two safety nets exist — use both:
17
+ A recording does not stop itself before its `timeLimitSeconds` cap, so a forgotten one keeps capturing until the cap fires, holding the recording session, wasting disk, and delaying the video you are waiting on (and with `trimStatic: false` it comes back padded with dead air). Two safety nets exist; use both:
18
18
 
19
- 1. **Set yourself a reminder the moment the recording starts.** You know the expected capture length (the interaction you are about to drive). Immediately after `screen-recording-start` returns, schedule a wake-up for that expected end time using whatever your harness provides — a built-in reminder/wakeup or scheduled-task tool if you have one, otherwise a background shell running `sleep <expected-seconds>` whose completion notification pulls you back. When it fires, call `screen-recording-stop`. Do not rely on remembering.
20
- 2. **Read the tool-result notes.** While a recording is running, every argent tool result carries a `NOTE:` reminding you it is still going and how to stop it. If the note says the recording already ended (time limit hit), still call `screen-recording-stop` — that is what hands you the file.
19
+ 1. **Set yourself a reminder the moment the recording starts.** You know the expected capture length (the interaction you are about to drive). Immediately after `screen-recording-start` returns, schedule a wake-up for that expected end time using whatever your harness provides: a built-in reminder/wakeup or scheduled-task tool if you have one, otherwise a background shell running `sleep <expected-seconds>` whose completion notification pulls you back. When it fires, call `screen-recording-stop`. Do not rely on remembering.
20
+ 2. **Read the tool-result notes.** While a recording is running, every argent tool result carries a `NOTE:` reminding you it is still going and how to stop it. If the note says the recording already ended (time limit hit), still call `screen-recording-stop`; that is what hands you the file.
21
21
 
22
22
  ---
23
23
 
@@ -25,25 +25,25 @@ A recording does not stop itself before its `timeLimitSeconds` cap, so a forgott
25
25
 
26
26
  1. Ensure the target device is booted and the app is in the state you want the video to open on (`list-devices`, `launch-app`, `argent-device-interact`).
27
27
  2. Call `screen-recording-start` with `udid` and a `timeLimitSeconds` slightly above the expected interaction length (default 180, max 600). Taps and swipes are drawn into the video by default (see the touch-visualizer note below); pass `showTouches: false` for a clean raw-screen capture.
28
- 3. Set the end-of-recording reminder described in §2 — this step is not optional.
28
+ 3. Set the end-of-recording reminder described in §2; this step is not optional.
29
29
  4. Drive the interaction to capture: gestures, navigation, typing (`argent-device-interact`). Prefer `run-sequence` for tight multi-step interactions so tool-call latency does not pad the video.
30
30
  5. Call `screen-recording-stop` with the same `udid`. It returns `{ video, durationMs, wallClockMs?, trimmedMs?, warning? }`; `video` is an artifact whose resolved path points at the durably-saved file (see below). The video is already final when stop returns (the watermark is stamped during capture, not in a second pass), so stop takes well under a second.
31
31
  6. Check `warning`: it reports cap-triggered stops, early encoder exits, a dropped frame stream, and possibly-truncated containers. Verify the file plays (or at least has a sane size) before presenting it to the user.
32
32
 
33
- **Where the file lands (durable, not scratch).** Unlike most argent artifacts (which live in a disposable temp cache the OS reclaims), a finished recording is saved durably on the **client** into `<project>/.argent/recordings/` — the project being the nearest ancestor of the client's working directory with a `.git`/`package.json`/`.argent`, or `~/.argent/recordings/` when the client isn't inside a project. This holds even for a remote `argent link` tool-server: the mp4 is written on the client host, not the server. The destination can be changed with the `recordings.directory` configuration (`argent config set recordings.directory <dir>`, global by default, `--scope project` for a per-repo choice; project wins when both are set) — the value may be absolute, `~`-prefixed, or relative to the project root, and is always resolved on the client host. The saved name is `screen-recording-<device>-<timestamp>.mp4`; if that name is already taken the new file lands beside it as `… (2).mp4` rather than overwriting. Because these files persist in the working tree, mention the path to the user (and note that they are untracked — add them to `.gitignore` or clean them up if they shouldn't be committed).
33
+ **Where the file lands (durable, not scratch).** Unlike most argent artifacts (which live in a disposable temp cache the OS reclaims), a finished recording is saved durably on the **client** into `<project>/.argent/recordings/`, the project being the nearest ancestor of the client's working directory with a `.git`/`package.json`/`.argent`, or `~/.argent/recordings/` when the client isn't inside a project. This holds even for a remote `argent link` tool-server: the mp4 is written on the client host, not the server. The destination can be changed with the `recordings.directory` configuration (`argent config set recordings.directory <dir>`, global by default, `--scope project` for a per-repo choice; project wins when both are set); the value may be absolute, `~`-prefixed, or relative to the project root, and is always resolved on the client host. The saved name is `screen-recording-<device>-<timestamp>.mp4`; if that name is already taken the new file lands beside it as `… (2).mp4` rather than overwriting. Because these files persist in the working tree, mention the path to the user (and note that they are untracked; add them to `.gitignore` or clean them up if they shouldn't be committed).
34
34
 
35
- **Static-frame trimming (on by default).** Stretches where the screen does not change are collapsed: the first second of each still stretch is kept so pauses read naturally, then unchanged frames are dropped until something moves again (a change of even a couple of pixels counts). So you can leave a recording running across slow steps, waits, or thinking time without padding the clip with dead air — a 40-second session with 5 seconds of real activity comes back as a ~5-7 second video. When trimming removed anything, stop also returns `wallClockMs` (real elapsed time) and `trimmedMs` (how much was cut); `durationMs` is always the length of the video you actually get. Pass `trimStatic: false` to `screen-recording-start` when you want a faithful real-time recording (e.g. to measure how long something took on screen).
35
+ **Static-frame trimming (on by default).** Stretches where the screen does not change are collapsed: the first second of each still stretch is kept so pauses read naturally, then unchanged frames are dropped until something moves again (a change of even a couple of pixels counts). So you can leave a recording running across slow steps, waits, or thinking time without padding the clip with dead air: a 40-second session with 5 seconds of real activity comes back as a ~5-7 second video. When trimming removed anything, stop also returns `wallClockMs` (real elapsed time) and `trimmedMs` (how much was cut); `durationMs` is always the length of the video you actually get. Pass `trimStatic: false` to `screen-recording-start` when you want a faithful real-time recording (e.g. to measure how long something took on screen).
36
36
 
37
- **Touch visualizer (on by default).** Every interaction argent drives is drawn straight into the video: a pulse marks each tap, a fading comet trail follows swipes and drags, and paired markers show the two contact points of a pinch or rotate. This makes a recording self-explanatory — a viewer can see _where_ each gesture landed rather than watching the UI react to an invisible finger. It is rendered by simulator-server into the frame stream (nothing is composited host-side), so it costs nothing extra and never appears in a `screenshot`. Pass `showTouches: false` to `screen-recording-start` to record the raw screen with no overlay (e.g. when capturing exactly what the user would see). If simulator-server cannot enable it, the recording still succeeds and stop returns a `warning` saying touches are not shown.
37
+ **Touch visualizer (on by default).** Every interaction argent drives is drawn straight into the video: a pulse marks each tap, a fading comet trail follows swipes and drags, and paired markers show the two contact points of a pinch or rotate. This makes a recording self-explanatory: a viewer can see _where_ each gesture landed rather than watching the UI react to an invisible finger. It is rendered by simulator-server into the frame stream (nothing is composited host-side), so it costs nothing extra and never appears in a `screenshot`. Pass `showTouches: false` to `screen-recording-start` to record the raw screen with no overlay (e.g. when capturing exactly what the user would see). If simulator-server cannot enable it, the recording still succeeds and stop returns a `warning` saying touches are not shown.
38
38
 
39
39
  ---
40
40
 
41
41
  ## 4. Platform notes and limits
42
42
 
43
- - **What can be recorded**: anything simulator-server drives — iOS simulators, Android emulators, and physical Android devices. The only length limit is `timeLimitSeconds` (max 600).
44
- - **The timeline is paced to a steady 30 fps**: a device only emits a frame when its screen changes, so captured frames are re-paced onto a fixed timeline rather than bunching up. With static-frame trimming off (`trimStatic: false`) that timeline is wall-clock accurate — a completely still screen still comes back as a full-length video (compressing to almost nothing) and `durationMs` matches the time you actually recorded. With trimming on (the default, see §3) still stretches past the grace window are collapsed, so `durationMs` is the trimmed video length and `wallClockMs` carries the real elapsed time.
43
+ - **What can be recorded**: anything simulator-server drives: iOS simulators, Android emulators, and physical Android devices. The only length limit is `timeLimitSeconds` (max 600).
44
+ - **The timeline is paced to a steady 30 fps**: a device only emits a frame when its screen changes, so captured frames are re-paced onto a fixed timeline rather than bunching up. With static-frame trimming off (`trimStatic: false`) that timeline is wall-clock accurate: a completely still screen still comes back as a full-length video (compressing to almost nothing) and `durationMs` matches the time you actually recorded. With trimming on (the default, see §3) still stretches past the grace window are collapsed, so `durationMs` is the trimmed video length and `wallClockMs` carries the real elapsed time.
45
45
  - **One size per video**: the video keeps the size of the screen at the start of the recording. If the screen changes size, argent keeps the proportions of the new screen and adds black bars. On a foldable simulator, start the recording on the panel that you need at full size.
46
46
  - **Android**: records at the device's native resolution; secure screens (DRM, some password fields) come out black.
47
- - **Unsupported**: tvOS simulators, physical iPhones, Chromium apps, Vega/Fire TV, and remote (`remote:`-prefixed) simulators — none of them expose a readable frame stream. For a single still frame use `screenshot`; for a replayable interaction script use `argent-create-flow` instead of a video.
47
+ - **Unsupported**: tvOS simulators, physical iPhones, Chromium apps, Vega/Fire TV, and remote (`remote:`-prefixed) simulators; none of them expose a readable frame stream. For a single still frame use `screenshot`; for a replayable interaction script use `argent-create-flow` instead of a video.
48
48
  - **ffmpeg is required**: it is the encoder, so `screen-recording-start` fails up front with an install hint if it is missing (`brew install ffmpeg` on macOS). It is resolved from `PATH` plus the usual Homebrew prefixes.
49
- - **Watermark**: the Argent logo + "By @swmansion" is stamped bottom-left while encoding, faint (20% opacity) and per-pixel contrast-matched to the background (light logo over dark UI, dark logo over light UI). On by default — turn it off with `argent disable video-watermark` (re-enable with `argent enable video-watermark`). The flag is read when the recording starts.
49
+ - **Watermark**: the Argent logo + "By @swmansion" is stamped bottom-left while encoding, faint (20% opacity) and per-pixel contrast-matched to the background (light logo over dark UI, dark logo over light UI). On by default; turn it off with `argent disable video-watermark` (re-enable with `argent enable video-watermark`). The flag is read when the recording starts.
@@ -7,7 +7,7 @@ description: Autonomously test an app UI (iOS or Android) by running interact-sc
7
7
 
8
8
  Physical iPhone (`kind: "device"`): read `argent-ios-device-interact` first. `launch-app` before anything; `describe` fails while the app is backgrounded.
9
9
 
10
- The interaction tool names are identical on iOS and Android — `gesture-tap`, `gesture-swipe`, `describe`, `screenshot`, `launch-app`, etc. — and the tool-server auto-dispatches based on the `udid` you pass (UUID-shape → iOS, adb serial → Android).
10
+ The interaction tool names are identical on iOS and Android (`gesture-tap`, `gesture-swipe`, `describe`, `screenshot`, `launch-app`, etc.) and the tool-server auto-dispatches based on the `udid` you pass (UUID-shape → iOS, adb serial → Android).
11
11
 
12
12
  **Before testing, resolve which device to test on.** Call `list-devices` and follow `<device_selection_rule>`: prefer a running device on any platform;
13
13
 
@@ -26,15 +26,15 @@ For implementation tasks that modify visible UI, this workflow can also serve as
26
26
 
27
27
  1. **Baseline screenshot**: Call `screenshot` to see the current UI state. For visual regression comparison or UI change verification, capture the baseline at `scale: 1.0` with `includeImageInContext: false` and keep the returned `path` before editing whenever feasible.
28
28
  2. **Find target**: Before tapping, use a discovery tool to get element coordinates:
29
- - **React Native apps**: use `debugger-component-tree` — it returns component names with (tap: x,y) coordinates. This is the preferred tool for RN apps on either platform. To use it, resolve the `argent-react-native-app-workflow` skill for setup; on Android you must also run `adb -s <serial> reverse tcp:8081 tcp:8081` so Metro is reachable from the device.
29
+ - **React Native apps**: use `debugger-component-tree`: it returns component names with (tap: x,y) coordinates. This is the preferred tool for RN apps on either platform. To use it, resolve the `argent-react-native-app-workflow` skill for setup; on Android you must also run `adb -s <serial> reverse tcp:8081 tcp:8081` so Metro is reachable from the device.
30
30
  - **Standard app screens and in-app modals**: use `describe`. On iOS this returns the AX tree (falls back to native-devtools when AX is empty); on Android it returns the uiautomator tree in the same DescribeNode shape.
31
- - **Permission prompts / system modal overlays**: try `describe` first. Fall back to `screenshot` only if the overlay is not exposed reliably. When the app raises its own permission dialog, answer it here — that's the real flow under test. To take a prompt _out_ of the flow (pre-grant/deny before launch, re-enable a permission the user already denied, or reset it so the dialog reappears), use the `argent-settings-permissions` skill during setup instead of interacting with the dialog.
31
+ - **Permission prompts / system modal overlays**: try `describe` first. Fall back to `screenshot` only if the overlay is not exposed reliably. When the app raises its own permission dialog, answer it here; that's the real flow under test. To take a prompt _out_ of the flow (pre-grant/deny before launch, re-enable a permission the user already denied, or reset it so the dialog reappears), use the `argent-settings-permissions` skill during setup instead of interacting with the dialog.
32
32
  - **Fallback**: use `screenshot` to estimate where the desired component is, then verify immediately after the action.
33
- 3. **Interact**: Perform the action (`gesture-tap`, `gesture-swipe`, `keyboard`, `button`, ...) — you receive a screenshot automatically.
34
- 4. **Verify**: Check the returned screenshot for expected results. If it shows a loading/transitional state, prefer blocking until it settles with `await-ui-element` (expected element `visible`, or a spinner `hidden`) over a guessed delay — but only with a selector you can trust (`text`/`identifier`/`role`) that the screen is known to have or that you saw in a prior `describe`; a guessed one just times out. Otherwise use a short fixed wait. Pick evidence by what's being asserted:
35
- - **Visual** (layout, spacing, color, typography, image/icon rendering, clipping, overflow, text rendering): prefer `screenshot-diff` against the baseline captured in step 1 — it surfaces pixel-visible changes the auto-screenshot might miss. Fall back to visual inspection of the auto-screenshot only when a stable baseline isn't available.
33
+ 3. **Interact**: Perform the action (`gesture-tap`, `gesture-swipe`, `keyboard`, `button`, ...): you receive a screenshot automatically.
34
+ 4. **Verify**: Check the returned screenshot for expected results. If it shows a loading/transitional state, prefer blocking until it settles with `await-ui-element` (expected element `visible`, or a spinner `hidden`) over a guessed delay, but only with a selector you can trust (`text`/`identifier`/`role`) that the screen is known to have or that you saw in a prior `describe`; a guessed one just times out. Otherwise use a short fixed wait. Pick evidence by what's being asserted:
35
+ - **Visual** (layout, spacing, color, typography, image/icon rendering, clipping, overflow, text rendering): prefer `screenshot-diff` against the baseline captured in step 1: it surfaces pixel-visible changes the auto-screenshot might miss. Fall back to visual inspection of the auto-screenshot only when a stable baseline isn't available.
36
36
  - **Structural** (navigation state, element existence, accessibility labels/values, selection, hierarchy, route): verify with `describe`, `debugger-component-tree`, or `native-describe-screen`.
37
- - **Runtime / log / network** (console errors, API calls, persistence, timing): verify with `view-network-logs`, `debugger-log-registry`, `debugger-evaluate`, or targeted tests. Note `debugger-log-registry` returns `{ status: "not_connected", reason, guidance }` with no log file when the debugger is unreachable — that is not evidence about the app; follow its `guidance` to reconnect, then re-verify.
37
+ - **Runtime / log / network** (console errors, API calls, persistence, timing): verify with `view-network-logs`, `debugger-log-registry`, `debugger-evaluate`, or targeted tests. Note `debugger-log-registry` returns `{ status: "not_connected", reason, guidance }` with no log file when the debugger is unreachable; that is not evidence about the app; follow its `guidance` to reconnect, then re-verify.
38
38
  - **Mixed**: collect evidence for each relevant class.
39
39
  - Report the combined verdict: expected behavior, observed behavior, evidence used, and any blocker for requested visual diffing.
40
40
  5. **Repeat** for each step in the flow.
@@ -67,7 +67,7 @@ Steps:
67
67
  7. screenshot → verify home screen appeared
68
68
  ```
69
69
 
70
- > **Credentials:** never type plaintext credentials — use a `{{secret:<NAME>}}` placeholder in `keyboard`, resolved server-side so the value never enters agent context. It comes from the `ARGENT_SECRET_<NAME>` environment variable or an argent secrets file (`.argent/secrets.env` in the project, `~/.argent/secrets.env`, or an `ARGENT_SECRET_`-prefixed key in the project's `.env` / `.env.local`). If the name is not defined, the failure lists the available names and every path it checked — ask the user to add it to one of those files (which applies immediately) instead of pasting the secret into the conversation. Never invent credentials or echo secret values into reports or saved files.
70
+ > **Credentials:** never type plaintext credentials; use a `{{secret:<NAME>}}` placeholder in `keyboard`, resolved server-side so the value never enters agent context. It comes from the `ARGENT_SECRET_<NAME>` environment variable or an argent secrets file (`.argent/secrets.env` in the project, `~/.argent/secrets.env`, or an `ARGENT_SECRET_`-prefixed key in the project's `.env` / `.env.local`). If the name is not defined, the failure lists the available names and every path it checked; ask the user to add it to one of those files (which applies immediately) instead of pasting the secret into the conversation. Never invent credentials or echo secret values into reports or saved files.
71
71
 
72
72
  ### Scroll and navigation
73
73
 
@@ -110,7 +110,7 @@ Steps:
110
110
  - If tap misses target: re-run discovery tool (`describe` / `debugger-component-tree`), retry once with new coordinates.
111
111
  - If a permission dialog or modal is visible: re-run `describe` first. Stay in screenshot-driven navigation only when the overlay is not exposed reliably, then switch back to `describe` / `debugger-component-tree` as soon as it is dismissed.
112
112
  - If tap fails twice at same coordinates: stop, re-discover, report if element not found.
113
- - If a **saved flow** fails during `flow-execute` replay (as opposed to live test steps above): follow `argent-create-flow`'s [Diagnose a replay failure](../argent-create-flow/references/reliability-and-recovery.md#diagnose-a-replay-failure) — classify the failure, inspect the actual screen, repair the smallest justified unit, then replay the full flow.
113
+ - If a **saved flow** fails during `flow-execute` replay (as opposed to live test steps above): follow `argent-create-flow`'s [Diagnose a replay failure](../argent-create-flow/references/reliability-and-recovery.md#diagnose-a-replay-failure): classify the failure, inspect the actual screen, repair the smallest justified unit, then replay the full flow.
114
114
 
115
115
  ## Tips
116
116
 
@@ -1,67 +1,67 @@
1
1
  ---
2
2
  name: argent-tv-interact
3
- description: Control and inspect TV apps via argent — Apple TV (tvOS), Android TV (leanback), and Amazon Fire TV (Vega). Boot the target, read focus, navigate with the D-pad remote, type, screenshot, and on Vega debug the JS runtime (evaluate, console logs, network inspector). Use when a task targets a TV (runtimeKind "tv", or platform "vega"), or mentions Apple TV / tvOS / Android TV / leanback / Vega / Fire TV / VVD.
3
+ description: Control and inspect TV apps via argent, Apple TV (tvOS), Android TV (leanback), and Amazon Fire TV (Vega). Boot the target, read focus, navigate with the D-pad remote, type, screenshot, and on Vega debug the JS runtime (evaluate, console logs, network inspector). Use when a task targets a TV (runtimeKind "tv", or platform "vega"), or mentions Apple TV / tvOS / Android TV / leanback / Vega / Fire TV / VVD.
4
4
  ---
5
5
 
6
6
  # Argent TV (Apple TV + Android TV + Fire TV)
7
7
 
8
8
  ## Critical
9
9
 
10
- - A TV is **focus-driven, not touch-driven.** Drive every interaction with `describe` + `tv-remote` + `keyboard`; never use `gesture-*` / coordinate taps — they don't apply on any TV platform.
11
- - **Always `describe` before navigating** to find the live cursor and your target — never guess focus from a screenshot. The cursor is the focused element; on **Vega** the toolkit often leaves `focused` false and marks the highlighted item `[selected]`, so treat `[selected]` as the cursor when nothing reports `[focused]`.
12
- - Pass the `udid` from `list-devices` — an Apple TV simulator UDID or an Android TV / Vega `serial`. Dispatch is automatic from the id; the same tools drive all three.
10
+ - A TV is **focus-driven, not touch-driven.** Drive every interaction with `describe` + `tv-remote` + `keyboard`; never use `gesture-*` / coordinate taps; they don't apply on any TV platform.
11
+ - **Always `describe` before navigating** to find the live cursor and your target; never guess focus from a screenshot. The cursor is the focused element; on **Vega** the toolkit often leaves `focused` false and marks the highlighted item `[selected]`, so treat `[selected]` as the cursor when nothing reports `[focused]`.
12
+ - Pass the `udid` from `list-devices`: an Apple TV simulator UDID or an Android TV / Vega `serial`. Dispatch is automatic from the id; the same tools drive all three.
13
13
 
14
14
  ## The navigation loop
15
15
 
16
- 1. `describe` — find the cursor and your target (returns the focused element + all focusable ones, not a tap tree).
17
- 2. `tv-remote` — move focus toward the target. Prefer **one** call with a path ending in `select`, e.g. `{button:["down","right","select"]}`; count rows/columns from the frames to build the path.
16
+ 1. `describe`: find the cursor and your target (returns the focused element + all focusable ones, not a tap tree).
17
+ 2. `tv-remote`: move focus toward the target. Prefer **one** call with a path ending in `select`, e.g. `{button:["down","right","select"]}`; count rows/columns from the frames to build the path.
18
18
  3. `describe` again to confirm. On a miss, repeat.
19
19
 
20
20
  ## Tools
21
21
 
22
- - `describe {udid}` — focus view: the focused / `[selected]` element + focusable elements with labels and normalized frames. Call before and after navigating. Empty tree → see the per-platform notes.
23
- - `tv-remote {udid, button}` — D-pad / remote. `button` is one key **or a whole path** (run in one call). Keys: `up`/`down`/`left`/`right`, `select`, `back`, `menu`, `home`, `playPause`, plus media keys `rewind`/`fastForward`/`next`/`previous`/`volumeUp`/`volumeDown`/`mute`. Single: `{button:"down"}`; repeat: `{button:"down", repeat:3}`; path: `{button:["up","right","select"]}`.
24
- - `keyboard {udid, text}` — type into the focused field (focus it with `tv-remote` first). One call carries `text` or `key`, never both — to type and then press a key, send two `keyboard` steps in one `run-sequence`. Named `key` presses (e.g. `{key:"enter"}`) work on Vega; on Apple TV / Android TV move focus with `tv-remote` instead.
25
- - `launch-app` / `restart-app` / `reinstall-app {udid, bundleId}` — `bundleId` from the app manifest. Vega `reinstall-app` takes `appPath` = a `.vpkg`.
26
- - `screenshot {udid, scale?}` — Apple TV via `xcrun simctl io` (downscaled); Android TV / Vega host-side via `adb` / `screencap`.
22
+ - `describe {udid}`: focus view: the focused / `[selected]` element + focusable elements with labels and normalized frames. Call before and after navigating. Empty tree → see the per-platform notes.
23
+ - `tv-remote {udid, button}`: D-pad / remote. `button` is one key **or a whole path** (run in one call). Keys: `up`/`down`/`left`/`right`, `select`, `back`, `menu`, `home`, `playPause`, plus media keys `rewind`/`fastForward`/`next`/`previous`/`volumeUp`/`volumeDown`/`mute`. Single: `{button:"down"}`; repeat: `{button:"down", repeat:3}`; path: `{button:["up","right","select"]}`.
24
+ - `keyboard {udid, text}`: type into the focused field (focus it with `tv-remote` first). One call carries `text` or `key`, never both; to type and then press a key, send two `keyboard` steps in one `run-sequence`. Named `key` presses (e.g. `{key:"enter"}`) work on Vega; on Apple TV / Android TV move focus with `tv-remote` instead.
25
+ - `launch-app` / `restart-app` / `reinstall-app {udid, bundleId}`: `bundleId` from the app manifest. Vega `reinstall-app` takes `appPath` = a `.vpkg`.
26
+ - `screenshot {udid, scale?}`: Apple TV via `xcrun simctl io` (downscaled); Android TV / Vega host-side via `adb` / `screencap`.
27
27
 
28
28
  ## Per-platform
29
29
 
30
30
  ### Apple TV (tvOS simulator)
31
31
 
32
32
  - Boot like any iOS sim (`boot-device`); the AX + HID daemons auto-start on the first `describe` / `tv-remote` (first call may take a few seconds). Give the RN bundle a few seconds to render before the first `describe`.
33
- - Media-transport / volume keys are **rejected** — the sim's HID stack ignores them (they work on Android TV / Vega).
33
+ - Media-transport / volume keys are **rejected**: the sim's HID stack ignores them (they work on Android TV / Vega).
34
34
  - Dev build: `open-url {udid, url:"<scheme>://expo-development-client/?url=http%3A%2F%2F<HOST_IP>%3A8081"}` (`<HOST_IP>` = your Mac's LAN IP, shown on the launcher).
35
35
 
36
36
  ### Android TV (leanback emulator)
37
37
 
38
- - Boot the leanback AVD like any emulator — see `argent-android-emulator-setup`.
38
+ - Boot the leanback AVD like any emulator; see `argent-android-emulator-setup`.
39
39
  - **`describe` may report zero focusables on a screen with visible tiles**: many `react-native-tvos` screens use RN's own focus engine, invisible to the OS accessibility tree. `describe` auto-falls-back to the full UI tree (and says so in the hint); `tv-remote` still moves focus, so drive blind + `screenshot` to confirm.
40
- - Dev build: `adb -s <serial> reverse tcp:8081 tcp:8081`, deep-link `<pkg>://expo-development-client/?url=http%3A%2F%2F10.0.2.2%3A8081`, dismiss the first dev-menu with `adb shell input keyevent KEYCODE_DPAD_CENTER` (not Back — Back exits the app).
40
+ - Dev build: `adb -s <serial> reverse tcp:8081 tcp:8081`, deep-link `<pkg>://expo-development-client/?url=http%3A%2F%2F10.0.2.2%3A8081`, dismiss the first dev-menu with `adb shell input keyevent KEYCODE_DPAD_CENTER` (not Back: Back exits the app).
41
41
 
42
42
  ### Fire TV (Vega / VVD)
43
43
 
44
44
  - `list-devices` shows a `serial` (use as `udid`) and a `vvdImage`. `boot-device {vvdImage}` (e.g. `"tv"`) starts the single SDK-managed VVD; skip if one already runs.
45
45
  - **Stop the VVD** with `vega virtual-device stop` in your shell. The CLI only tracks VVDs it started in the foreground, so it may report "not running" for one started via `boot-device`; to restart that one use `boot-device {vvdImage, force:true}` (stops then re-boots).
46
46
  - Empty `describe` tree → `restart-app` (the automation toolkit attaches at launch), then retry. Input ignored → enable developer mode in the VVD: `vsm developer-mode enable`.
47
- - Editing `node_modules` has no effect on a Release build — only Debug `.vpkg` builds load patchable JS.
47
+ - Editing `node_modules` has no effect on a Release build; only Debug `.vpkg` builds load patchable JS.
48
48
  - Profiling / crashes → `amazon-devices-buildertools-mcp` server (`analyze_perfetto_traces`, `get_app_hot_functions`, `symbolicate_acr`); docs via its `search_documentation` tool.
49
49
 
50
50
  ## Common gotchas
51
51
 
52
- - **Empty focus right after `launch-app` / `restart-app`** is the splash / loading window — `describe` retries internally; wait ~2-3s and retry on a cold start.
53
- - Passing a phone/tablet (`runtimeKind: "mobile"`) udid to `tv-remote` fails with a clear "tvOS-only" / "Android-TV-only" error — pick a TV target from `list-devices`.
52
+ - **Empty focus right after `launch-app` / `restart-app`** is the splash / loading window; `describe` retries internally; wait ~2-3s and retry on a cold start.
53
+ - Passing a phone/tablet (`runtimeKind: "mobile"`) udid to `tv-remote` fails with a clear "tvOS-only" / "Android-TV-only" error; pick a TV target from `list-devices`.
54
54
 
55
55
  ## Fast Refresh (dev builds)
56
56
 
57
- Needs a Debug build + Metro running. argent only _connects_ to Metro — start Metro and port-forward yourself (any platform). Metro is fixed on **:8081**.
57
+ Needs a Debug build + Metro running. argent only _connects_ to Metro; start Metro and port-forward yourself (any platform). Metro is fixed on **:8081**.
58
58
 
59
59
  - **Apple TV / Android TV:** use the dev-build deep-links above; `npm start` for Metro.
60
60
  - **Vega:** build/install a Debug `.vpkg` (`vega device install-app -p <path>`), `npm start`, `vega device start-port-forwarding --port 8081 --forward false`, then `vega device launch-app -a <appId>`. Confirm `http://localhost:8081/json/list` shows a `Hermes React Native` target; `.tsx` edits then hot-reload.
61
61
 
62
62
  ## Debugging the JS runtime (Vega)
63
63
 
64
- Once that same Debug build + Metro setup is in place, the JS-runtime tools work on a Vega VVD: `debugger-connect`, `debugger-status`, `debugger-evaluate`, `debugger-log-registry` (console logs), `view-network-logs`, and `view-network-request-details`. Verify with `debugger-status`: it returns a status result rather than an error when not connected — `status: "connected"` means the setup works; `status: "not_connected"` carries a `reason` and `guidance` (e.g. `metro_not_running` → Metro itself is not up). Vega-specific: on `no_app_connected`, check `vega device start-port-forwarding` **before** relaunching the app — a down device→host forward is the usual cause, and the generic guidance can't know about it. See the `argent-metro-debugger` skill.
64
+ Once that same Debug build + Metro setup is in place, the JS-runtime tools work on a Vega VVD: `debugger-connect`, `debugger-status`, `debugger-evaluate`, `debugger-log-registry` (console logs), `view-network-logs`, and `view-network-request-details`. Verify with `debugger-status`: it returns a status result rather than an error when not connected: `status: "connected"` means the setup works; `status: "not_connected"` carries a `reason` and `guidance` (e.g. `metro_not_running` → Metro itself is not up). Vega-specific: on `no_app_connected`, check `vega device start-port-forwarding` **before** relaunching the app: a down device→host forward is the usual cause, and the generic guidance can't know about it. See the `argent-metro-debugger` skill.
65
65
 
66
66
  Vega's React Native forks RN 0.72 and serves the legacy Hermes inspector, so three things differ from iOS / Android:
67
67