driftx 0.1.1 → 0.1.3

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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +216 -0
  3. package/dist/bin.js +834 -81
  4. package/dist/bin.js.map +1 -1
  5. package/driftx-plugin/skills/driftx/SKILL.md +281 -27
  6. package/ios-companion/DriftxCompanion/DriftxCompanionApp.swift +10 -0
  7. package/ios-companion/DriftxCompanion/Info.plist +22 -0
  8. package/ios-companion/DriftxCompanion.xcodeproj/project.pbxproj +376 -0
  9. package/ios-companion/DriftxCompanion.xcodeproj/xcshareddata/xcschemes/DriftxCompanionUITests.xcscheme +109 -0
  10. package/ios-companion/DriftxCompanionUITests/CompanionServer.swift +176 -0
  11. package/ios-companion/DriftxCompanionUITests/DriftxCompanionUITests.swift +15 -0
  12. package/ios-companion/DriftxCompanionUITests/HierarchyEndpoint.swift +140 -0
  13. package/ios-companion/DriftxCompanionUITests/Info.plist +22 -0
  14. package/ios-companion/DriftxCompanionUITests/InteractionEndpoint.swift +142 -0
  15. package/ios-companion/DriftxCompanionUITests/Router.swift +47 -0
  16. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/DriftxCompanion +0 -0
  17. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/DriftxCompanion.debug.dylib +0 -0
  18. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/Info.plist +0 -0
  19. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/PkgInfo +1 -0
  20. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanion.app/__preview.dylib +0 -0
  21. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/DriftxCompanionUITests-Runner +0 -0
  22. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/Testing.framework/Info.plist +0 -0
  23. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/Testing.framework/Testing +0 -0
  24. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/Testing.framework/_CodeSignature/CodeResources +168 -0
  25. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/Testing.framework/version.plist +18 -0
  26. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTAutomationSupport.framework/Info.plist +0 -0
  27. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTAutomationSupport.framework/XCTAutomationSupport +0 -0
  28. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTAutomationSupport.framework/_CodeSignature/CodeResources +113 -0
  29. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTAutomationSupport.framework/version.plist +18 -0
  30. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTest.framework/Info.plist +0 -0
  31. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTest.framework/XCTest +0 -0
  32. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTest.framework/_CodeSignature/CodeResources +817 -0
  33. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTest.framework/version.plist +18 -0
  34. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestCore.framework/Info.plist +0 -0
  35. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestCore.framework/XCTestCore +0 -0
  36. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestCore.framework/_CodeSignature/CodeResources +113 -0
  37. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestCore.framework/version.plist +18 -0
  38. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestSupport.framework/Info.plist +0 -0
  39. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestSupport.framework/XCTestSupport +0 -0
  40. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestSupport.framework/_CodeSignature/CodeResources +113 -0
  41. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCTestSupport.framework/version.plist +18 -0
  42. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUIAutomation.framework/Info.plist +0 -0
  43. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUIAutomation.framework/XCUIAutomation +0 -0
  44. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUIAutomation.framework/_CodeSignature/CodeResources +432 -0
  45. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUIAutomation.framework/version.plist +18 -0
  46. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUnit.framework/Info.plist +0 -0
  47. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUnit.framework/XCUnit +0 -0
  48. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUnit.framework/_CodeSignature/CodeResources +113 -0
  49. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/XCUnit.framework/version.plist +18 -0
  50. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Frameworks/libXCTestSwiftSupport.dylib +0 -0
  51. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/Info.plist +254 -0
  52. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/PkgInfo +1 -0
  53. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/PlugIns/DriftxCompanionUITests.xctest/DriftxCompanionUITests +0 -0
  54. package/ios-companion/prebuilt/Debug-iphonesimulator/DriftxCompanionUITests-Runner.app/PlugIns/DriftxCompanionUITests.xctest/Info.plist +0 -0
  55. package/ios-companion/prebuilt/DriftxCompanionUITests.xctestrun +135 -0
  56. package/ios-companion/prebuilt/build-info.json +6 -0
  57. package/package.json +14 -3
@@ -1,21 +1,54 @@
1
1
  ---
2
2
  name: driftx
3
- description: Visual comparison, accessibility audit, and layout regression for React Native and Android apps. Use when the user asks to compare their app against a design, check accessibility, detect visual regressions, inspect the component tree, or capture screenshots from a device/simulator.
3
+ description: Visual comparison, accessibility audit, layout regression, and device interaction for mobile apps (Android, iOS, React Native). Use when the user asks to compare their app against a design, check accessibility, detect visual regressions, inspect the component tree, capture screenshots, or interact with a device/simulator (tap, type, swipe, navigate).
4
4
  ---
5
5
 
6
6
  # driftx — Visual Analysis for React Native & Android
7
7
 
8
8
  Use driftx when the user wants to:
9
- - Compare their running app against a design image (Figma export, mockup, etc.)
9
+ - Compare their running app against a design image (from Figma, Google Stitch, Penpot, or any exported mockup)
10
10
  - Run an accessibility audit on the component tree
11
11
  - Detect layout regressions between builds
12
12
  - Inspect the React Native component tree on a device
13
13
  - Capture a screenshot from a running simulator/emulator
14
+ - Interact with the app — tap buttons, type text, swipe, navigate back, open deep links
15
+ - Test a user flow end-to-end (navigate, interact, then verify visually)
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install -g driftx
21
+ ```
22
+
23
+ The iOS companion ships pre-built — no Xcode build step required on install.
24
+ driftx will notify you when a newer version is available.
14
25
 
15
26
  ## Prerequisites
16
27
 
17
- driftx must be installed in the project: `npm install driftx` or available globally.
18
- Run `npx driftx doctor` to verify the environment is set up correctly.
28
+ Run `driftx doctor` to verify the environment is set up correctly.
29
+
30
+ **Requirements:**
31
+ - **Metro bundler** must be running (`npx react-native start`) for tree inspection, tap resolution, and bundle ID auto-detection
32
+ - **Android**: `adb` available, emulator booted
33
+ - **iOS**: `xcrun simctl` available, simulator booted. The XCUITest companion auto-launches when needed.
34
+
35
+ ## Platform Support
36
+
37
+ driftx currently supports **simulators and emulators only**:
38
+ - **Android**: Emulators via `adb`
39
+ - **iOS**: Simulators via `xcrun simctl` + XCUITest companion
40
+
41
+ Physical device support is not yet available (requires code signing for XCUITest companion deployment and alternative screenshot tooling).
42
+
43
+ ## Global Flags
44
+
45
+ | Flag | Description |
46
+ |------|-------------|
47
+ | `-d, --device <id>` | Device ID or name. If omitted and multiple devices are booted, driftx shows a picker. |
48
+ | `--bundle-id <id>` | iOS app bundle identifier. Optional — auto-detected from Metro CDP target when Metro is running. |
49
+ | `--verbose` | Enable debug logging. Useful for diagnosing tap resolution, companion issues, or CDP connection problems. |
50
+ | `--format <type>` | Output format: `terminal`, `markdown`, `json` (default: `terminal`). |
51
+ | `--copy` | Copy output to clipboard. |
19
52
 
20
53
  ## Commands Reference
21
54
 
@@ -48,7 +81,6 @@ npx driftx compare --baseline --format json
48
81
  |------|-------------|
49
82
  | `--design <path>` | Path to design image (PNG). Required unless `--baseline`. |
50
83
  | `--screenshot <path>` | Use existing screenshot instead of capturing from device. |
51
- | `-d, --device <id>` | Device ID or name to capture from. |
52
84
  | `--threshold <n>` | Pixel sensitivity threshold (0-1, default 0.1). |
53
85
  | `--with <analyses>` | Comma-separated analyses to run (e.g., `pixel,a11y,regression`). |
54
86
  | `--without <analyses>` | Analyses to exclude. |
@@ -68,10 +100,11 @@ npx driftx compare --baseline --format json
68
100
 
69
101
  ```bash
70
102
  npx driftx inspect --format json
103
+ npx driftx inspect --json # shorthand for --format json
71
104
  npx driftx inspect --device "Pixel 8" --format json
72
105
  ```
73
106
 
74
- Returns the React Native component tree with component names, testIDs, text content, and bounds.
107
+ Returns the React Native component tree with component names, testIDs, text content, and bounds. Use this to discover tap targets before interacting — the tree shows all visible text, testIDs, and component names that `driftx tap` can target.
75
108
 
76
109
  ### `driftx devices` — List connected devices
77
110
 
@@ -79,7 +112,7 @@ Returns the React Native component tree with component names, testIDs, text cont
79
112
  npx driftx devices --format json
80
113
  ```
81
114
 
82
- Returns available simulators/emulators and their state (booted/offline).
115
+ Returns available simulators/emulators and their state (booted/offline). When multiple devices are booted and no `-d` flag is provided, driftx shows an interactive picker.
83
116
 
84
117
  ### `driftx capture` — Capture screenshot
85
118
 
@@ -98,6 +131,14 @@ npx driftx doctor --format json
98
131
 
99
132
  Checks that adb, xcrun, Metro, etc. are available.
100
133
 
134
+ ### `driftx setup-claude` — Register as Claude Code plugin
135
+
136
+ ```bash
137
+ npx driftx setup-claude
138
+ ```
139
+
140
+ Registers driftx as a Claude Code plugin so the skill is available in all projects.
141
+
101
142
  ## Output Interpretation
102
143
 
103
144
  ### JSON format (CompareReport)
@@ -178,19 +219,97 @@ Read `report.md` for a formatted summary. Read `result.json` for structured data
178
219
  - `minor` — small issues (slightly small tap targets)
179
220
  - `info` — informational (empty text nodes)
180
221
 
222
+ ## Interpreting Visual Differences
223
+
224
+ When comparing a design against a live app, **distinguish between structural issues and dynamic data**. Not every pixel difference is a bug.
225
+
226
+ ### Dynamic data (NOT issues)
227
+
228
+ These are expected to differ between a design mockup and a live app — do NOT report them as mismatches:
229
+
230
+ - **Counts and numbers** — "12 stops" vs "243 stops", "97" vs "99+", timestamps, dates
231
+ - **User-specific text** — names, email addresses, avatars, profile data
232
+ - **API-driven content** — store names, product titles, list items, map labels, notification badges
233
+ - **Images from a server** — map tiles, avatars, product images, thumbnails
234
+
235
+ ### Structural issues (REAL issues)
236
+
237
+ These are actual design deviations that should be reported:
238
+
239
+ - **Missing or extra UI elements** — buttons, cards, banners not in the design
240
+ - **Different labels/icons** — tab bar says "Settings" but design says "Account", wrong icon
241
+ - **Layout differences** — spacing, alignment, sizing that doesn't match the design
242
+ - **Typography changes** — bold vs regular, different font size, wrong color
243
+ - **Style differences** — wrong background color, border radius, shadows
244
+
245
+ ### How to present comparison results
246
+
247
+ When showing a design-vs-app comparison table, add a **Type** column:
248
+
249
+ ```
250
+ | Area | Design | App | Type | Match? |
251
+ |------|--------|-----|------|--------|
252
+ | Stop count | "12 stops" | "243 stops" | Dynamic data | OK |
253
+ | Tab labels | "Account" | "Settings" | Structural | Mismatch |
254
+ | Alert badge | 97 | 99+ | Dynamic data | OK |
255
+ | Action buttons | None | "View stops..." | Structural | Mismatch — extra element |
256
+ ```
257
+
258
+ Mark dynamic data rows as **OK** even if the values differ. Only flag structural differences as mismatches. Summarize by counting only structural mismatches, not dynamic data differences.
259
+
181
260
  ## Workflow Patterns
182
261
 
262
+ ### Design-to-code verification (general pattern)
263
+
264
+ driftx works with any design source. **You MUST follow this pattern for every design-to-code task. Do not skip any step.**
265
+
266
+ 1. **Get the design image** from whatever tool the user is using
267
+ 2. **Save it locally** as a PNG (e.g., `/tmp/design-target.png`) to use as the driftx comparison target
268
+ 3. **Capture a "before" screenshot**: `npx driftx capture -o /tmp/before.png` -- this records the starting state before any code changes
269
+ 4. **Write or modify code** to match the design
270
+ 5. **Capture an "after" screenshot**: `npx driftx capture -o /tmp/after.png` -- this records the state after code changes
271
+ 6. **Compare against the design**: `npx driftx compare --design /tmp/design-target.png --format json`
272
+ 7. **Read the results** and classify differences as dynamic data or structural issues
273
+ 8. **Test the feature** -- use driftx to interact with the new UI (tap buttons, type into inputs, swipe, etc.) and capture screenshots to verify the interactions work correctly
274
+ 9. **Iterate** -- fix structural or interaction issues, capture a new screenshot, re-compare until it matches
275
+
276
+ **Mandatory screenshots:** You MUST capture a screenshot of the app BEFORE making changes and AFTER making changes. This is not optional. The before/after pair proves the work was done and shows what changed. After each subsequent code change, capture another screenshot and re-compare to verify the UI is converging toward the design.
277
+
278
+ **Mandatory interaction testing:** After the UI matches the design, you MUST test every interactive element using driftx (tap, type, swipe). Do not consider a feature complete until you have verified that all interactions work. Capture screenshots after each interaction to confirm the expected behavior.
279
+
280
+ ### Compare against a Google Stitch design
281
+
282
+ If the user has the Stitch MCP server connected:
283
+
284
+ 1. Use `get_screen` to retrieve the screen details (screenshot URL, HTML code)
285
+ 2. Download the screenshot using `curl -L` and save as PNG locally (e.g., `/tmp/stitch-design.png`)
286
+ 3. Optionally download the HTML code for implementation reference
287
+ 4. Run `npx driftx compare --design /tmp/stitch-design.png --format json`
288
+ 5. Read the JSON output and artifact files to understand differences
289
+ 6. Fix structural issues, re-compare until it matches
290
+
183
291
  ### Compare against a Figma design
184
292
 
185
- If the user has a Figma MCP server connected, use it to export the frame as an image first, then run driftx:
293
+ If the user has a Figma MCP server connected:
294
+
295
+ 1. Use Figma MCP to get the design frame and export as PNG
296
+ 2. Save the exported image locally (e.g., `/tmp/figma-design.png`)
297
+ 3. Run `npx driftx compare --design /tmp/figma-design.png --format json`
298
+ 4. Read the JSON output to understand differences
299
+ 5. Read artifact files (diff mask, report.md) for visual context
300
+ 6. **Classify each difference** as dynamic data or structural issue
301
+ 7. Only suggest code fixes for structural issues
302
+
303
+ ### Compare against any other design source
304
+
305
+ For other tools (Penpot, Framer, Galileo AI, or a plain image file):
186
306
 
187
- 1. Use Figma MCP to get the design frame save as PNG
188
- 2. Run `npx driftx compare --design <saved-image-path> --format json`
189
- 3. Read the JSON output to understand differences
190
- 4. Read artifact files (diff mask, report.md) for visual context
191
- 5. Suggest code fixes based on the findings
307
+ 1. Get the design image -- export from the tool, or use the path the user provides
308
+ 2. Save locally as PNG if not already on disk
309
+ 3. Run `npx driftx compare --design <path> --format json`
310
+ 4. Follow the same classify-and-fix loop
192
311
 
193
- If no Figma MCP, ask the user to provide the design image path.
312
+ If no design tool MCP is available, ask the user to provide the design image path.
194
313
 
195
314
  ### Accessibility audit
196
315
 
@@ -225,17 +344,42 @@ Runs pixel diff and accessibility audit together.
225
344
 
226
345
  driftx can interact with the running app — tap buttons, type text, swipe, navigate.
227
346
 
347
+ **Critical rule: always verify interactions visually.** Before any interaction, capture a screenshot to understand the current screen state. After any interaction, capture another screenshot to verify it worked. Never assume an interaction succeeded without visual confirmation.
348
+
349
+ ### Recommended interaction pattern
350
+
351
+ 1. `npx driftx capture -o /tmp/before.png` — see what's on screen
352
+ 2. `npx driftx inspect --json` — find tap targets (text, testIDs, component names)
353
+ 3. `npx driftx tap "Submit"` — interact
354
+ 4. `npx driftx capture -o /tmp/after.png` — verify the result
355
+
356
+ ### How tap resolution works
357
+
358
+ When you run `driftx tap "Submit"`, the tool resolves the target through multiple strategies in order:
359
+
360
+ 1. **CDP tree** (React Native) — finds components by testID, name, or text with bounds
361
+ 2. **XCUITest companion hierarchy** (iOS) — accessibility elements with real screen bounds, fuzzy text matching (e.g., "Trips" matches "Trips, tab, 2 of 6")
362
+ 3. **XCUITest element query** (iOS) — searches staticTexts, buttons, links by label
363
+ 4. **CDP fiber measurement** — finds the React fiber by text, then calls `stateNode.measureInWindow()` to get actual screen coordinates
364
+
365
+ This means `driftx tap "Submit"` works even for React Native elements that have no accessibility label — the CDP fiber measurement will find and measure it directly.
366
+
228
367
  ### `driftx tap <target>` — Tap a component
229
368
 
230
369
  ```bash
370
+ # By testID, component name, or visible text
231
371
  npx driftx tap login-btn
232
372
  npx driftx tap LoginButton
233
373
  npx driftx tap "Submit"
374
+
375
+ # By exact coordinates
234
376
  npx driftx tap 150,300 --xy
235
- npx driftx tap login-btn --device "iPhone 16 Pro"
377
+
378
+ # Target a specific device
379
+ npx driftx tap "Submit" --device "iPhone 16 Pro"
236
380
  ```
237
381
 
238
- Returns JSON with interaction result.
382
+ The `--bundle-id` flag is optional — driftx auto-detects the app's bundle ID from the Metro CDP target when Metro is running.
239
383
 
240
384
  ### `driftx type <target> <text>` — Type text into a field
241
385
 
@@ -252,8 +396,13 @@ npx driftx swipe up
252
396
  npx driftx swipe down
253
397
  npx driftx swipe left
254
398
  npx driftx swipe right
399
+
400
+ # Custom distance (default: 300pt iOS, 600pt Android)
401
+ npx driftx swipe up --distance 200
255
402
  ```
256
403
 
404
+ Default distance is 300pt on iOS and 600pt on Android. Always capture a screenshot before swiping to understand the screen layout and choose an appropriate distance, and after swiping to verify the result. If a swipe dismisses the app or triggers the home gesture, reduce the distance (e.g., `--distance 150`).
405
+
257
406
  ### `driftx go-back` — Press back button
258
407
 
259
408
  ```bash
@@ -268,17 +417,25 @@ npx driftx open-url "myapp://profile/123"
268
417
 
269
418
  ### Interaction Workflow
270
419
 
271
- 1. Write/modify code
272
- 2. Hot reload
420
+ **Simple navigation test:**
421
+ 1. `npx driftx capture -o /tmp/start.png` — capture starting state
422
+ 2. `npx driftx inspect --json` — find available tap targets
273
423
  3. `npx driftx tap "Login"` — navigate
274
- 4. `npx driftx compare --design mockup.png --format json` — verify
275
- 5. Fix issues and repeat
276
-
277
- For form testing:
278
- 1. `npx driftx type email-input "test@example.com"`
279
- 2. `npx driftx type password-input "password123"`
280
- 3. `npx driftx tap "Submit"`
281
- 4. `npx driftx compare --baseline --format json`
424
+ 4. `npx driftx capture -o /tmp/after-login.png` — verify navigation happened
425
+ 5. `npx driftx compare --design mockup.png --format json` — compare against design
426
+
427
+ **Form testing:**
428
+ 1. `npx driftx capture -o /tmp/form.png` — see the form
429
+ 2. `npx driftx type email-input "test@example.com"`
430
+ 3. `npx driftx type password-input "password123"`
431
+ 4. `npx driftx tap "Submit"`
432
+ 5. `npx driftx capture -o /tmp/after-submit.png` — verify submission result
433
+
434
+ **Scrolling to find content:**
435
+ 1. `npx driftx capture -o /tmp/before-scroll.png` — see what's visible
436
+ 2. `npx driftx swipe up` — scroll down
437
+ 3. `npx driftx capture -o /tmp/after-scroll.png` — verify new content is visible
438
+ 4. `npx driftx tap "Load More"` — tap newly visible element
282
439
 
283
440
  ## Configuration
284
441
 
@@ -291,9 +448,106 @@ driftx uses `.driftxrc.json` in the project root. Run `npx driftx init` to creat
291
448
  - `analyses.default`: Default analyses to run
292
449
  - `analyses.disabled`: Analyses to never run
293
450
 
451
+ ## Output Formatting Rules
452
+
453
+ **Always present results in a consistent, structured format.** Follow these rules strictly:
454
+
455
+ ### Results Table
456
+
457
+ Every analysis result — whether it has issues or not — must be shown in a table. Use this format for **each device**:
458
+
459
+ **When issues are found:**
460
+
461
+ ```
462
+ ### <Device Name> (<Platform>)
463
+
464
+ <N> components checked — <M> issues found.
465
+
466
+ | Severity | Issue | Component | Location |
467
+ |----------|-------|-----------|----------|
468
+ | Major | Missing accessibilityLabel | android.widget.Button | x:954 y:164 (105x105px) |
469
+ | Minor | Small tap target (36x36) | RCTText | x:10 y:200 (36x36px) |
470
+ ```
471
+
472
+ **When no issues are found:**
473
+
474
+ ```
475
+ ### <Device Name> (<Platform>)
476
+
477
+ <N> components checked — no issues found.
478
+
479
+ | Category | Count |
480
+ |----------|-------|
481
+ | Missing labels | 0 |
482
+ | Small tap targets | 0 |
483
+ | Images without alt text | 0 |
484
+ | Empty text nodes | 0 |
485
+ ```
486
+
487
+ **For pixel diff results:**
488
+
489
+ ```
490
+ ### <Device Name> (<Platform>)
491
+
492
+ | Metric | Value |
493
+ |--------|-------|
494
+ | Diff | 2.10% (5000 / 238000 pixels) |
495
+ | Regions | 3 |
496
+ | Duration | 450ms |
497
+ | Result | FAIL |
498
+
499
+ | # | Severity | Category | Component | Region |
500
+ |---|----------|----------|-----------|--------|
501
+ | 1 | Critical | spacing | LoginButton [login-btn] | (10,20) 100x50 |
502
+ ```
503
+
504
+ ### Next Actions
505
+
506
+ After presenting results, **always offer next actions using the AskUserQuestion tool with `options`**. This renders as a radio-button selection menu. Never present choices as plain numbered text.
507
+
508
+ Example — after a11y audit with issues:
509
+ ```
510
+ AskUserQuestion(
511
+ question: "What would you like to do next?",
512
+ options: [
513
+ "Capture a screenshot to visually identify the issue",
514
+ "Inspect the component tree to find the source component",
515
+ "Fix the issue (add accessibilityLabel)",
516
+ "Run the audit again after changes",
517
+ "Run on another device"
518
+ ]
519
+ )
520
+ ```
521
+
522
+ Example — after clean results (no issues):
523
+ ```
524
+ AskUserQuestion(
525
+ question: "What would you like to do next?",
526
+ options: [
527
+ "Run pixel diff against a design",
528
+ "Run regression test against previous baseline",
529
+ "Check another device",
530
+ "Inspect the component tree",
531
+ "Capture a screenshot"
532
+ ]
533
+ )
534
+ ```
535
+
536
+ Tailor the options to the context. Always use AskUserQuestion with options — never plain text lists.
537
+
538
+ ### General Rules
539
+
540
+ - **Consistent style across all devices** — if you show a table for one device, show a table for all
541
+ - **Always include the device name and platform** as a header
542
+ - **Always include component count** (from `metadata.totalChecked`)
543
+ - **Always offer next actions** as a numbered list
544
+ - **Read artifact files** (`report.md`, `result.json`) when you need more detail about findings
545
+
294
546
  ## Error Handling
295
547
 
296
548
  - If no booted device is found, suggest the user start a simulator/emulator
297
- - If Metro is not running, suggest `npx react-native start`
549
+ - If Metro is not running, suggest `npx react-native start` — Metro is required for tree inspection, tap-by-text, and bundle ID auto-detection
298
550
  - If `driftx doctor` shows missing prerequisites, show the user which tools to install
299
551
  - If compare fails with "Either --design or --baseline must be provided", one of those flags is required
552
+ - If tap returns `"Target not found"`, run `npx driftx inspect --json` to see available targets, or use `--xy` with coordinates from a screenshot
553
+ - If interactions fail with timeout, add `--verbose` to see debug logs for the companion and CDP connection
@@ -0,0 +1,10 @@
1
+ import SwiftUI
2
+
3
+ @main
4
+ struct DriftxCompanionApp: App {
5
+ var body: some Scene {
6
+ WindowGroup {
7
+ Text("DriftxCompanion")
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>en</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>$(PRODUCT_NAME)</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>APPL</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.0</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>1</string>
21
+ </dict>
22
+ </plist>