agent-device 0.13.2 → 0.14.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 (65) hide show
  1. package/README.md +68 -63
  2. package/android-snapshot-helper/README.md +75 -0
  3. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.14.0.apk +0 -0
  4. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.14.0.apk.sha256 +1 -0
  5. package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.14.0.manifest.json +17 -0
  6. package/bin/agent-device.mjs +6 -2
  7. package/dist/src/113.js +1 -1
  8. package/dist/src/1974.js +2 -2
  9. package/dist/src/221.js +4 -0
  10. package/dist/src/2301.js +1 -1
  11. package/dist/src/3918.js +29 -29
  12. package/dist/src/7847.js +1 -1
  13. package/dist/src/8161.js +3 -0
  14. package/dist/src/8656.js +1 -1
  15. package/dist/src/9152.js +1 -1
  16. package/dist/src/940.js +1 -0
  17. package/dist/src/9542.js +2 -2
  18. package/dist/src/9818.js +1 -1
  19. package/dist/src/989.js +1 -1
  20. package/dist/src/android-snapshot-helper.d.ts +181 -0
  21. package/dist/src/android-snapshot-helper.js +1 -0
  22. package/dist/src/index.d.ts +204 -1942
  23. package/dist/src/index.js +1 -1
  24. package/dist/src/internal/bin.js +440 -0
  25. package/dist/src/internal/companion-tunnel.js +1 -0
  26. package/dist/src/internal/daemon.js +45 -0
  27. package/dist/src/internal/update-check-entry.js +1 -0
  28. package/dist/src/metro.d.ts +5 -3
  29. package/dist/src/selectors.js +1 -1
  30. package/package.json +28 -24
  31. package/skills/agent-device/SKILL.md +20 -62
  32. package/skills/dogfood/SKILL.md +9 -168
  33. package/skills/react-devtools/SKILL.md +15 -31
  34. package/dist/src/4993.js +0 -1
  35. package/dist/src/5721.js +0 -1
  36. package/dist/src/7166.js +0 -1
  37. package/dist/src/8564.js +0 -3
  38. package/dist/src/9076.js +0 -1
  39. package/dist/src/backend.d.ts +0 -527
  40. package/dist/src/backend.js +0 -1
  41. package/dist/src/bin.js +0 -105
  42. package/dist/src/commands/index.d.ts +0 -1883
  43. package/dist/src/commands/index.js +0 -1
  44. package/dist/src/daemon.js +0 -43
  45. package/dist/src/metro-companion.js +0 -1
  46. package/dist/src/observability.d.ts +0 -91
  47. package/dist/src/observability.js +0 -1
  48. package/dist/src/testing/conformance.d.ts +0 -753
  49. package/dist/src/testing/conformance.js +0 -1
  50. package/dist/src/update-check-entry.js +0 -1
  51. package/skills/agent-device/references/bootstrap-install.md +0 -244
  52. package/skills/agent-device/references/coordinate-system.md +0 -28
  53. package/skills/agent-device/references/debugging.md +0 -138
  54. package/skills/agent-device/references/exploration.md +0 -362
  55. package/skills/agent-device/references/macos-desktop.md +0 -88
  56. package/skills/agent-device/references/remote-tenancy.md +0 -188
  57. package/skills/agent-device/references/verification.md +0 -134
  58. package/skills/dogfood/references/issue-taxonomy.md +0 -83
  59. package/skills/dogfood/templates/dogfood-report-template.md +0 -52
  60. package/skills/react-devtools/references/commands.md +0 -91
  61. package/skills/react-devtools/references/profiling.md +0 -74
  62. /package/dist/src/{bin.d.ts → internal/bin.d.ts} +0 -0
  63. /package/dist/src/{daemon.d.ts → internal/companion-tunnel.d.ts} +0 -0
  64. /package/dist/src/{metro-companion.d.ts → internal/daemon.d.ts} +0 -0
  65. /package/dist/src/{update-check-entry.d.ts → internal/update-check-entry.d.ts} +0 -0
@@ -1 +0,0 @@
1
- import e from"node:assert/strict";import{commands as a,selector as s}from"../9076.js";let t={session:"default",app:"com.example.app",installSourcePath:"/tmp/example.app",appEventName:"example.ready",appPushPayload:{aps:{alert:"hello"}},visibleSelector:"label=Continue",visibleText:"Continue",editableTarget:s("label=Email"),fillText:"hello@example.com",point:{x:4,y:8},swipeTo:{x:24,y:28}},n=w({name:"capture",cases:[{name:"captures screenshots through the backend primitive",command:"capture.screenshot",run:async(s,t)=>{let n=await a.capture.screenshot(s,{session:t.session});e.equal(typeof n.path,"string"),e.ok(n.path.length>0)}},{name:"captures snapshots with nodes",command:"capture.snapshot",run:async(s,t)=>{let n=await a.capture.snapshot(s,{session:t.session});e.ok(Array.isArray(n.nodes))}}]}),i=w({name:"selectors",cases:[{name:"finds visible text",command:"selectors.find",run:async(s,t)=>{let n=await a.selectors.find(s,{session:t.session,query:t.visibleText,action:"exists"});e.equal(n.kind,"found"),e.equal(n.found,!0)}},{name:"reads text from a selector",command:"selectors.getText",run:async(t,n)=>{let i=await a.selectors.getText(t,{session:n.session,target:s(n.visibleSelector)});e.equal(i.kind,"text"),e.equal(i.text,n.visibleText)}},{name:"checks selector visibility",command:"selectors.isVisible",run:async(t,n)=>{let i=await a.selectors.isVisible(t,{session:n.session,target:s(n.visibleSelector)});e.equal(i.pass,!0)}},{name:"waits for visible text",command:"selectors.waitForText",run:async(s,t)=>{let n=await a.selectors.waitForText(s,{session:t.session,text:t.visibleText,timeoutMs:1});e.equal(n.kind,"text"),e.equal(n.text,t.visibleText)}}]}),o=w({name:"interactions",cases:[{name:"clicks selector targets",command:"interactions.click",run:async(t,n)=>{let i=await a.interactions.click(t,{session:n.session,target:s(n.visibleSelector)});e.equal(i.kind,"selector")}},{name:"presses explicit points",command:"interactions.press",run:async(s,t)=>{let n=await a.interactions.press(s,{session:t.session,target:{kind:"point",...t.point}});e.deepEqual(n.point,t.point)}},{name:"fills editable targets",command:"interactions.fill",run:async(s,t)=>{let n=await a.interactions.fill(s,{session:t.session,target:t.editableTarget,text:t.fillText});e.equal(n.text,t.fillText)}},{name:"types text without a target",command:"interactions.typeText",run:async(s,t)=>{let n=await a.interactions.typeText(s,{session:t.session,text:t.fillText});e.equal(n.text,t.fillText)}},{name:"focuses selector targets",command:"interactions.focus",run:async(t,n)=>{let i=await a.interactions.focus(t,{session:n.session,target:s(n.visibleSelector)});e.equal(i.kind,"selector")}},{name:"long presses selector targets",command:"interactions.longPress",run:async(t,n)=>{let i=await a.interactions.longPress(t,{session:n.session,target:s(n.visibleSelector),durationMs:500});e.equal(i.kind,"selector")}},{name:"swipes explicit points",command:"interactions.swipe",run:async(s,t)=>{let n=await a.interactions.swipe(s,{session:t.session,from:t.point,to:t.swipeTo});e.deepEqual(n.from,t.point)}},{name:"scrolls viewport targets",command:"interactions.scroll",run:async(s,t)=>{let n=await a.interactions.scroll(s,{session:t.session,target:{kind:"viewport"},direction:"down"});e.equal(n.kind,"viewport")}},{name:"pinches through the backend primitive",command:"interactions.pinch",run:async s=>{let t=await a.interactions.pinch(s,{scale:1.1});e.equal(t.kind,"pinch")}}]}),r=w({name:"system",cases:[{name:"presses back",command:"system.back",run:async(s,t)=>{let n=await a.system.back(s,{session:t.session,mode:"in-app"});e.equal(n.kind,"systemBack")}},{name:"presses home",command:"system.home",run:async(s,t)=>{let n=await a.system.home(s,{session:t.session});e.equal(n.kind,"systemHome")}},{name:"rotates devices",command:"system.rotate",run:async(s,t)=>{let n=await a.system.rotate(s,{session:t.session,orientation:"portrait"});e.equal(n.orientation,"portrait")}},{name:"reads keyboard state",command:"system.keyboard",run:async(s,t)=>{let n=await a.system.keyboard(s,{session:t.session,action:"status"});e.equal(n.kind,"keyboardState")}},{name:"reads clipboard text",command:"system.clipboard",run:async(s,t)=>{let n=await a.system.clipboard(s,{session:t.session,action:"read"});e.equal(n.kind,"clipboardText")}},{name:"opens settings",command:"system.settings",run:async(s,t)=>{let n=await a.system.settings(s,{session:t.session});e.equal(n.kind,"settingsOpened")}},{name:"reads alert state",command:"system.alert",run:async(s,t)=>{let n=await a.system.alert(s,{session:t.session,action:"get"});e.equal(n.kind,"alertStatus")}},{name:"opens app switcher",command:"system.appSwitcher",run:async(s,t)=>{let n=await a.system.appSwitcher(s,{session:t.session});e.equal(n.kind,"appSwitcherOpened")}}]}),c=w({name:"apps",cases:[{name:"opens apps by id",command:"apps.open",run:async(s,t)=>{let n=await a.apps.open(s,{session:t.session,app:t.app});e.equal(n.kind,"appOpened"),e.equal(n.target.app,t.app)}},{name:"closes apps by id",command:"apps.close",run:async(s,t)=>{let n=await a.apps.close(s,{session:t.session,app:t.app});e.equal(n.kind,"appClosed"),e.equal(n.app,t.app)}},{name:"lists apps",command:"apps.list",run:async s=>{let t=await a.apps.list(s,{filter:"all"});e.equal(t.kind,"appsList"),e.ok(Array.isArray(t.apps))}},{name:"reads app state",command:"apps.state",run:async(s,t)=>{let n=await a.apps.state(s,{session:t.session,app:t.app});e.equal(n.kind,"appState"),e.equal(n.app,t.app)}},{name:"pushes app payloads",command:"apps.push",run:async(s,t)=>{let n=await a.apps.push(s,{session:t.session,app:t.app,input:{kind:"json",payload:t.appPushPayload}});e.equal(n.kind,"appPushed"),e.equal(n.inputKind,"json")}},{name:"triggers app events",command:"apps.triggerEvent",run:async(s,t)=>{let n=await a.apps.triggerEvent(s,{session:t.session,name:t.appEventName});e.equal(n.kind,"appEventTriggered"),e.equal(n.name,t.appEventName)}}]}),l=w({name:"admin",cases:[{name:"lists devices",command:"admin.devices",run:async s=>{let t=await a.admin.devices(s,{});e.equal(t.kind,"adminDevices"),e.ok(Array.isArray(t.devices))}},{name:"boots devices",command:"admin.boot",run:async s=>{let t=await a.admin.boot(s,{});e.equal(t.kind,"deviceBooted")}},{name:"ensures simulators",command:"admin.ensureSimulator",run:async s=>{let t=await a.admin.ensureSimulator(s,{device:"iPhone 16",runtime:"iOS 18"});e.equal(t.kind,"simulatorEnsured")}},{name:"installs apps from structured sources",command:"admin.install",run:async(s,t)=>{let n=await a.admin.install(s,{app:t.app,source:{kind:"path",path:t.installSourcePath}});e.equal(n.kind,"appInstalled")}},{name:"reinstalls apps from structured sources",command:"admin.reinstall",run:async(s,t)=>{let n=await a.admin.reinstall(s,{app:t.app,source:{kind:"path",path:t.installSourcePath}});e.equal(n.kind,"appReinstalled")}},{name:"installs apps from source resolver",command:"admin.installFromSource",run:async(s,t)=>{let n=await a.admin.installFromSource(s,{source:{kind:"path",path:t.installSourcePath}});e.equal(n.kind,"appInstalledFromSource")}}]}),m=w({name:"recording",cases:[{name:"starts recording",command:"record",run:async s=>{let t=await a.recording.record(s,{action:"start"});e.equal(t.kind,"recordingStarted")}},{name:"stops traces",command:"trace",run:async s=>{let t=await a.recording.trace(s,{action:"stop"});e.equal(t.kind,"traceStopped")}}]}),p=w({name:"diagnostics",cases:[{name:"reads paginated logs",command:"diagnostics.logs",run:async s=>{let t=await a.diagnostics.logs(s,{limit:10});e.equal(t.kind,"diagnosticsLogs"),e.ok(Array.isArray(t.entries))}},{name:"dumps structured network entries",command:"diagnostics.network",run:async s=>{let t=await a.diagnostics.network(s,{limit:10,include:"summary"});e.equal(t.kind,"diagnosticsNetwork"),e.ok(Array.isArray(t.entries))}},{name:"measures perf metrics",command:"diagnostics.perf",run:async s=>{let t=await a.diagnostics.perf(s,{sampleMs:100});e.equal(t.kind,"diagnosticsPerf"),e.ok(Array.isArray(t.metrics))}}]}),d=[n,i,o,r,c,l,m,p];async function u(e,a={}){let s=a.suites??d,t=[];for(let a of s)t.push(await a.run(e));let n=t.flatMap(e=>e.failures);return{target:e.name,passed:t.reduce((e,a)=>e+a.passed,0),failed:t.reduce((e,a)=>e+a.failed,0),failures:n,suites:t}}async function y(e,a={}){let s=await u(e,a);if(s.failed>0)throw AggregateError(s.failures.map(e=>e.error),`${e.name} failed ${s.failed} agent-device conformance case${1===s.failed?"":"s"}`);return s}function w(e){return{name:e.name,cases:e.cases,run:async a=>{let s={...t,...a.fixtures},n=[],i=0;for(let t of e.cases){let o={suite:e.name,caseName:t.name,fixtures:s};try{await a.beforeEach?.(o);let e=await a.createRuntime();await t.run(e,s),i+=1}catch(a){n.push({suite:e.name,caseName:t.name,command:t.command,error:a})}finally{await a.afterEach?.(o)}}return{suite:e.name,passed:i,failed:n.length,failures:n}}}}export{l as adminConformanceSuite,c as appsConformanceSuite,y as assertCommandConformance,n as captureConformanceSuite,d as commandConformanceSuites,t as defaultCommandConformanceFixtures,p as diagnosticsConformanceSuite,o as interactionConformanceSuite,m as recordingConformanceSuite,u as runCommandConformance,i as selectorConformanceSuite,r as systemConformanceSuite};
@@ -1 +0,0 @@
1
- import{readUpdateCheckWorkerArgs as e,runUpdateCheckWorker as c}from"./113.js";let o=e(process.argv.slice(2));o&&c(o).catch(()=>{process.exitCode=0});
@@ -1,244 +0,0 @@
1
- # Bootstrap and Install
2
-
3
- ## When to open this file
4
-
5
- Open this file when you still need to choose the right target, start the right session, install or relaunch the app, or pin automation to one device before interacting. This is the deterministic setup layer for sandbox, cloud, or other environments where install paths, device state, or app readiness may be uncertain.
6
-
7
- ## Open-first path
8
-
9
- - `devices`
10
- - `apps`
11
- - `ensure-simulator`
12
- - `open`
13
- - `session list`
14
-
15
- Use this exact order when you are not sure about the installed app identifier. On Android dev builds in particular, `apps` is cheaper than guessing package suffixes and retrying failed `open` calls.
16
-
17
- ## Install path
18
-
19
- - `install` or `reinstall`
20
- - `install-from-source` when the artifact already exists at a URL the daemon can reach
21
- - `install-from-source --github-actions-artifact` when a compatible remote daemon should resolve a GitHub Actions artifact
22
-
23
- ## Most common mistake to avoid
24
-
25
- Do not start acting before you have pinned the correct target and opened an `app` session. In mixed-device environments, always pass `--device`, `--udid`, or `--serial`.
26
-
27
- ## Deterministic setup rule
28
-
29
- If there is no simulator, no app install, no open app session, or any uncertainty about where the app should come from, stay in this file and use deterministic setup commands or bootstrap scripts first. Do not improvise install paths or app-launch flows while exploring.
30
-
31
- After setup is confirmed or completed, move to `exploration.md` before doing UI inspection or interaction.
32
-
33
- ## Open-first rule
34
-
35
- - If the user asks to test an app and does not provide an install artifact or explicit install instruction, try `open <app>` first.
36
- - If `open <app>` fails, run `agent-device apps` and retry with a discovered app name before considering install steps.
37
- - Do not install or reinstall on the first attempt unless the user explicitly asks for installation or provides a concrete artifact path or URL.
38
- - When installation is required from a known location, prefer a checked-in shell script or other deterministic bootstrap command over ad hoc path guessing.
39
- - Use `apps --platform <platform>` together with `--device`, `--udid`, or `--serial` when target selection matters.
40
- - Once you have the correct app name, retry `open` with that exact discovered value.
41
-
42
- ## Common starting points
43
-
44
- These are examples, not required exact sequences. Use the smallest setup flow that matches the task.
45
-
46
- ### Boot a simulator and open an app
47
-
48
- ```bash
49
- agent-device ensure-simulator --platform ios --device "iPhone 17 Pro" --boot
50
- agent-device open MyApp --platform ios --device "iPhone 17 Pro" --relaunch
51
- ```
52
-
53
- ### Install an app artifact
54
-
55
- ```bash
56
- agent-device install com.example.app ./build/app.apk --platform android --serial emulator-5554
57
- ```
58
-
59
- ```bash
60
- agent-device install com.example.app ./build/MyApp.app --platform ios --device "iPhone 17 Pro"
61
- ```
62
-
63
- ```bash
64
- ARTIFACT_URL="<trusted-artifact-url>"
65
- agent-device install-from-source "$ARTIFACT_URL" --platform android
66
- ```
67
-
68
- Daemon-resolved GitHub Actions artifacts:
69
-
70
- ```bash
71
- agent-device install-from-source \
72
- --github-actions-artifact ORG/REPO:1234567890 \
73
- --platform android
74
- ```
75
-
76
- Project config can provide an artifact name instead:
77
-
78
- ```json
79
- {
80
- "platform": "android",
81
- "installSource": {
82
- "type": "github-actions-artifact",
83
- "repo": "ORG/REPO",
84
- "artifact": "app-debug"
85
- }
86
- }
87
- ```
88
-
89
- ## Install guidance
90
-
91
- - Use `install <app> <path>` when the app may already be installed and you do not need a fresh-state reset.
92
- - Use `reinstall <app> <path>` when you explicitly need uninstall plus install as one deterministic step.
93
- - Use `install-from-source <url>` only when an existing artifact URL is trusted, operator-approved, and reachable by the daemon.
94
- - Use `--github-actions-artifact <org>/<repo>:<artifact>` when a compatible remote daemon should resolve a GitHub Actions artifact. Numeric artifacts are IDs; non-numeric artifacts are names.
95
- - Local `.apk`, `.aab`, `.app`, and `.ipa` paths go through `install` or `reinstall`; existing reachable URLs go through `install-from-source`.
96
- - Do not download, re-zip, publish temporary GitHub releases, or move CI artifacts elsewhere just to make an install command work.
97
- - Keep install and open as separate phases. Do not turn them into one default command flow.
98
- - Supported binary formats:
99
- - Android: `.apk` and `.aab`
100
- - iOS: `.app` and `.ipa`
101
- - Android URL sources can be direct `.apk` or `.aab` files.
102
- - Trusted artifact service URLs may point at archive-backed downloads that contain one installable artifact. Prefer `--github-actions-artifact` for GitHub Actions artifacts that a compatible remote daemon can resolve with its own credentials.
103
- - If a trusted artifact archive contains multiple installables, stop and ask for the intended artifact instead of guessing.
104
- - `.aab` still requires `bundletool` in `PATH`, or `AGENT_DEVICE_BUNDLETOOL_JAR=<absolute-path-to-bundletool-all.jar>` with `java` in `PATH`, when the daemon installs the materialized artifact.
105
- - For `.ipa` archives with multiple app bundles, `<app>` is the bundle id or bundle name selection hint.
106
- - After install or reinstall, later use `open <app>` with the exact discovered or known package/bundle identifier, not the artifact path.
107
-
108
- ## Choose the right starting point
109
-
110
- - iOS local QA: prefer simulators unless the task explicitly requires physical hardware.
111
- - iOS in mixed simulator and device environments: run `ensure-simulator` first, then keep using `--device` or `--udid`.
112
- - TV targets: use `--target tv` together with `--platform` when the task is for tvOS or Android TV rather than phone or tablet surfaces.
113
- - Android binary flow: use `install` or `reinstall` for `.apk` or `.aab`, then open by installed package name.
114
- - macOS desktop app flow: use `open <app> --platform macos`. Only load [macos-desktop.md](macos-desktop.md) if a desktop surface or macOS-specific behavior matters.
115
-
116
- TV example:
117
-
118
- ```bash
119
- agent-device open MyTvApp --platform ios --target tv
120
- agent-device open com.example.androidtv --platform android --target tv
121
- ```
122
-
123
- ## Session rules
124
-
125
- - Use `--session <name>` when you need a named session:
126
-
127
- ```bash
128
- agent-device --session auth open Settings --platform ios
129
- agent-device --session auth snapshot -i
130
- ```
131
-
132
- - Use `open <app>` before interactions.
133
- - Use `close` when done. Add `--shutdown` when you want simulators or emulators torn down with the session.
134
- - Use semantic session names when you need multiple concurrent runs.
135
- - Use `--save-script=<path>` on `close` when you want to keep a replay script.
136
- - For dev loops where state can linger, prefer `open <app> --relaunch`.
137
- - For Metro-backed React Native JS changes with the app already running, prefer `metro reload` instead of `open <app> --relaunch`; it asks Metro to reload connected apps without restarting the native process.
138
- - In iOS sessions, use `open <app>` for the app itself. Use `open <url>` for deep links, and `open <app> <url>` when you need to launch the app and deep link in one step.
139
- - On iOS, `appstate` is session-scoped and requires the matching active session on the target device.
140
-
141
- ## After a session is established
142
-
143
- Once you have opened the correct session on the correct target, default to the conservative rule: keep the session binding on follow-up commands, and stop repeating device-routing flags unless you are intentionally retargeting.
144
-
145
- - Prefer `--session <name>` on follow-up commands, or use sandboxed `AGENT_DEVICE_SESSION`.
146
- - Do not keep repeating `--platform`, `--target`, `--device`, `--udid`, `--serial`, or similar target-selection flags on normal follow-up commands.
147
- - Only omit follow-up session flags when the environment explicitly guarantees isolation.
148
-
149
- Good shared-host pattern:
150
-
151
- ```bash
152
- agent-device --session auth open Settings --platform ios --device "iPhone 17 Pro"
153
- agent-device --session auth snapshot -i
154
- agent-device --session auth press @e3
155
- agent-device --session auth close
156
- ```
157
-
158
- Bad shared-host pattern:
159
-
160
- ```bash
161
- agent-device --session auth open Settings --platform ios --device "iPhone 17 Pro"
162
- agent-device --session auth snapshot -i --platform ios --device "iPhone 17 Pro"
163
- ```
164
-
165
- Use target-selection flags again only when you are choosing the target before opening a session, or when you explicitly mean to retarget.
166
-
167
- ## Session-bound automation
168
-
169
- Use this when an orchestrator must keep plain CLI calls on one session and device.
170
-
171
- ```bash
172
- export AGENT_DEVICE_SESSION=qa-ios
173
- export AGENT_DEVICE_PLATFORM=ios
174
- export AGENT_DEVICE_SESSION_LOCK=strip
175
-
176
- agent-device open MyApp --relaunch
177
- ```
178
-
179
- - `AGENT_DEVICE_SESSION` plus `AGENT_DEVICE_PLATFORM` provides the default binding.
180
- - `--session-lock reject|strip` controls whether conflicting per-call routing flags fail or are ignored.
181
- - Conflicts include explicit retargeting flags such as `--platform`, `--target`, `--device`, `--udid`, `--serial`, `--ios-simulator-device-set`, and `--android-device-allowlist`.
182
- - Lock policy applies to nested `batch` steps too.
183
- - Compatibility aliases remain supported: `--session-locked`, `--session-lock-conflicts`, `AGENT_DEVICE_SESSION_LOCKED`, and `AGENT_DEVICE_SESSION_LOCK_CONFLICTS`.
184
-
185
- Android emulator variant:
186
-
187
- ```bash
188
- export AGENT_DEVICE_SESSION=qa-android
189
- export AGENT_DEVICE_PLATFORM=android
190
-
191
- agent-device --session-lock reject open com.example.myapp --relaunch
192
- ```
193
-
194
- ## Scoped discovery
195
-
196
- Use scoped discovery when one run must not see host-global device lists.
197
-
198
- ```bash
199
- agent-device devices --platform ios --ios-simulator-device-set /tmp/tenant-a/simulators
200
- agent-device devices --platform android --android-device-allowlist emulator-5554,device-1234
201
- ```
202
-
203
- - Scope is applied before `--device`, `--udid`, and `--serial`.
204
- - Out-of-scope selectors fail with `DEVICE_NOT_FOUND`.
205
- - With iOS simulator-set scope enabled, iOS physical devices are not enumerated.
206
- - If the scoped iOS simulator set is empty, the error should point at the set path and suggest creating a simulator in that set.
207
- - Environment equivalents:
208
- - `AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET`
209
- - `AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST`
210
-
211
- ## Session inspection and replay
212
-
213
- ```bash
214
- agent-device session list
215
- agent-device replay ./session.ad --session auth
216
- agent-device replay -u ./session.ad --session auth
217
- ```
218
-
219
- - iOS session entries include `device_udid` and `ios_simulator_device_set`. Use them to confirm routing in concurrent runs.
220
- - Prefer selector-based actions and assertions in saved replay scripts.
221
- - Tenant isolation namespaces sessions as `<tenant>:<session>` during tenant-scoped runs.
222
-
223
- ## When to leave this file
224
-
225
- - Once the correct target and session are pinned, move to [exploration.md](exploration.md).
226
- - If opening, startup, permissions, or logs become the blocker, switch to [debugging.md](debugging.md).
227
-
228
- ## Install examples
229
-
230
- ```bash
231
- agent-device reinstall MyApp /path/to/app-debug.apk --platform android --serial emulator-5554
232
- ```
233
-
234
- ```bash
235
- agent-device install com.example.app ./build/MyApp.ipa --platform ios --device "iPhone 17 Pro"
236
- ```
237
-
238
- Do not use `open <apk|aab> --relaunch` on Android.
239
-
240
- ## Security and trust notes
241
-
242
- - Treat signing, provisioning, and daemon auth values as host secrets. Do not paste them into shared logs or commit them to source control.
243
- - Prefer Xcode Automatic Signing over manual overrides when a physical iOS device is involved.
244
- - Keep persistent host-specific defaults in environment variables rather than checked-in project config.
@@ -1,28 +0,0 @@
1
- # Coordinate System
2
-
3
- ## When to open this file
4
-
5
- Open this file only when you must use raw coordinates instead of selectors or `@ref` targeting.
6
-
7
- ## Main commands to reach for first
8
-
9
- - `screenshot`
10
- - coordinate-based `click` or `swipe`
11
-
12
- ## Most common mistake to avoid
13
-
14
- Do not assume coordinates mean the same thing across platforms or runs. Prefer selectors and refs first.
15
-
16
- ## Canonical loop
17
-
18
- ```bash
19
- agent-device screenshot /tmp/current-screen.png
20
- agent-device click 120 240
21
- ```
22
-
23
- ## Rules
24
-
25
- - Origin is the top-left of the device screen.
26
- - iOS uses device points.
27
- - Android uses pixels.
28
- - Use screenshots to reason about coordinates before acting.
@@ -1,138 +0,0 @@
1
- # Debugging
2
-
3
- ## When to open this file
4
-
5
- Open this file when the task turns into failure triage, logs, network inspection, permission prompts, setup trouble, or unstable session behavior.
6
-
7
- If the debugging task needs the React Native component tree, props, state, hooks, or render profiling, use `agent-device react-devtools ...` and the `skills/react-devtools` workflow instead of trying to infer those internals from the accessibility tree or app logs alone.
8
-
9
- ## Main commands to reach for first
10
-
11
- - `logs clear --restart`
12
- - `network dump`
13
- - `logs path`
14
- - `logs doctor`
15
- - `alert wait`
16
- - `alert accept` or `alert dismiss`
17
-
18
- ## Most common mistake to avoid
19
-
20
- Do not leave logging on for normal flows or dump full log files into context. Keep debug windows short and inspect logs with `grep` or `tail`.
21
-
22
- In React Native dev or debug builds, do not dismiss visible warning or error overlays without remembering to report them later. If you close one to keep the flow moving, keep at least a screenshot or a short marked log window so the summary can name it.
23
-
24
- ## Canonical loop
25
-
26
- ```bash
27
- agent-device open MyApp --platform ios
28
- agent-device logs clear --restart
29
- agent-device network dump 25
30
- agent-device logs path
31
- agent-device close
32
- ```
33
-
34
- ## Log and network flow
35
-
36
- Logging is off by default. Enable it only when you need a debugging window.
37
-
38
- - Default app logs live under `~/.agent-device/sessions/<session>/app.log`.
39
- - `logs clear --restart` is the fastest clean repro loop.
40
- - `network dump [limit] [summary|headers|body|all]` parses recent HTTP(s) entries from the same session app log.
41
- - On macOS, `network dump` is app-scoped and only sees Unified Logging associated with the active session app.
42
- - On iOS simulators, `network dump` can recover recent app log history with `simctl log show` when the live session stream is sparse, so check the returned notes before assuming the repro window was empty.
43
- - On iOS, `network dump` is still limited to what Unified Logging exposes for the app process. If the app does not emit request metadata there, `network dump` can legitimately return no HTTP entries even during a real repro.
44
- - Summary output already shows timestamp, status, and duration when the log backend exposes them.
45
- - Prefer the explicit flag form `network dump 25 --include headers|body|all` when you need more than the default summary view.
46
- - If iOS simulator notes say app logs were recovered but none looked like HTTP traffic, treat that as an app instrumentation gap rather than a missing repro and inspect `logs path` for the non-network diagnostics that were captured.
47
- - `logs doctor` checks backend and runtime readiness for the current session and device.
48
- - `logs mark "before tap"` inserts a timestamped marker into the app log.
49
- - Android `network dump` surfaces timestamps from logcat-style prefixes and can backfill status and request/response duration from adjacent GIBSDK packet lines, so check it before dumping raw log windows.
50
- - Android app-log streaming rebinds to the current app PID after relaunches, so rerun the repro window before assuming the last log slice is stale.
51
- - Marker lines are emitted with the `[agent-device][mark][...]` prefix. When you grep later, prefer a narrow pattern such as `grep -n -E "agent-device.*mark|before tap" <path>`.
52
- - Session app logs can contain runtime data, headers, or payload fragments. Review them before sharing.
53
- - `logs start` requires an active app session and appends to `app.log`.
54
- - `logs stop` stops streaming. `close` also stops logging.
55
- - `logs clear` truncates `app.log` and removes rotated `app.log.N` files, and requires logging to be stopped first.
56
- - `logs path` returns the log path plus metadata about the active backend and file state.
57
- - `network log` is an alias for `network dump`.
58
-
59
- Operational limits:
60
-
61
- - `app.log` rotates to `app.log.1` after 5 MB by default.
62
- - `network dump` scans the last 4000 app-log lines, returns up to 200 entries, and truncates header or payload fields at 2048 characters.
63
- - Retention knobs:
64
- - `AGENT_DEVICE_APP_LOG_MAX_BYTES`
65
- - `AGENT_DEVICE_APP_LOG_MAX_FILES`
66
- - Redaction hook:
67
- - `AGENT_DEVICE_APP_LOG_REDACT_PATTERNS`
68
-
69
- Useful shell follow-up after `logs path`:
70
-
71
- ```bash
72
- grep -n -E "Error|Exception|Fatal|crash" <path>
73
- grep -n -E "agent-device.*mark|before tap" <path>
74
- tail -50 <path>
75
- ```
76
-
77
- If the app showed a visible warning or error overlay during the flow:
78
-
79
- - Prefer a narrow grep window around your `logs mark` lines instead of loading the whole file.
80
- - Mention the surfaced warning or error in the final summary even if it did not block completion.
81
- - If the overlay kept returning, call that out as a stability issue instead of treating it as operator noise.
82
-
83
- ## Alerts and permissions
84
-
85
- Use `alert` for iOS simulator permission dialogs and macOS desktop alerts instead of tapping coordinates.
86
-
87
- ```bash
88
- agent-device alert wait 5000
89
- agent-device alert accept
90
- ```
91
-
92
- - `alert` is supported on iOS simulators and macOS desktop targets.
93
- - `alert accept` and `alert dismiss` retry internally for a short window, so you usually do not need manual sleeps.
94
- - If a permission sheet or modal is visible in `snapshot` or `screenshot` but `alert accept` says no alert was found, treat it as normal tappable UI for that run: take a scoped `snapshot -i -s "<visible label>"` and `press @ref` instead of looping on `alert`.
95
- - iOS 16+ "Allow Paste" prompts are suppressed under XCUITest. Use `xcrun simctl pbcopy booted` when you need to seed simulator clipboard content directly.
96
-
97
- ## Setup problems worth recognizing early
98
-
99
- - iOS snapshots do not require macOS Accessibility permissions.
100
- - iOS physical-device XCTest setup does require valid signing and provisioning.
101
- - If physical-device runner setup fails, prefer Xcode Automatic Signing first.
102
- - Optional overrides are:
103
- - `AGENT_DEVICE_IOS_TEAM_ID`
104
- - `AGENT_DEVICE_IOS_SIGNING_IDENTITY`
105
- - `AGENT_DEVICE_IOS_PROVISIONING_PROFILE`
106
- - `AGENT_DEVICE_IOS_BUNDLE_ID`
107
- - If daemon startup is timing out during setup, increase `AGENT_DEVICE_DAEMON_TIMEOUT_MS`.
108
- - If daemon startup fails with stale metadata hints, clean `~/.agent-device/daemon.json` and `~/.agent-device/daemon.lock`, then retry.
109
- - Free Apple Developer personal-team accounts may reject generic bundle IDs. Use a unique reverse-DNS value for `AGENT_DEVICE_IOS_BUNDLE_ID` when that happens.
110
-
111
- ## Common failure patterns
112
-
113
- - `snapshot` returns 0 nodes: the app may no longer be foregrounded or the UI is not stable yet. Re-open the app or retry when state settles.
114
- - Logs are empty: confirm you opened an app session before `logs clear --restart`.
115
- - Android logs look stale after relaunch: retry the repro window after the process rebinds.
116
- - Android accessibility snapshots can lag behind visible screen transitions. The next snapshot retries suspicious trees for a short post-action deadline after navigation-sensitive actions, and `@ref` actions refresh while that window is active. If the tree still looks stale, use `screenshot` as visual truth, wait briefly, then re-run `snapshot -i`. For animation-heavy runs, try `settings animations off` and restore with `settings animations on`.
117
- - React Native dev warnings or errors keep reappearing: treat them as part of the app state, not as disposable chrome. Capture one clean repro and include them in the summary.
118
- - Permission prompts block the flow: wait for the alert and handle it explicitly.
119
- - If snapshots keep returning 0 nodes on an iOS simulator, restart Simulator and re-open the app.
120
- - If a macOS snapshot looks incomplete, compare with `snapshot --raw --platform macos` to separate collector filtering from missing AX content.
121
-
122
- ## Crash triage fast path
123
-
124
- Always start from the session app log, then branch by platform.
125
-
126
- ```bash
127
- agent-device logs path
128
- grep -n -E "SIGABRT|SIGSEGV|EXC_|fatal|exception|terminated|killed|jetsam|memorystatus|FATAL EXCEPTION|Abort message" <path>
129
- ```
130
-
131
- - iOS: if the log suggests `ReportCrash`, `SIGABRT`, or `EXC_*`, inspect `~/Library/Logs/DiagnosticReports`.
132
- - Android: if the app log is not enough, use `adb logcat` for `FATAL EXCEPTION`, `Abort message`, or `signal` lines around process death.
133
- - If no crash signature appears in app logs, stop collecting broad logs and switch to the platform-native crash source.
134
-
135
- ## When to leave this file
136
-
137
- - Return to [exploration.md](exploration.md) once the app is stable again.
138
- - Load [verification.md](verification.md) if you need evidence artifacts after reproducing the issue.