@appetize/cli 0.19.0 → 0.21.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.
@@ -1,396 +1,105 @@
1
1
  # Command reference
2
2
 
3
- Every command, flag and output shape. `appetize <command> --help` prints the
4
- same flags at the terminal.
5
-
6
- - [Global](#global)
7
- - [session start](#session-start)
8
- - [session stop](#session-stop)
9
- - [build list](#build-list)
10
- - [build upload](#build-upload)
11
- - [device list](#device-list)
12
- - [inspect](#inspect)
13
- - [tap](#tap)
14
- - [swipe](#swipe)
15
- - [type](#type)
16
- - [press](#press)
17
- - [rotate](#rotate)
18
- - [open](#open)
19
- - [keychain clear](#keychain-clear)
20
- - [screenshot](#screenshot)
21
- - [recording start](#recording-start)
22
- - [recording stop](#recording-stop)
23
- - [skill install](#skill-install)
24
- - [Selectors](#selectors)
25
- - [Environment](#environment)
26
- - [Exit codes and output streams](#exit-codes-and-output-streams)
27
-
28
- ## Global
29
-
30
- `--json` prints the result as JSON. End every command with it. `--no-json`
31
- prints text.
32
-
33
- `--quiet` hides the progress spinner shown on an interactive terminal.
34
-
35
- `--session-id <id>` is accepted by every command except those marked "Takes
36
- no session". On
37
- `session start` it names the session being created; everywhere else it picks
38
- which existing session to act on, defaulting to the sole active one, so pass it
39
- only when several are running.
3
+ Behaviour that `appetize <command> --help` does not show. Run that for flags.
40
4
 
41
- ## session start
42
-
43
- ```
44
- appetize session start <device-id> <target> [options]
45
- ```
46
-
47
- | Flag | Meaning |
48
- | --------------------- | ------------------------------------------------------ |
49
- | `--device-os-version` | Device OS version, e.g. `17` for iOS, `14` for Android |
50
- | `--endpoint` | Appetize URL; overrides `APPETIZE_ENDPOINT` |
51
- | `--no-wait` | Return without waiting for the device to be ready |
52
- | `--open` | URL opened once the session is ready |
53
- | `--proxy` | Proxy traffic: `intercept`, or a custom `http://` url |
54
- | `--session-id` | Name the session; defaults to a generated 3-word id |
55
-
56
- Spawns a daemon that holds the session open and prints JSON on stdout. Waiting
57
- (the default) prints
58
- `{ adbSerial, baseUrl, controlSocket, logs, sessionId, viewerUrl }`
59
- once the device is ready; `--no-wait` prints `{ logs, sessionId }` immediately.
60
- `adbSerial` is present only for an Android session, and only while adb is
61
- available to it: `adb connect <adbSerial>` attaches to the device until the
62
- session ends. `viewerUrl` opens the local browser viewer. `logs`
63
- carries a `device` and a `daemon` path, plus a `network` path — the JSONL capture
64
- of the app's traffic — when started with `--proxy` (or `--proxy intercept`).
65
-
66
- Network traffic can be proxied or intercepted for debugging. `--proxy` (or
67
- `--proxy intercept`) provisions the intercepting proxy so traffic can be
68
- captured; `--proxy http://host:port` routes through a proxy of your own, and the
69
- streaming server rejects any other scheme. Interception rewrites TLS, so an app
70
- that pins certificates may not work under it.
71
-
72
- `sessionId` is what every other command takes. A generated one looks like
73
- `tidy-pandas-jump`; a name you pass may use letters, digits, `.`, `-` and `_`,
74
- and starting a session with an id already in use fails.
5
+ ## Output and exit codes
75
6
 
76
- ## session stop
7
+ Results go to stdout and hold only what you could not know beforehand; `{}`
8
+ means the command ran. `APPETIZE_OUTPUT` (`json` or `text`) applies when neither
9
+ `--json` nor `--no-json` is passed.
77
10
 
78
- ```
79
- appetize session stop
80
- ```
11
+ Failures exit non-zero and print `{ "error": { "message": "…" } }` to stderr,
12
+ plus `hints` when there is something to try, and `sessionDir` once a session is
13
+ found. An expired selector `--timeout` is a failure, which is what makes it a
14
+ wait.
81
15
 
82
- Signals the daemon to shut down and prints `{ sessionId }`. Reports
83
- the id even if the daemon had already exited, so it is safe to call twice.
84
-
85
- ## build list
16
+ Session directories live under `~/.appetize/cli/sessions/`, or
17
+ `$APPETIZE_CLI_HOME`.
86
18
 
87
- ```
88
- appetize build list [options]
89
- ```
90
-
91
- | Flag | Meaning |
92
- | ------------ | ------------------------------------------- |
93
- | `--app` | App id to filter by (bundle or package id) |
94
- | `--endpoint` | Appetize URL; overrides `APPETIZE_ENDPOINT` |
95
- | `--limit` | Builds per page (default 10, max 200) |
96
- | `--page` | Page of results to fetch (default 1) |
97
-
98
- Lists one page of the account's uploaded builds, newest first, printing
99
- `{ builds, nextPage, total }` on stdout. Each build's `id` is a target
100
- `session start` takes, alongside `appId`, `platform`, `versionName`,
101
- `buildNumber` and `created`. Pass a non-null `nextPage` back as `--page` to
102
- continue. Requires `APPETIZE_API_TOKEN`. Takes no session.
19
+ ## session start
103
20
 
104
- ## build upload
21
+ - `--session-id` may use letters, digits, `.`, `-` and `_`. Reusing one fails
22
+ unless `--force` replaces that session.
23
+ - `--no-wait` returns just `sessionId` and `logs`, so you can work while the
24
+ device boots.
25
+ - `adbSerial` appears only while adb is available, and attaches until the
26
+ session ends.
27
+ - `--proxy http://host:port` routes through your own proxy; other schemes are
28
+ rejected. Interception rewrites TLS, so an app that pins certificates may
29
+ fail under it.
105
30
 
106
- ```
107
- appetize build upload <file> [options]
108
- ```
31
+ ## session stop
109
32
 
110
- | Flag | Meaning |
111
- | ------------ | --------------------------------------------------- |
112
- | `--endpoint` | Appetize URL; overrides `APPETIZE_ENDPOINT` |
113
- | `--note` | Note to store with the build |
114
- | `--tags` | Comma separated tags to store with the build |
115
- | `--timeout` | Milliseconds to wait with `--wait` (default 120000) |
116
- | `--wait` | Wait for the app id and version metadata to resolve |
33
+ Waits for the daemon to exit, so logs are complete; `--no-wait` only signals
34
+ it. Safe to call twice.
117
35
 
118
- Uploads a `.apk`, `.apks`, `.zip` or `.tar.gz` and prints
119
- `{ created, id, platform }` on stdout, where `id` is a target `session start`
120
- takes.
36
+ ## build list
121
37
 
122
- The extension decides the platform — `.apk` and `.apks` are Android, `.zip`,
123
- `.tar.gz` and `.tgz` are iOS — and any other file is refused before uploading.
38
+ Newest first. Pass a non-null `nextPage` back as `--page` to continue.
124
39
 
125
- Appetize fills in `appId`, `versionName` and `buildNumber` by processing the
126
- file after the upload responds, which takes a few seconds and is not needed to
127
- start a session. `--wait` polls until they appear and prints the full
128
- `build list` shape, failing once `--timeout` elapses.
40
+ ## build upload
129
41
 
130
- Requires `APPETIZE_API_TOKEN`. Takes no session.
42
+ The extension decides the platform: `.apk` and `.apks` are Android, `.zip`,
43
+ `.tar.gz` and `.tgz` are iOS. `appId`, `versionName` and `buildNumber` resolve a
44
+ few seconds after upload and are not needed to start a session; `--wait` polls
45
+ for them.
131
46
 
132
47
  ## device list
133
48
 
134
- ```
135
- appetize device list [options]
136
- ```
137
-
138
- | Flag | Meaning |
139
- | ------------ | ------------------------------------------- |
140
- | `--endpoint` | Appetize URL; overrides `APPETIZE_ENDPOINT` |
141
- | `--platform` | Platform to filter by: `ios` or `android` |
142
-
143
- Lists available device models, printing `{ devices }` on stdout. Each device's
144
- `id` is the `<device-id>` `session start` takes, alongside `name`, `platform`
145
- and `osVersions` — the values `--device-os-version` accepts. Needs no
146
- `APPETIZE_API_TOKEN`. Takes no session.
147
-
148
- ## inspect
149
-
150
- ```
151
- appetize inspect [output] [options]
152
- ```
49
+ Needs no `APPETIZE_API_TOKEN`. `osVersions` are the values
50
+ `--device-os-version` accepts.
153
51
 
154
- | Flag | Meaning |
155
- | ----------------------------------------------------- | -------------------------------------------------- |
156
- | `--select-text`, `--select-test-id`, `--select-index` | Scope to one element — see [Selectors](#selectors) |
157
- | `--timeout` | Milliseconds to wait for the element |
158
- | `--pretty` | Indent the JSON |
52
+ ## gesture
159
53
 
160
- `output` defaults to `inspect.json`; `.json` is added if you omit an extension.
161
- Writes the hierarchy to that file and prints `{ bytes, nodes, output }` on stdout.
162
- The JSON is `{ platform, root }`, where each node carries `attributes`, `bounds`
163
- and `children`. Only currently visible elements appear.
54
+ `--help` holds the syntax and examples. Every element is resolved before the
55
+ gesture starts, so a missing one fails without touching the screen; so does a
56
+ syntax error, reporting its position.
164
57
 
165
- Unscoped output on an ordinary screen exceeds 100 KB, so prefer a selector and
166
- read the file.
58
+ Android ignores a second tap within 40 ms, and `{wait}` overruns its 300 ms
59
+ double-tap window.
167
60
 
168
- ## tap
169
-
170
- ```
171
- appetize tap [options]
172
- ```
173
-
174
- | Flag | Meaning |
175
- | ------------ | -------------------------------------------------------- |
176
- | `--select-*` | Element or position to tap — see [Selectors](#selectors) |
177
- | `--timeout` | Milliseconds to wait for the element |
178
-
179
- Prints `{}`. Combining an element selector with `--select-x` /
180
- `--select-y` taps a point within that element, and values outside `0-1` are
181
- allowed to reach just beyond its edge (e.g. `--select-x=-0.1`).
182
-
183
- ## swipe
184
-
185
- ```
186
- appetize swipe [options]
187
- ```
188
-
189
- | Flag | Meaning |
190
- | ------------- | ------------------------------------------------------ |
191
- | `--direction` | `down`, `left`, `right` or `up` |
192
- | `--distance` | Travel as a fraction of the screen (0-1) |
193
- | `--from-*` | Where the gesture starts — see [Selectors](#selectors) |
194
- | `--to-*` | Where the gesture ends — see [Selectors](#selectors) |
195
- | `--duration` | Milliseconds the gesture travels for |
196
- | `--timeout` | Milliseconds to wait for any `--from`/`--to` elements |
61
+ ## inspect
197
62
 
198
- Prints `{}`. Two shapes are valid: a `--direction` with an
199
- optional `--from-*` starting point, or both a `--from-*` and a `--to-*` point to
200
- form a path. Mixing `--direction` with `--to-*` is an error, as is `--distance`
201
- without `--direction`.
63
+ Writes `{ platform, root }`, where each node carries `attributes`, `bounds` and
64
+ `children`. `.json` is added if you omit an extension.
202
65
 
203
66
  ## type
204
67
 
205
- ```
206
- appetize type <text> [options]
207
- ```
208
-
209
- | Flag | Meaning |
210
- | --------- | ---------------------------------- |
211
- | `--delay` | Milliseconds to wait between steps |
212
-
213
- Prints `{}`. Bare text is delivered as a string; `{...}` names a
214
- key delivered as a keystroke. Supported keys: `ArrowDown`, `ArrowLeft`,
215
- `ArrowRight`, `ArrowUp`, `Backspace`, `Enter`, `Tab`. A token may carry a repeat
216
- count as in `{Backspace>16/}`, and `{{` types a literal `{`. An unclosed token
217
- or an unsupported key name fails without typing anything.
218
-
219
- Typing does not focus a field — tap it first.
220
-
221
- ## press
222
-
223
- ```
224
- appetize press <button>
225
- ```
226
-
227
- Prints `{}`. Buttons: `home` and `lock` on both platforms;
228
- `back`, `menu`, `unlock`, `volumeUp` and `volumeDown` on Android only. Calling
229
- an Android-only button on iOS fails.
230
-
231
- There is no keyboard-dismiss action. To dismiss the soft keyboard, see the
232
- main page.
233
-
234
- ## rotate
235
-
236
- ```
237
- appetize rotate <orientation>
238
- ```
239
-
240
- Prints `{}`. Orientations: `portrait`, `landscapeLeft`,
241
- `landscapeRight`, `upsideDown`.
68
+ Typing does not focus a field — tap it first. `{Backspace>16/}` repeats a key
69
+ and `{{` types a literal `{`. An unclosed token or unknown key fails without
70
+ typing anything.
242
71
 
243
72
  ## open
244
73
 
245
- ```
246
- appetize open <url>
247
- ```
248
-
249
- Prints `{}`. `<url>` is a deep link (`myapp://orders/42`) or an
250
- http(s) URL. A malformed or scheme-less value is refused.
251
-
252
- ## keychain clear
253
-
254
- ```
255
- appetize keychain clear
256
- ```
257
-
258
- Prints `{}`. iOS only: clears the entire keychain. No effect on
259
- Android.
260
-
261
- ## screenshot
262
-
263
- ```
264
- appetize screenshot [output]
265
- ```
266
-
267
- `output` defaults to `screenshot`, and an extension matching the image is added
268
- if you omit one. Writes a PNG and prints `{ bytes, output }`.
74
+ A scheme-less value is refused. iOS caps URLs at 2048 characters.
269
75
 
270
76
  ## recording start
271
77
 
272
- ```
273
- appetize recording start <output> [options]
274
- ```
275
-
276
- | Flag | Meaning |
277
- | --------- | --------------------------------------- |
278
- | `--force` | Overwrite the file if it already exists |
279
-
280
- Asks the daemon to open the device video stream and capture it to `output`,
281
- printing `{ path }`. Capture is opt-in — video is lazy
282
- device-side, so nothing streams until this runs.
283
-
284
- `output` is required. `.mp4` is added if you omit an extension, any other
285
- extension is refused, and the directory must already exist. A relative path
286
- resolves against your shell rather than the daemon's.
287
-
288
- Starting while a recording is already running fails, whatever path you name —
289
- adopting it would hand you a file that began whenever the first call did.
290
-
291
- The daemon owns the stream and the file, so the command returns as soon as
292
- capture is running.
78
+ `.mp4` is added if you omit an extension, any other extension is refused, and
79
+ the directory must already exist. Starting while a recording runs fails, as
80
+ does an existing file without `--force`.
293
81
 
294
82
  ## recording stop
295
83
 
296
- ```
297
- appetize recording stop
298
- ```
299
-
300
- Closes the stream and the file, printing `{ path }`. Fails
301
- with `No video recording in progress` when nothing is recording. Ending the
302
- session while recording closes the file too, noting it in `daemon.log`.
303
-
304
- A session that dies unexpectedly still leaves the file playable, losing at most
305
- the last second.
306
-
307
- Every frame is written at a constant 30fps, so playback does not track real
308
- time. A rotation keeps the original dimensions and is noted in `daemon.log`.
309
-
310
- Recording over an existing file fails unless you pass `--force`, so name a new
311
- file to record more than once in a session.
312
-
313
- `output` is resolved and checked by the CLI, so a bad path fails before the
314
- daemon is contacted.
84
+ Fails when nothing is recording. Ending the session closes the file too, and a
85
+ session that dies unexpectedly still leaves it playable, losing at most the
86
+ last second. A write failure is reported here, not when it happens.
315
87
 
316
- A write failure is reported once the recording stops, not when it happens.
88
+ Playback is a constant 30fps, so it does not track real time. A rotation keeps
89
+ the original dimensions.
317
90
 
318
91
  ## skill install
319
92
 
320
- ```
321
- appetize skill install [options]
322
- ```
323
-
324
- | Flag | Meaning |
325
- | --------- | -------------------------------------------------------------- |
326
- | `--agent` | `agents`, `claude`, `codex`, `copilot` or `cursor`; repeatable |
327
- | `--scope` | `project` (default), or `user` for your home directory |
328
-
329
- Installs this skill for each agent whose directory is already present — Claude
330
- Code reads `.claude/skills`, the others `.agents/skills` — and into both when
331
- none is found. `--agent` names agents directly instead. Takes no session.
93
+ Installs into each agent directory already present — `.claude/skills` for
94
+ Claude Code, `.agents/skills` for the others — and into both when none is.
332
95
 
333
96
  ## Selectors
334
97
 
335
- Selector flags come as a prefix naming which point is being selected, plus a
336
- suffix naming how. The prefixes:
337
-
338
- - `inspect --select-*`
339
- - `tap --select-*`
340
- - `swipe --from-*` and `swipe --to-*`
341
-
342
- Element suffixes, identical under every prefix:
343
-
344
- | Flag | Meaning |
345
- | -------------------- | --------------------------------------------------------------------------------------------------------------------- |
346
- | `--<prefix>-text` | Exact string, or `/regex/flags` such as `/sign in/i` |
347
- | `--<prefix>-test-id` | Exact match — on Android the whole `resource-id` or the part after its last `/`, on iOS the `accessibilityIdentifier` |
348
- | `--<prefix>-index` | Which match when several, 0-based |
349
-
350
- So `inspect --select-text 'Log in'`, `tap --select-test-id save` and
351
- `swipe --from-test-id card --to-test-id bin` all name elements the same way.
352
-
353
- Position suffixes, accepted by `tap` and `swipe` (not `inspect`):
354
-
355
- | Flag | Meaning |
356
- | ------------------------------ | -------------------------------------------------------------------------------------------- |
357
- | `--<prefix>-position` | Screen position as `x,y`, each 0-1, e.g. `0.5,0.75` |
358
- | `--<prefix>-x`, `--<prefix>-y` | Position within the matched element (0-1, negative/>1 to reach outside the selected element) |
359
-
360
- Pick one kind of match per point. Prefer a test id, then text; reach for a
361
- position when the target has no identity of its own, such as a canvas or a
362
- slider track.
363
-
364
- ## Environment
365
-
366
- | Variable | Meaning |
367
- | -------------------- | ---------------------------------------------- |
368
- | `APPETIZE_API_TOKEN` | Authorizes private APIs and session targets |
369
- | `APPETIZE_ENDPOINT` | Appetize URL used when `--endpoint` is omitted |
370
- | `APPETIZE_CLI_HOME` | Overrides the session state directory |
371
- | `APPETIZE_OUTPUT` | `json` or `text` when neither flag is passed |
372
-
373
- Session state is written to `~/.appetize/cli/sessions/<session-id>/state.json`.
374
- Device logs stream as JSONL to `device.log.jsonl` beside it, and the daemon's
375
- own output goes to `daemon.log`.
376
-
377
- ## Exit codes and output streams
378
-
379
- Commands exit `0` on success and non-zero on failure, printing
380
- `{ "error": { "message": "…" } }` to stderr (text on a terminal, unless
381
- `--json`), plus `sessionDir` (the session's
382
- logs and `state.json`) once a session is found, unless the command was misused.
383
- A selector `--timeout` that expires is a failure, which is what makes it usable
384
- as a wait.
385
-
386
- Results go to stdout as JSON (text on a terminal, unless `--json`) and hold
387
- only what you could not know beforehand; `{}` means the command ran. stderr
388
- carries only errors, plus a progress spinner on an interactive terminal.
389
-
390
- Common failures:
98
+ `inspect --select-*`, `tap --select-*` and `swipe --from-*`/`--to-*` share the
99
+ same suffixes. `-text` is an exact string or `/regex/flags`; `-index` is
100
+ 0-based. `-test-id` is an exact match: on Android the whole `resource-id` or the
101
+ part after its last `/`, on iOS the `accessibilityIdentifier`.
391
102
 
392
- | Message | What to check |
393
- | --------------------------- | --------------------------------------------------------------------------------- |
394
- | `No active sessions` | `session start` first; if one should be live, its `daemon.log` says why it exited |
395
- | `No session found for id X` | `endedReason` in the session's `state.json` |
396
- | `Session is not ready` | `state.phase` in `state.json` under `error.sessionDir` says how far it got |
103
+ Only `tap` and `swipe` take positions. `-position` is a screen `x,y`, each 0-1;
104
+ `-x` and `-y` place the point within the matched element, beyond its edge when
105
+ outside 0-1.