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.
- package/README.md +68 -63
- package/android-snapshot-helper/README.md +75 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.14.0.apk +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.14.0.apk.sha256 +1 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.14.0.manifest.json +17 -0
- package/bin/agent-device.mjs +6 -2
- package/dist/src/113.js +1 -1
- package/dist/src/1974.js +2 -2
- package/dist/src/221.js +4 -0
- package/dist/src/2301.js +1 -1
- package/dist/src/3918.js +29 -29
- package/dist/src/7847.js +1 -1
- package/dist/src/8161.js +3 -0
- package/dist/src/8656.js +1 -1
- package/dist/src/9152.js +1 -1
- package/dist/src/940.js +1 -0
- package/dist/src/9542.js +2 -2
- package/dist/src/9818.js +1 -1
- package/dist/src/989.js +1 -1
- package/dist/src/android-snapshot-helper.d.ts +181 -0
- package/dist/src/android-snapshot-helper.js +1 -0
- package/dist/src/index.d.ts +204 -1942
- package/dist/src/index.js +1 -1
- package/dist/src/internal/bin.js +440 -0
- package/dist/src/internal/companion-tunnel.js +1 -0
- package/dist/src/internal/daemon.js +45 -0
- package/dist/src/internal/update-check-entry.js +1 -0
- package/dist/src/metro.d.ts +5 -3
- package/dist/src/selectors.js +1 -1
- package/package.json +28 -24
- package/skills/agent-device/SKILL.md +20 -62
- package/skills/dogfood/SKILL.md +9 -168
- package/skills/react-devtools/SKILL.md +15 -31
- package/dist/src/4993.js +0 -1
- package/dist/src/5721.js +0 -1
- package/dist/src/7166.js +0 -1
- package/dist/src/8564.js +0 -3
- package/dist/src/9076.js +0 -1
- package/dist/src/backend.d.ts +0 -527
- package/dist/src/backend.js +0 -1
- package/dist/src/bin.js +0 -105
- package/dist/src/commands/index.d.ts +0 -1883
- package/dist/src/commands/index.js +0 -1
- package/dist/src/daemon.js +0 -43
- package/dist/src/metro-companion.js +0 -1
- package/dist/src/observability.d.ts +0 -91
- package/dist/src/observability.js +0 -1
- package/dist/src/testing/conformance.d.ts +0 -753
- package/dist/src/testing/conformance.js +0 -1
- package/dist/src/update-check-entry.js +0 -1
- package/skills/agent-device/references/bootstrap-install.md +0 -244
- package/skills/agent-device/references/coordinate-system.md +0 -28
- package/skills/agent-device/references/debugging.md +0 -138
- package/skills/agent-device/references/exploration.md +0 -362
- package/skills/agent-device/references/macos-desktop.md +0 -88
- package/skills/agent-device/references/remote-tenancy.md +0 -188
- package/skills/agent-device/references/verification.md +0 -134
- package/skills/dogfood/references/issue-taxonomy.md +0 -83
- package/skills/dogfood/templates/dogfood-report-template.md +0 -52
- package/skills/react-devtools/references/commands.md +0 -91
- package/skills/react-devtools/references/profiling.md +0 -74
- /package/dist/src/{bin.d.ts → internal/bin.d.ts} +0 -0
- /package/dist/src/{daemon.d.ts → internal/companion-tunnel.d.ts} +0 -0
- /package/dist/src/{metro-companion.d.ts → internal/daemon.d.ts} +0 -0
- /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.
|