@swmansion/argent 0.11.0 → 0.12.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 (45) hide show
  1. package/README.md +13 -8
  2. package/bin/argent-android-devtools-0.1.0.apk +0 -0
  3. package/bin/argent-simulator-server.cjs +11 -3
  4. package/bin/darwin/ax-service +0 -0
  5. package/bin/darwin/resources/android/LICENSE.txt +186 -0
  6. package/bin/darwin/resources/android/README.md +11 -0
  7. package/bin/darwin/resources/android/arm64-v8a/libscreen-sharing-agent.so +0 -0
  8. package/bin/darwin/resources/android/armeabi-v7a/libscreen-sharing-agent.so +0 -0
  9. package/bin/darwin/resources/android/screen-sharing-agent.jar +0 -0
  10. package/bin/darwin/resources/android/x86_64/libscreen-sharing-agent.so +0 -0
  11. package/bin/darwin/simulator-server +0 -0
  12. package/bin/linux/resources/android/LICENSE.txt +186 -0
  13. package/bin/linux/resources/android/README.md +11 -0
  14. package/bin/linux/resources/android/arm64-v8a/libscreen-sharing-agent.so +0 -0
  15. package/bin/linux/resources/android/armeabi-v7a/libscreen-sharing-agent.so +0 -0
  16. package/bin/linux/resources/android/screen-sharing-agent.jar +0 -0
  17. package/bin/linux/resources/android/x86_64/libscreen-sharing-agent.so +0 -0
  18. package/bin/linux/simulator-server +0 -0
  19. package/bin/linux-arm64/resources/android/LICENSE.txt +186 -0
  20. package/bin/linux-arm64/resources/android/README.md +11 -0
  21. package/bin/linux-arm64/resources/android/arm64-v8a/libscreen-sharing-agent.so +0 -0
  22. package/bin/linux-arm64/resources/android/armeabi-v7a/libscreen-sharing-agent.so +0 -0
  23. package/bin/linux-arm64/resources/android/screen-sharing-agent.jar +0 -0
  24. package/bin/linux-arm64/resources/android/x86_64/libscreen-sharing-agent.so +0 -0
  25. package/bin/linux-arm64/simulator-server +0 -0
  26. package/dist/cli-cmds.mjs +7345 -762
  27. package/dist/cli.js +3 -3
  28. package/dist/cli.js.map +1 -1
  29. package/dist/installer.mjs +9741 -2815
  30. package/dist/mcp-server.mjs +2925 -150
  31. package/dist/preview-ui/index.html +4500 -645
  32. package/dist/preview-ui/theme.css +231 -0
  33. package/dist/preview-window/main.cjs +182 -0
  34. package/dist/tool-server.cjs +98829 -56347
  35. package/dylibs/libArgentInjectionBootstrap.dylib +0 -0
  36. package/dylibs/libKeyboardPatch.dylib +0 -0
  37. package/dylibs/libNativeDevtoolsIos.dylib +0 -0
  38. package/package.json +14 -7
  39. package/rules/argent.md +23 -2
  40. package/scripts/postinstall.cjs +6 -2
  41. package/skills/argent-device-interact/SKILL.md +36 -28
  42. package/skills/argent-lens/SKILL.md +101 -0
  43. package/skills/argent-metro-debugger/SKILL.md +18 -16
  44. package/skills/argent-native-profiler/SKILL.md +3 -3
  45. package/skills/argent-react-native-app-workflow/SKILL.md +8 -8
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/argent",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "description": "MCP server for iOS Simulator and Android Emulator control",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -41,22 +41,29 @@
41
41
  "scripts/postinstall.cjs"
42
42
  ],
43
43
  "dependencies": {
44
- "@modelcontextprotocol/sdk": "^1.20.0"
44
+ "@modelcontextprotocol/sdk": "^1.20.0",
45
+ "tree-sitter": "^0.21.1",
46
+ "tree-sitter-typescript": "^0.23.2"
47
+ },
48
+ "optionalDependencies": {
49
+ "electron": "^42.4.1"
45
50
  },
46
51
  "devDependencies": {
47
52
  "@argent/cli": "file:../argent-cli",
48
53
  "@argent/installer": "file:../argent-installer",
49
54
  "@argent/mcp": "file:../argent-mcp",
55
+ "@argent/telemetry": "file:../telemetry",
50
56
  "@argent/tools-client": "file:../argent-tools-client",
51
- "@clack/prompts": "^1.1.0",
52
- "@types/node": "^25.9.0",
57
+ "@clack/prompts": "^1.5.1",
58
+ "@types/node": "^25.9.3",
53
59
  "@types/semver": "^7.7.1",
54
- "esbuild": "^0.28.0",
60
+ "esbuild": "^0.28.1",
55
61
  "picocolors": "^1.1.1",
56
- "semver": "^7.7.4",
62
+ "posthog-node": "5.35.0",
63
+ "semver": "^7.8.4",
57
64
  "smol-toml": "^1.6.1",
58
65
  "typescript": "^6.0.3",
59
- "vitest": "^4.1.6",
66
+ "vitest": "^4.1.9",
60
67
  "yaml": "^2.8.3"
61
68
  }
62
69
  }
package/rules/argent.md CHANGED
@@ -4,7 +4,7 @@ alwaysApply: true
4
4
  ---
5
5
 
6
6
  <description>
7
- Argent MCP tools are available in this project for iOS simulator and Android emulator control. Argent MCP tools are the preferred form of interaction with the application.
7
+ If argent is installed and configured in this environment, its MCP tools are the preferred form of interaction with the application for iOS simulator, Android emulator, and Chromium (CDP) app control; otherwise see `<availability_check>` below before attempting any argent workflow. A "Chromium (CDP) app" is any Chromium runtime exposing a Chrome DevTools Protocol endpoint — an Electron app, or any Chromium-family browser (Chrome/Brave/Edge) launched with `--remote-debugging-port`; all are driven through the same tool surface and tagged `platform: "chromium"`.
8
8
  Running MCP server and managing the Argent toolkit utilises `argent` command - if asked use `argent --help` for reference.
9
9
  To check current version of MCP server run `argent --version` command.
10
10
 
@@ -17,8 +17,24 @@ Use cases:
17
17
  - Any request to execute manual QA, UI QA, or visual behavior validation for a mobile app
18
18
  - Running, debugging, or testing a React Native app (iOS or Android)
19
19
  - Profiling performance or diagnosing re-renders in a React Native app (iOS or Android)
20
+ - Running, debugging, or testing a Chromium (CDP) app — an Electron app (boot with `boot-device` + `electronAppPath`) or a Chromium browser exposing CDP (auto-discovered on port `9222` / `ARGENT_CHROMIUM_PORTS`); on Chromium scroll with `gesture-scroll` and drag with `gesture-drag` — `gesture-swipe` is touch-only
20
21
  </description>
21
22
 
23
+ <availability_check>
24
+ <important>Run this check once per session, before the first argent tool call or `argent` command. Do not re-probe before later calls.</important>
25
+
26
+ Confirm argent is available:
27
+
28
+ 1. Are `mcp__argent__*` tools in your tool list? If none are present, argent is not available.
29
+ 2. If still unsure, run `command -v argent`. A non-zero exit means the CLI is not on PATH.
30
+
31
+ If argent IS available, ignore the rest of this block and follow this rule normally.
32
+
33
+ If argent is ABSENT, treat it as an expected state, not an error to retry. Do not call `mcp__argent__*` tools, do not run `argent` commands, and do not attempt any argent workflow. Tell the user once, and ask if you should continue without argent:
34
+
35
+ > Argent isn't installed in this environment. To enable the mobile/Chromium tooling this repo is configured for, run `npx @swmansion/argent init -y` (or `npm i -g @swmansion/argent && argent init -y`).
36
+ > </availability_check>
37
+
22
38
  <tapping_rule>
23
39
  <important>**Never** derive tap coordinates from a screenshot</important>
24
40
  Before **every** tap, you MUST call a discovery tool and extract coordinates from the result. This is not optional. Preferred tools are, in order:
@@ -44,7 +60,7 @@ Before booting, running, or interacting with any app, call `list-devices` first
44
60
  Decision order:
45
61
 
46
62
  1. **Explicit user intent** - choose the user named platform or device. Look for words "simulator" and "emulator".
47
- 2. **Prefer a running device.** iOS simulators - state `Booted` and Android devices - `state: "device"` come first in `list-devices`.
63
+ 2. **Prefer a running device.** iOS simulators - state `Booted` and Android devices - `state: "device"` come first in `list-devices`; Chromium (CDP) apps appear as `platform: "chromium"`, `state: "Running"`.
48
64
  3. **Single-platform project:** (per `argent-environment-inspector` flags `is_native_ios`/`is_native_android`, or RN with only one platform configured) → boot that platform.
49
65
  </device_selection_rule>
50
66
 
@@ -128,6 +144,11 @@ RECORDING & REPLAYING FLOWS
128
144
  Use skill: `argent-create-flow`
129
145
  When: A multi-step interaction sequence needs to be repeated — re-profiling after a fix, A/B comparisons, regression checks, user says "again" / "run that flow", or you worked through a complex path worth saving. Also use proactively: if you are about to repeat steps you already performed, record first, then replay.
130
146
  Prompt keywords: flow, repeat, test X times
147
+
148
+ PROPOSING DESIGN VARIANTS FOR HUMAN SELECTION
149
+ Use skill: `argent-lens`
150
+ When: The user asks for design alternatives / options / A-B choices for a screen or component, or you have produced more than one candidate look for an element and want a human to pick before committing. Covers the build → navigate → screenshot → propose_variant loop and the single blocking await_user_selection call. (Gated behind the `argent-lens` flag, off by default — run `argent enable argent-lens` first.)
151
+ Prompt keywords: variant, design option, alternative, A/B, "let me pick", "show me options"
131
152
  </skill_routing>
132
153
 
133
154
  <subagents>
@@ -15,10 +15,14 @@ try {
15
15
  if (state && state.pid) {
16
16
  try {
17
17
  process.kill(state.pid, "SIGTERM");
18
- } catch {}
18
+ } catch {
19
+ /* process already gone — nothing to kill */
20
+ }
19
21
  }
20
22
  fs.unlinkSync(stateFile);
21
- } catch {}
23
+ } catch {
24
+ /* no state file or unreadable — nothing to clean up */
25
+ }
22
26
 
23
27
  if (process.env.ARGENT_SKIP_POSTINSTALL === "1") {
24
28
  process.exit(0);
@@ -1,11 +1,17 @@
1
1
  ---
2
2
  name: argent-device-interact
3
- description: Interact with an iOS simulator or Android emulator using argent MCP tools. Use when tapping UI elements, performing gestures, scrolling/swiping, typing text, pressing hardware buttons, launching apps, opening URLs, taking screenshots, or checking visible app state after interactions.
3
+ description: Interact with an iOS simulator, Android emulator, or Chromium (CDP) app using argent MCP tools. Use when tapping UI elements, performing gestures, scrolling/swiping, typing text, pressing hardware buttons, launching apps, opening URLs, taking screenshots, or checking visible app state after interactions.
4
4
  ---
5
5
 
6
6
  ## Unified tool surface
7
7
 
8
- All interaction tools below accept a `udid` parameter and auto-dispatch iOS vs Android based on its shape (UUID → iOS simulator, anything else → Android adb serial). You use the same tool names on both platforms.
8
+ All interaction tools below accept a `udid` parameter and auto-dispatch iOS vs Android based on its shape (UUID → iOS simulator, `chromium-cdp-<port>` → Chromium (CDP) app, anything else → Android adb serial). You use the same tool names on every platform.
9
+
10
+ **Chromium (CDP) app** = any Chromium runtime exposing a Chrome DevTools Protocol endpoint: an Electron app (boot it with `boot-device` + `electronAppPath`), or any Chromium-family browser (Chrome/Brave/Edge) launched with `--remote-debugging-port`. The latter is auto-discovered by `list-devices` on port `9222` plus anything in `ARGENT_CHROMIUM_PORTS`. The same describe/tap/swipe/keyboard/screenshot surface drives all of them.
11
+
12
+ **Multi-tab / windows (Chromium only):** a Chromium device may have several tabs / BrowserWindows. Use `chromium-tabs` to `list` them (stable ids `t1`, `t2`, …, optional labels), open a `new` one, `select` which is active, or `close` one. Every other tool (`describe`, `gesture-tap`, `screenshot`, `debugger-evaluate`, `open-url`, …) acts on the **active** tab, so `chromium-tabs action=select` before driving a different tab. Note: a cross-process navigation (some redirects) can swap a tab's underlying CDP target — re-run `chromium-tabs action=list` to pick it up under a fresh id.
13
+
14
+ **Cookies & storage (Chromium only):** `chromium-cookies` reads/writes cookies via the Network domain (so HttpOnly cookies are visible): `action=get` (optionally scoped by `url`), `set` (`name`, `value`, + `url`/`domain`, optional `secure`/`httpOnly`/`sameSite`/`expires`), `delete` (`name`), `clear` (all). `chromium-storage` reads/writes Web Storage for the active page: `store=local|session`, `action=get` (one `key` or all entries), `set`, `remove`, `clear`. Both are per-origin / active-tab. Handy for seeding auth before a flow or asserting app state after one.
9
15
 
10
16
  For platform-specific caveats (Metro `adb reverse`, locked-screen describe errors, etc.), see § 9 Platform-specific notes at the bottom.
11
17
 
@@ -13,7 +19,7 @@ For platform-specific caveats (Metro `adb reverse`, locked-screen describe error
13
19
 
14
20
  If you delegate simulator tasks to sub-agents, make sure they have MCP permissions.
15
21
 
16
- Use `list-devices` to get a target id. Results are tagged with `platform` (`ios` or `android`); booted/ready devices come first. Pick the first entry that matches the platform you need — if none are ready, call `boot-device` with `udid` (iOS) or `avdName` (Android). See `argent-ios-simulator-setup` / `argent-android-emulator-setup` for full setup flow.
22
+ Use `list-devices` to get a target id. Results are tagged with `platform` (`ios`, `android`, or `chromium`); booted/ready devices come first. Pick the first entry that matches the platform you need — if none are ready, call `boot-device` with `udid` (iOS), `avdName` (Android), or `electronAppPath` (boots an Electron app as a `chromium` device). A Chromium browser already running with a CDP port shows up directly — no `boot-device` needed. See `argent-ios-simulator-setup` / `argent-android-emulator-setup` for full setup flow.
17
23
 
18
24
  **Load tool schemas before first use.** Gesture tools (`gesture-tap`, `gesture-swipe`, `gesture-pinch`, `gesture-rotate`, `gesture-custom`) may be deferred — their parameter schemas are not loaded until fetched. Always use ToolSearch to load the schemas of all gesture tools you plan to use **before** calling any of them. If you skip this step, parameters may be coerced to strings instead of numbers, causing validation errors.
19
25
 
@@ -21,7 +27,7 @@ Use `list-devices` to get a target id. Results are tagged with `platform` (`ios`
21
27
 
22
28
  1. **Always refer to tapping_rule** from your argent.md rule before tapping.
23
29
  2. Before performing interactions, consider whether they can be **dispatched sequentially** - more on that in `run-sequence`.
24
- 3. **Use `gesture-swipe` for lists/scrolling**, not `gesture-custom`, unless you need non-linear movement. Consider whether you need multiple swipes, if yes - use `run-sequence`.
30
+ 3. **Use `gesture-swipe` for lists/scrolling**, not `gesture-custom`, unless you need non-linear movement. On Chromium use `gesture-scroll` instead — `gesture-swipe` is touch-only. Consider whether you need multiple swipes, if yes - use `run-sequence`.
25
31
  4. **Tap a text field before typing** — on iOS try `paste` first then fall back to `keyboard`; on Android use `keyboard` directly (`paste` is iOS-only).
26
32
  5. **Coordinates are normalized** — always 0.0–1.0, not pixels.
27
33
  6. **For app navigation, prefer `describe` first.** It works on any screen without app restart. Do not navigate from screenshots on regular in-app screens unless `describe` failed to expose a reliable target. Use `native-describe-screen` only when you need app-scoped UIKit properties.
@@ -48,35 +54,37 @@ Common schemes: `messages://`, `settings://`, `maps://?q=<query>`, `tel://<numbe
48
54
 
49
55
  ## 4. Choosing the Right Tool
50
56
 
51
- | Action | Tool | Notes |
52
- | ---------------- | ---------------- | ---------------------------------------------------------------------- |
53
- | Multiple actions | `run-sequence` | Batch steps in one call (no intermediate screenshots) |
54
- | Open an app | `launch-app` | **Always — never tap home-screen icons** |
55
- | Restart an app | `restart-app` | Terminate and relaunch by bundle ID |
56
- | Open URL/scheme | `open-url` | Web pages, deep links, URL schemes |
57
- | Single tap | `gesture-tap` | Buttons, links, checkboxes |
58
- | Scroll/swipe | `gesture-swipe` | Straight-line scroll or swipe |
59
- | Long press | `gesture-custom` | Context menus, drag start |
60
- | Drag & drop | `gesture-custom` | Complex drag interactions |
61
- | Pinch/zoom | `gesture-pinch` | Two-finger pinch with auto-interpolation |
62
- | Rotation | `gesture-rotate` | Two-finger rotation with auto-interpolation |
63
- | Custom gesture | `gesture-custom` | Arbitrary touch sequences, optional interpolation |
64
- | Hardware key | `button` | Home, back, power, volume, appSwitch, actionButton |
65
- | Type text (fast) | `paste` | iOS only. Form fields — uses clipboard |
66
- | Type text | `keyboard` | iOS+Android. Fallback when paste fails; supports Enter, Escape, arrows |
67
- | Rotate device | `rotate` | Orientation changes |
57
+ | Action | Tool | Notes |
58
+ | ----------------- | ---------------- | ---------------------------------------------------------------------- |
59
+ | Multiple actions | `run-sequence` | Batch steps in one call (no intermediate screenshots) |
60
+ | Open an app | `launch-app` | **Always — never tap home-screen icons** |
61
+ | Restart an app | `restart-app` | Terminate and relaunch by bundle ID |
62
+ | Open URL/scheme | `open-url` | Web pages, deep links, URL schemes |
63
+ | Single tap | `gesture-tap` | Buttons, links, checkboxes |
64
+ | Scroll/swipe | `gesture-swipe` | Straight-line scroll or swipe |
65
+ | Scroll (Chromium) | `gesture-scroll` | Wheel-based; deltas are window fractions, positive deltaY = down |
66
+ | Drag (Chromium) | `gesture-drag` | Sliders, drag-and-drop, text selection |
67
+ | Long press | `gesture-custom` | Context menus, drag start |
68
+ | Drag & drop | `gesture-custom` | Complex drag interactions |
69
+ | Pinch/zoom | `gesture-pinch` | Two-finger pinch with auto-interpolation |
70
+ | Rotation | `gesture-rotate` | Two-finger rotation with auto-interpolation |
71
+ | Custom gesture | `gesture-custom` | Arbitrary touch sequences, optional interpolation |
72
+ | Hardware key | `button` | Home, back, power, volume, appSwitch, actionButton |
73
+ | Type text (fast) | `paste` | iOS only. Form fields — uses clipboard |
74
+ | Type text | `keyboard` | iOS+Android. Fallback when paste fails; supports Enter, Escape, arrows |
75
+ | Rotate device | `rotate` | Orientation changes |
68
76
 
69
77
  ## 5. Finding Tap Targets
70
78
 
71
79
  IMPORTANT. When moved to a different screen after an action or do not know the coordinates of component, **always** perform proper discovery first.
72
80
 
73
- | App type | Discovery tool | What it returns |
74
- | --------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
75
- | Target app discovery | `describe` | Accessibility element tree for the current device screen (iOS AX-service or Android uiautomator) with normalized frame coordinates. Works on any app, system dialogs, and Home screen — no app restart or `bundleId` required |
76
- | React Native | `debugger-component-tree` | React component tree with names, text, testID, and (tap: x,y) |
77
- | App-scoped native | `native-describe-screen` | Low-level app-scoped accessibility elements with normalized and raw coordinates; requires `bundleId` |
78
- | Permission / system modal overlay | `describe` | `describe` detects system dialogs automatically and returns dialog buttons with tap coordinates. Fall back to `screenshot` only if `describe` does not expose the controls |
79
- | Final visual fallback | `screenshot` | Use only when discovery tools cannot inspect the current UI reliably. Do not derive routine in-app navigation targets from screenshots |
81
+ | App type | Discovery tool | What it returns |
82
+ | --------------------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
83
+ | Target app discovery | `describe` | Accessibility element tree for the current device screen (iOS AX-service, Android uiautomator, or Chromium DOM walker) with normalized frame coordinates. Works on any app, system dialogs, and Home screen — no app restart or `bundleId` required |
84
+ | React Native | `debugger-component-tree` | React component tree with names, text, testID, and (tap: x,y) |
85
+ | App-scoped native | `native-describe-screen` | Low-level app-scoped accessibility elements with normalized and raw coordinates; requires `bundleId` |
86
+ | Permission / system modal overlay | `describe` | `describe` detects system dialogs automatically and returns dialog buttons with tap coordinates. Fall back to `screenshot` only if `describe` does not expose the controls |
87
+ | Final visual fallback | `screenshot` | Use only when discovery tools cannot inspect the current UI reliably. Do not derive routine in-app navigation targets from screenshots |
80
88
 
81
89
  Point follow-up native diagnostics after you already have a candidate point:
82
90
 
@@ -0,0 +1,101 @@
1
+ ---
2
+ name: argent-lens
3
+ description: Propose multiple visual design variants for on-screen elements and let the human pick in the Argent Lens window. Use when the user asks for design alternatives / options / A-B choices for a screen or component, or any time you have produced more than one candidate look for an element and want a human decision before committing.
4
+ ---
5
+
6
+ > **Prerequisite — feature flag.** This workflow is gated behind the `argent-lens` flag (off by default). Run `argent enable argent-lens` once before using it. If `propose_variant` / `await_user_selection` come back not-found, the flag is off — enable it and retry.
7
+
8
+ ## 1. Overview
9
+
10
+ You implement several candidate designs, capture each one running on the device, and stage them with `propose_variant`. Each proposed element shows up as a floating card next to the live simulator stream in the Argent Lens window (a native window that opens automatically), connected by a thin line to the real element. The human picks per element, optionally pins free-form comments to elements, and presses **Complete selection**. `await_user_selection` is the single blocking call that returns their decision.
11
+
12
+ **The golden rule: one variant = one real, _distinct_ screenshot.** A proposal is only useful if its `previewImage` shows the variant actually rendered on the device, captured AFTER that specific variant was applied. Never propose a variant you have not built and seen on screen, and never point two variants at the same file path — if two captures end up byte-identical you have not actually changed anything and the Argent Lens degenerates to identical thumbnails. Plan → build → navigate → screenshot → propose, repeated for every variant of every element, then await once.
13
+
14
+ ## 2. Tools
15
+
16
+ | Tool | Blocking? | Purpose |
17
+ | ---------------------- | --------- | ----------------------------------------------------------------------- |
18
+ | `propose_variant` | No | Stage ONE variant for ONE element. Call once per variant. Keep working. |
19
+ | `await_user_selection` | Yes | Call ONCE after every variant is staged. Parks until the human is done. |
20
+
21
+ `propose_variant` params: `element` (human name), optional `match` (`{ by: "text"|"label"|"identifier"|"role", value }`), optional `udid` (the device id you captured the variants on), and `variant` (`{ name, summary, code?, filePath?, previewImage?, frame? }`). Repeated calls with the same `element` accumulate variants on that element; different `element` values create separate cards.
22
+
23
+ **Always pass `udid`** (the same simulator/emulator id you screenshotted and described with). The preview window then streams _that_ device directly — the human never has to pick a simulator. Set it on the first `propose_variant` of a round; later calls may omit it (the last value wins).
24
+
25
+ ## 3. Workflow
26
+
27
+ Resolve a simulator/emulator first (`argent-ios-simulator-setup` / `argent-android-emulator-setup`) and, for React Native, `argent-react-native-app-workflow` to run the app and reload the bundle. Argent shows the staged variants in a native preview window that opens automatically on the user's screen; you don't open or display anything yourself. Just stage variants and call `await_user_selection`, and the window appears on its own.
28
+
29
+ ### Step 0 — Plan the variants
30
+
31
+ Decide, before touching code, exactly which elements you are redesigning and the distinct variants for each. Write them down (e.g. "Search field: Filled / Outlined / Pill" — "Primary CTA: Solid / Gradient"). Each variant must be a single, self-contained change you can apply, screenshot, and revert independently. Vague or overlapping variants produce useless proposals.
32
+
33
+ ### Step 1 — Get a precise matcher
34
+
35
+ For each element, run `describe` (or `debugger-component-tree` for RN) on the screen where it lives and read its exact `label` / `identifier` / `role`. Pass that as `match` so the floating card's connector anchors to the right element:
36
+
37
+ - Stable testID / accessibilityIdentifier → `{ by: "identifier", value: "search-input" }` (most reliable)
38
+ - Exact a11y label → `{ by: "label", value: "Search" }`
39
+ - Otherwise → `{ by: "text", value: "Search" }` (fuzzy contains; the default if `match` is omitted)
40
+
41
+ Omitting `match` defaults to `{ by: "text", value: element }`, which is fine only when the element's visible text is unique.
42
+
43
+ ### Step 2 — For each variant: build → navigate → screenshot → propose
44
+
45
+ Loop over every variant of every element:
46
+
47
+ 1. **Build the variant.** Implement that one variant in code.
48
+ 2. **Apply it on the device.** Reload the RN bundle (`debugger-reload-metro`) or rebuild as needed so the running app shows this variant.
49
+ 3. **Navigate to it.** Drive the app (`argent-device-interact`) to the screen where the element is visible — a screenshot is only meaningful if the element is actually on screen.
50
+ 4. **Screenshot.** Call `screenshot` and pass the returned file path **straight through** as `variant.previewImage`. **NEVER hand-crop, resize, re-encode, or copy the screenshot to another folder** (e.g. a `crop.py` into `/tmp/variants/`): that double-crops against the preview window's own cropping and writes the image somewhere the server won't serve it ("No preview"). Capture the whole screen — the preview window crops it for you using `variant.frame` (step 5). The path you got back must be a NEW file; if you suspect the device froze or the variant didn't apply (you see no visible change vs. the previous capture), diff with the previous path (`shasum -a 256`) before proposing — byte-identical captures mean the variant is not on screen yet. Fix that before proposing, never propose anyway.
51
+ 5. **Propose.** Call `propose_variant` with `element`, `match`, `udid` (the device you captured on), and `variant.previewImage` set to that screenshot path. The tool **auto-captures the crop frame**: it describes the device at propose time and matches the element, so each thumbnail crops to its own current layout — **as long as the variant is still on screen when you call `propose_variant`** (propose right after the screenshot, before reverting). You may pass `variant.frame` (the matched node's normalized `{x, y, width, height}` in 0..1 from a `describe` on THIS variant) to override the auto-capture — useful when the element can't stay on screen at propose time. Add `summary` (what changed and why) and `code`/`filePath` when useful.
52
+ 6. **Revert.** Roll the variant change back before building the next one — only one variant can be on screen at a time. Keep going; `propose_variant` does not block.
53
+
54
+ `previewImage` accepts a local screenshot path (served from the OS temp dir / cwd), an `http(s)` URL, or a `data:` URI. A local screenshot of the real running variant is strongly preferred.
55
+
56
+ ### Step 3 — Await the human's decision (once)
57
+
58
+ After every variant for every element is staged, call `await_user_selection` exactly once. It returns:
59
+
60
+ - `{ status: "completed", selections: [{ element, chosenVariant, comment? }], unselected, annotations: [{ target, match, comment }], globalComment }` — apply `chosenVariant` for each element; skip elements in `unselected`. Treat each `annotations` entry (inspector comments the human pinned to elements) and `globalComment` as a change request.
61
+ - `{ status: "pending", proposedElements }` — `timeoutSeconds` elapsed, not an error. Proposals are still live; call `await_user_selection` again.
62
+ - `{ status: "no_proposals" }` — you called it before any `propose_variant`. Stage variants first.
63
+
64
+ ### Step 4 — Apply the outcome
65
+
66
+ Implement the chosen variant for every selected element, address every annotation/comment, and report what you applied and what was skipped. If the human commented but skipped a variant, the comment still matters — act on it.
67
+
68
+ ## 4. Rules
69
+
70
+ - **At least two variants per element.** A choice needs alternatives — every element you propose must have ≥2 distinct variants (call `propose_variant` at least twice for it). If you only have one look for an element, either produce a real alternative or don't propose that element at all; a lone variant isn't a choice.
71
+ - **Build before you propose.** Every `previewImage` must be a screenshot of that variant actually running on the device. No mockups, no guesses, no proposing un-built ideas.
72
+ - **Distinct screenshot per variant.** Reusing a `previewImage` path across two variants — or capturing two paths whose bytes turn out identical — defeats the whole point of the Argent Lens. If you can't produce visibly different captures (e.g. the app is read-only, accessibility is broken so you can't navigate, the bundle won't hot-reload), STOP and tell the user instead of staging duplicates.
73
+ - **One blocking call.** `propose_variant` never blocks — stage freely. `await_user_selection` is the only call that waits, and you call it once, last.
74
+ - **Anchor accurately.** Pull matchers from `describe`; a wrong `match` makes the card point at the wrong element or float unanchored.
75
+ - **One variant on screen at a time.** Apply → screenshot → revert before the next variant so screenshots never bleed together.
76
+ - **`pending` is normal.** On `pending`, just await again — proposals persist across timeouts.
77
+ - **Re-proposing starts a fresh round.** Calling `propose_variant` after a round was consumed begins round N+1 and clears the previous round's elements; stage a full set each round.
78
+
79
+ ## 5. Example
80
+
81
+ ```
82
+ describe { udid } # read exact label/identifier
83
+ propose_variant { element: "Search field",
84
+ match: { by: "identifier", value: "search-input" },
85
+ variant: { name: "Outlined", summary: "1pt border, transparent fill",
86
+ previewImage: "/var/folders/.../search-outlined.png" } }
87
+ propose_variant { element: "Search field",
88
+ match: { by: "identifier", value: "search-input" },
89
+ variant: { name: "Pill", summary: "Fully rounded, filled grey",
90
+ previewImage: "/var/folders/.../search-pill.png" } }
91
+ propose_variant { element: "Primary CTA",
92
+ match: { by: "label", value: "Get started" },
93
+ variant: { name: "Gradient", summary: "Accent gradient fill",
94
+ previewImage: "/var/folders/.../cta-gradient.png" } }
95
+ await_user_selection {} # ONE blocking call → human picks
96
+ → { status: "completed",
97
+ selections: [ { element: "Search field", chosenVariant: { name: "Pill" } },
98
+ { element: "Primary CTA", chosenVariant: { name: "Gradient" } } ],
99
+ annotations: [ { target: "Tab bar", comment: "raise contrast" } ] }
100
+ # → apply Pill + Gradient, and raise tab-bar contrast.
101
+ ```
@@ -1,11 +1,13 @@
1
1
  ---
2
2
  name: argent-metro-debugger
3
- description: Debug a React Native app via Metro CDP using argent debugger tools. Use when connecting to Metro, inspecting React components, reading console logs, or evaluating JavaScript in the app runtime.
3
+ description: Debug a JS runtime via CDP using argent debugger tools. Primary path is React Native via Metro (iOS / Android); a subset of the tools (debugger-connect, debugger-status, debugger-evaluate, debugger-log-registry) also drive a Chromium (CDP) app's renderer (an Electron app, or any Chromium browser exposing CDP) through the same surface. Use when connecting to the runtime, inspecting React components, reading console logs, or evaluating JavaScript.
4
4
  ---
5
5
 
6
6
  ## 1. Prerequisites
7
7
 
8
- The debugger requires **Metro dev server running** (default `localhost:8081`) and **a React Native app connected to Metro** (at least one CDP target). Verify via `debugger-status`.
8
+ For **React Native (iOS / Android)**: requires **Metro dev server running** (default `localhost:8081`) and **a React Native app connected to Metro** (at least one CDP target). Verify via `debugger-status`.
9
+
10
+ For **Chromium (CDP)**: requires a Chromium/CDP app already available — an Electron app booted via `boot-device` with `electronAppPath`, or any Chromium browser exposing a CDP port (auto-discovered by `list-devices` on `9222` / `ARGENT_CHROMIUM_PORTS`). The debugger re-uses the page CDP session — `port` is ignored, `device_id` is the `chromium-cdp-<port>` value from `list-devices` / `boot-device`. Only `debugger-connect`, `debugger-status`, `debugger-evaluate`, `debugger-log-registry`, `view-network-logs`, and `view-network-request-details` work on Chromium (the latter two read the browser's native CDP Network recording for the active tab instead of the Metro-injected `fetch` interceptor); `debugger-component-tree`, `debugger-reload-metro`, `debugger-inspect-element`, and the `react-profiler-*` / `profiler-*` tools are RN-only and reject Chromium at the capability gate with `Tool 'X' is not supported on chromium app`.
9
11
 
10
12
  ### Android: reverse port for Metro
11
13
 
@@ -25,10 +27,10 @@ One Metro port can serve multiple connected devices (e.g. two simulators on `loc
25
27
 
26
28
  ### Connect & diagnostics
27
29
 
28
- | Tool | Purpose |
29
- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
30
- | `debugger-connect` | Connect to Metro CDP. Returns port, projectRoot, deviceName, appName, `logicalDeviceId`, isNewDebugger, connected. The returned `logicalDeviceId` is the `device_id` for every subsequent debugger/network/profiler call. |
31
- | `debugger-status` | Like connect + loadedScripts, enabledDomains, sourceMapReady. **Use to diagnose.** |
30
+ | Tool | Purpose |
31
+ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
32
+ | `debugger-connect` | Connect to the JS runtime's CDP (Metro on iOS / Android; the page CDP session on Chromium). Returns port, projectRoot (empty on Chromium), deviceName, appName, `logicalDeviceId`, isNewDebugger, connected. The returned `logicalDeviceId` is the `device_id` for every subsequent debugger call. |
33
+ | `debugger-status` | Like connect + loadedScripts, enabledDomains, sourceMapReady (no-op on Chromium). **Use to diagnose.** |
32
34
 
33
35
  ### Reload & recovery
34
36
 
@@ -115,13 +117,13 @@ When reading from the log file:
115
117
 
116
118
  ## Quick Reference
117
119
 
118
- | Action | Tool |
119
- | ----------------------------- | ------------------------------------------------------------------- |
120
- | Diagnose / check connection | `debugger-status` |
121
- | Connect to Metro CDP | `debugger-connect` |
122
- | Reload JS (already connected) | `debugger-reload-metro` |
123
- | Relaunch app on device | `restart-app` |
124
- | Inspect component at point | `debugger-inspect-element` |
125
- | Full component tree | `debugger-component-tree` |
126
- | Console log overview | `debugger-log-registry` (summary + log file path for `Grep`/`Read`) |
127
- | Evaluate JS | `debugger-evaluate` |
120
+ | Action | Tool |
121
+ | --------------------------------- | ------------------------------------------------------------------- |
122
+ | Diagnose / check connection | `debugger-status` |
123
+ | Connect to CDP (Metro / Chromium) | `debugger-connect` |
124
+ | Reload JS (already connected) | `debugger-reload-metro` |
125
+ | Relaunch app on device | `restart-app` |
126
+ | Inspect component at point | `debugger-inspect-element` |
127
+ | Full component tree | `debugger-component-tree` |
128
+ | Console log overview | `debugger-log-registry` (summary + log file path for `Grep`/`Read`) |
129
+ | Evaluate JS | `debugger-evaluate` |
@@ -86,14 +86,14 @@ To revisit a previous trace:
86
86
 
87
87
  Bottlenecks are categorized by severity:
88
88
 
89
- - **RED**: CPU functions taking >15% of total time, all UI hangs, all memory leaks. These require immediate attention.
90
- - **YELLOW**: CPU functions taking 5-15% of total time. Worth investigating but may be acceptable.
89
+ - **RED**: CPU functions taking >15% of total time, all UI hangs, and **attributed** memory leaks (those with a resolved responsible frame). These require immediate attention.
90
+ - **YELLOW**: CPU functions taking 5-15% of total time, and **unattributed** memory leaks (`<Call stack limit reached>`, no library — see the memory-leaks caveat below). Worth investigating but may be acceptable.
91
91
 
92
92
  Each bottleneck type indicates a different class of problem:
93
93
 
94
94
  - **CPU hotspots**: Native functions consuming excessive CPU time. Look for tight loops, expensive computations, or redundant work.
95
95
  - **UI hangs**: Main thread blocked long enough to cause visible jank or unresponsiveness. Often caused by synchronous I/O, heavy layout passes, or lock contention.
96
- - **Memory leaks**: Objects allocated but never freed. Common causes include retain cycles, unclosed resources, or forgotten observers.
96
+ - **Memory leaks**: Objects allocated but never freed. Common causes include retain cycles, unclosed resources, or forgotten observers. Argent records via `xctrace --attach`, which has no malloc-stack history, so on the simulator most leaks come back **unattributed** (`<Call stack limit reached>`, no library) and are dominated by benign system allocations — these are reported as a low-confidence YELLOW summary, not confirmed RED leaks. For attributed stacks, capture with malloc stack logging enabled at launch.
97
97
 
98
98
  ---
99
99
 
@@ -235,13 +235,13 @@ If the user's intent is ambiguous (run existing tests, write new tests, or find
235
235
 
236
236
  ## Related Skills
237
237
 
238
- | Skill | When to use |
239
- | ------------------------------- | ------------------------------------------------------------------------------- |
240
- | `argent-ios-simulator-setup` | Initial iOS simulator boot and connection setup |
241
- | `argent-android-emulator-setup` | Initial Android emulator boot and connection setup |
242
- | `argent-device-interact` | Tapping, swiping, typing, hardware buttons, gestures on the simulator/emulator |
243
- | `argent-metro-debugger` | Full Metro CDP debugging: component inspection, console logs, JS evaluation |
244
- | `argent-react-native-profiler` | Profiling performance, finding re-render issues, CPU hotspots |
245
- | `argent-test-ui-flow` | Interactive UI testing with automatic screenshot verification after each action |
238
+ | Skill | When to use |
239
+ | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
240
+ | `argent-ios-simulator-setup` | Initial iOS simulator boot and connection setup |
241
+ | `argent-android-emulator-setup` | Initial Android emulator boot and connection setup |
242
+ | `argent-device-interact` | Tapping, swiping, typing, hardware buttons, gestures on the simulator/emulator |
243
+ | `argent-metro-debugger` | JS-runtime CDP debugging (Metro on iOS / Android; the four ported tools also drive Chromium/CDP apps): component inspection, console logs, JS evaluation |
244
+ | `argent-react-native-profiler` | Profiling performance, finding re-render issues, CPU hotspots |
245
+ | `argent-test-ui-flow` | Interactive UI testing with automatic screenshot verification after each action |
246
246
 
247
247
  Ask the user before running tests: confirm which test suite (unit, E2E, or both), whether to use existing CI commands, and whether they want you to run existing tests, write new ones, or explore test cases yourself.