vibeview 0.20.3 → 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.
- package/dist/{chunk-MCCXPIGE.js → chunk-KON2FOEC.js} +9 -0
- package/dist/{chunk-QZNZPKHV.js → chunk-VVKF7GGL.js} +45 -2
- package/dist/cli.js +65 -10
- package/dist/{server-UN5JRYGY.js → server-WWNWYD4Q.js} +3 -3
- package/dist/{upload-app-HUMMA6UY.js → upload-app-W6NOSJPA.js} +1 -1
- package/package.json +1 -1
- package/skills/vibeview-agent/SKILL.md +6 -4
|
@@ -490,6 +490,15 @@ var ApiClient = class {
|
|
|
490
490
|
...body.changesNotSentForReview !== void 0 ? { changes_not_sent_for_review: body.changesNotSentForReview } : {}
|
|
491
491
|
});
|
|
492
492
|
}
|
|
493
|
+
/** GET /api/v1/submissions/preflight — is the store ready to receive
|
|
494
|
+
* this app? Answers by identifier (bundle id / package name), so it can
|
|
495
|
+
* run before any build exists. Always resolves — a "not ready" is an
|
|
496
|
+
* answer carried in `status`/`message`, never a thrown error. */
|
|
497
|
+
async checkStorePreflight(q) {
|
|
498
|
+
const params = new URLSearchParams({ platform: q.platform, identifier: q.identifier });
|
|
499
|
+
if (q.ascKey !== void 0) params.set("asc_key", q.ascKey);
|
|
500
|
+
return this.requestRaw("GET", `/submissions/preflight?${params.toString()}`);
|
|
501
|
+
}
|
|
493
502
|
/** GET /api/v1/submissions?build=<id> — that build's submissions, newest
|
|
494
503
|
* first. */
|
|
495
504
|
async listSubmissions(build) {
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
loadConfig,
|
|
7
7
|
resolveAuth,
|
|
8
8
|
uploadAppBuild
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KON2FOEC.js";
|
|
10
10
|
|
|
11
11
|
// src/lib/dev-state.ts
|
|
12
12
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
@@ -2068,16 +2068,33 @@ async function startDevSession(cfg, onEvent = () => {
|
|
|
2068
2068
|
const sessionId = created.session_id;
|
|
2069
2069
|
let stopping = false;
|
|
2070
2070
|
let tunnel = null;
|
|
2071
|
+
let queueEntryId = null;
|
|
2071
2072
|
const stopSession = async (code) => {
|
|
2072
2073
|
if (stopping) return;
|
|
2073
2074
|
stopping = true;
|
|
2074
2075
|
tunnel?.stop();
|
|
2076
|
+
if (queueEntryId !== null) {
|
|
2077
|
+
await api.cancelQueueEntry(queueEntryId).catch(() => {
|
|
2078
|
+
});
|
|
2079
|
+
queueEntryId = null;
|
|
2080
|
+
}
|
|
2075
2081
|
await api.stopSession(sessionId).catch(() => {
|
|
2076
2082
|
});
|
|
2077
2083
|
onEvent({ event: "session_ended", session_id: sessionId, code });
|
|
2078
2084
|
};
|
|
2079
2085
|
try {
|
|
2080
|
-
await api.startSession(sessionId);
|
|
2086
|
+
const started = await api.startSession(sessionId);
|
|
2087
|
+
if (started.status === "queued") {
|
|
2088
|
+
queueEntryId = started.queue_entry_id ?? null;
|
|
2089
|
+
onEvent({
|
|
2090
|
+
event: "queued",
|
|
2091
|
+
session_id: sessionId,
|
|
2092
|
+
position: started.position ?? null,
|
|
2093
|
+
queue_entry_id: queueEntryId
|
|
2094
|
+
});
|
|
2095
|
+
await pollWhileQueued(api, sessionId, QUEUE_WAIT_MS);
|
|
2096
|
+
queueEntryId = null;
|
|
2097
|
+
}
|
|
2081
2098
|
const pageUrl = `${cfg.webUrl || cfg.baseUrl}/sandbox/${sessionId}`;
|
|
2082
2099
|
const reportedWarnings = /* @__PURE__ */ new Set();
|
|
2083
2100
|
if (usesTunnel) {
|
|
@@ -2142,6 +2159,25 @@ var BLOCKING_WARNING_PREFIXES = ["No debug build", "App install failed", "App no
|
|
|
2142
2159
|
function findBlockingWarning(info) {
|
|
2143
2160
|
return (info.warnings ?? []).find((w) => BLOCKING_WARNING_PREFIXES.some((p) => w.includes(p)));
|
|
2144
2161
|
}
|
|
2162
|
+
var QUEUE_WAIT_MS = 30 * 6e4;
|
|
2163
|
+
async function pollWhileQueued(api, sessionId, timeoutMs, intervalMs = 3e3) {
|
|
2164
|
+
const deadline = Date.now() + timeoutMs;
|
|
2165
|
+
for (; ; ) {
|
|
2166
|
+
const info = await api.getSession(sessionId);
|
|
2167
|
+
const blocking = findBlockingWarning(info);
|
|
2168
|
+
if (blocking) throw new Error(blocking);
|
|
2169
|
+
if (info.status === "stopped" || info.status === "failed") {
|
|
2170
|
+
throw new Error(`session ${info.status} while waiting for a device`);
|
|
2171
|
+
}
|
|
2172
|
+
if (info.status !== "pending" && info.status !== "queued") return info;
|
|
2173
|
+
if (Date.now() > deadline) {
|
|
2174
|
+
throw new Error(
|
|
2175
|
+
`no device became free within ${Math.round(timeoutMs / 6e4)} minutes \u2014 try again later or pick another device`
|
|
2176
|
+
);
|
|
2177
|
+
}
|
|
2178
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2145
2181
|
async function pollUntilTunnelReady(api, sessionId, timeoutMs, intervalMs = 2e3) {
|
|
2146
2182
|
const deadline = Date.now() + timeoutMs;
|
|
2147
2183
|
for (; ; ) {
|
|
@@ -2537,6 +2573,13 @@ async function runDevInProcess(opts) {
|
|
|
2537
2573
|
} else {
|
|
2538
2574
|
console.error(chalk3.yellow(`\u26A0 ${evt.message}`));
|
|
2539
2575
|
}
|
|
2576
|
+
} else if (evt.event === "queued") {
|
|
2577
|
+
const where = evt.position ? ` (position ${evt.position})` : "";
|
|
2578
|
+
console.error(
|
|
2579
|
+
chalk3.yellow(
|
|
2580
|
+
`\u23F3 every device is busy \u2014 waiting in the queue${where}, Ctrl-C to give up`
|
|
2581
|
+
)
|
|
2582
|
+
);
|
|
2540
2583
|
} else if (evt.event === "tunnel_connected") {
|
|
2541
2584
|
everConnected = true;
|
|
2542
2585
|
console.error(chalk3.green("\u2713 tunnel connected \u2014 edit away, Fast Refresh is live"));
|
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
readDevState,
|
|
16
16
|
readMetroState,
|
|
17
17
|
runAgentVerb
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-VVKF7GGL.js";
|
|
19
19
|
import {
|
|
20
20
|
ApiClient,
|
|
21
21
|
EXIT_INFRA_ERROR,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
resolveAuth,
|
|
29
29
|
saveConfig,
|
|
30
30
|
uploadApp
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-KON2FOEC.js";
|
|
32
32
|
|
|
33
33
|
// src/cli.ts
|
|
34
34
|
import { createRequire } from "module";
|
|
@@ -1387,7 +1387,8 @@ function defaultDeps2(client) {
|
|
|
1387
1387
|
createSubmission: client.createSubmission.bind(client),
|
|
1388
1388
|
getSubmission: client.getSubmission.bind(client),
|
|
1389
1389
|
getSubmissionLog: client.getSubmissionLog.bind(client),
|
|
1390
|
-
listCloudBuilds: client.listCloudBuilds.bind(client)
|
|
1390
|
+
listCloudBuilds: client.listCloudBuilds.bind(client),
|
|
1391
|
+
checkStorePreflight: client.checkStorePreflight.bind(client)
|
|
1391
1392
|
};
|
|
1392
1393
|
}
|
|
1393
1394
|
var POLL_INTERVAL_MS2 = 2e3;
|
|
@@ -1450,10 +1451,20 @@ async function submitCommand(opts, deps) {
|
|
|
1450
1451
|
}
|
|
1451
1452
|
const platform = opts.platform;
|
|
1452
1453
|
const androidFamily = platform === "android" || platform === "androidtv";
|
|
1453
|
-
if (opts.
|
|
1454
|
+
if (opts.check && (opts.build || opts.latest)) {
|
|
1455
|
+
throw new UsageError(
|
|
1456
|
+
"--check looks the app up by identifier, not by build \u2014 drop --build/--latest (pass --bundle-id for ios/tvos or --package for android/androidtv)"
|
|
1457
|
+
);
|
|
1458
|
+
}
|
|
1459
|
+
if (!opts.check && opts.bundleId !== void 0) {
|
|
1460
|
+
throw new UsageError(
|
|
1461
|
+
"--bundle-id only applies with --check \u2014 a submission reads the bundle id from the build itself"
|
|
1462
|
+
);
|
|
1463
|
+
}
|
|
1464
|
+
if (!opts.check && opts.build && opts.latest) {
|
|
1454
1465
|
throw new UsageError("pass either --build <id> or --latest, not both");
|
|
1455
1466
|
}
|
|
1456
|
-
if (!opts.build && !opts.latest) {
|
|
1467
|
+
if (!opts.check && !opts.build && !opts.latest) {
|
|
1457
1468
|
throw new UsageError(
|
|
1458
1469
|
"pass --build <id> (see `vibeview builds list`) or --latest (the newest succeeded production build for this platform)"
|
|
1459
1470
|
);
|
|
@@ -1467,6 +1478,11 @@ async function submitCommand(opts, deps) {
|
|
|
1467
1478
|
if (androidFamily && opts.ascKey !== void 0) {
|
|
1468
1479
|
throw new UsageError(`--asc-key only applies to ios/tvos (TestFlight) \u2014 not ${platform}`);
|
|
1469
1480
|
}
|
|
1481
|
+
if (androidFamily && opts.bundleId !== void 0) {
|
|
1482
|
+
throw new UsageError(
|
|
1483
|
+
`--bundle-id only applies to ios/tvos \u2014 for ${platform} pass --package <name>`
|
|
1484
|
+
);
|
|
1485
|
+
}
|
|
1470
1486
|
if (!androidFamily && opts.releaseStatus !== void 0) {
|
|
1471
1487
|
throw new UsageError(
|
|
1472
1488
|
`--release-status only applies to android/androidtv (Play) \u2014 not ${platform}`
|
|
@@ -1508,6 +1524,10 @@ async function submitCommand(opts, deps) {
|
|
|
1508
1524
|
const { token, baseUrl } = resolveAuth(opts);
|
|
1509
1525
|
const client = new ApiClient(baseUrl, token);
|
|
1510
1526
|
const d = deps ?? defaultDeps2(client);
|
|
1527
|
+
if (opts.check) {
|
|
1528
|
+
await checkStore(platform, androidFamily, ascKey2, opts, d);
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1511
1531
|
try {
|
|
1512
1532
|
const buildId = opts.build ?? await resolveLatestBuild(platform, d);
|
|
1513
1533
|
const sub = await d.createSubmission({
|
|
@@ -1546,6 +1566,37 @@ async function submitCommand(opts, deps) {
|
|
|
1546
1566
|
process.exitCode = 1;
|
|
1547
1567
|
}
|
|
1548
1568
|
}
|
|
1569
|
+
async function checkStore(platform, androidFamily, ascKey2, opts, deps) {
|
|
1570
|
+
const identifier = androidFamily ? opts.package : opts.bundleId;
|
|
1571
|
+
if (!identifier) {
|
|
1572
|
+
throw new UsageError(
|
|
1573
|
+
androidFamily ? `--check needs the package name to look up: --package <name> (e.g. --package io.example.app)` : `--check needs the bundle identifier to look up: --bundle-id <id> (e.g. --bundle-id io.example.app)`
|
|
1574
|
+
);
|
|
1575
|
+
}
|
|
1576
|
+
try {
|
|
1577
|
+
const result = await deps.checkStorePreflight({
|
|
1578
|
+
platform,
|
|
1579
|
+
identifier,
|
|
1580
|
+
...ascKey2 !== void 0 ? { ascKey: ascKey2 } : {}
|
|
1581
|
+
});
|
|
1582
|
+
emit(opts.json, { event: "preflight", ...result });
|
|
1583
|
+
if (!opts.json) {
|
|
1584
|
+
const mark = result.ready ? chalk12.green("\u2713") : chalk12.red("\u2717");
|
|
1585
|
+
console.error(`${mark} ${result.message}`);
|
|
1586
|
+
if (result.ready) {
|
|
1587
|
+
console.error(
|
|
1588
|
+
chalk12.dim(
|
|
1589
|
+
` next: vibeview build --cloud --production --platform ${platform}, then vibeview submit --platform ${platform} --latest`
|
|
1590
|
+
)
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
process.exitCode = result.ready ? 0 : 1;
|
|
1595
|
+
} catch (err) {
|
|
1596
|
+
printError2(opts, err);
|
|
1597
|
+
process.exitCode = 1;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1549
1600
|
async function resolveLatestBuild(platform, deps) {
|
|
1550
1601
|
const { builds: builds2 } = await deps.listCloudBuilds({
|
|
1551
1602
|
platform,
|
|
@@ -3025,7 +3076,7 @@ function resolveMetadata(opts) {
|
|
|
3025
3076
|
}
|
|
3026
3077
|
var program = new Command();
|
|
3027
3078
|
program.name("vibeview").description("VibeView CLI -- run mobile tests from CI/CD pipelines").version(pkg.version);
|
|
3028
|
-
program.command("run-suite <suite-id>").description("Run all test cases in a suite").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show per-case breakdown", false).option("--timeout <seconds>", "Max wait time in seconds", "
|
|
3079
|
+
program.command("run-suite <suite-id>").description("Run all test cases in a suite").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show per-case breakdown", false).option("--timeout <seconds>", "Max wait time in seconds (queue wait plus execution)", "1800").option("--commit-sha <sha>", "Git commit SHA for GitHub status checks").option("--model <model>", "AI model to use").option("--provider <provider>", "AI provider").option("--mode <mode>", "Execution mode: hybrid, ai, replay").option(
|
|
3029
3080
|
"--device-category <category>",
|
|
3030
3081
|
"Device category: phone, tablet, tv (default: phone when --device is not set)",
|
|
3031
3082
|
parseDeviceCategory
|
|
@@ -3053,7 +3104,7 @@ program.command("run-suites").description("Run all suites matching a tag filter"
|
|
|
3053
3104
|
).option("--match <mode>", "any (default) or all", "any").option(
|
|
3054
3105
|
"--platform <platform>",
|
|
3055
3106
|
"Filter matched suites to one platform: ios, android, tvos, androidtv (default: no filter)"
|
|
3056
|
-
).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show per-suite progress", false).option("--timeout <seconds>", "Per-suite timeout, capped at 2 hours total", "
|
|
3107
|
+
).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show per-suite progress", false).option("--timeout <seconds>", "Per-suite timeout, capped at 2 hours total", "1800").option("--commit-sha <sha>", "Git commit SHA propagated to every SuiteRun").option("--model <model>", "AI model").option("--provider <provider>", "AI provider").option("--mode <mode>", "Execution mode: hybrid, ai, replay").option(
|
|
3057
3108
|
"--device-category <category>",
|
|
3058
3109
|
"Device category: phone, tablet, tv (default: phone when --device is not set)",
|
|
3059
3110
|
parseDeviceCategory
|
|
@@ -3073,7 +3124,7 @@ program.command("run-suites").description("Run all suites matching a tag filter"
|
|
|
3073
3124
|
build: opts.build ? parseInt(opts.build, 10) : void 0
|
|
3074
3125
|
});
|
|
3075
3126
|
});
|
|
3076
|
-
program.command("run-test <test-id>").description("Run a single test case").option("--token <token>", "API token").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show step details", false).option("--timeout <seconds>", "Max wait time in seconds", "
|
|
3127
|
+
program.command("run-test <test-id>").description("Run a single test case").option("--token <token>", "API token").option("--output <format>", "Output format: human, json, junit", "human").option("--verbose", "Show step details", false).option("--timeout <seconds>", "Max wait time in seconds (queue wait plus execution)", "1800").option("--commit-sha <sha>", "Git commit SHA for GitHub status checks").option("--model <model>", "AI model to use").option("--provider <provider>", "AI provider").option("--mode <mode>", "Execution mode: hybrid, ai, replay").option(
|
|
3077
3128
|
"--device-category <category>",
|
|
3078
3129
|
"Device category: phone, tablet, tv (default: phone when --device is not set)",
|
|
3079
3130
|
parseDeviceCategory
|
|
@@ -3163,7 +3214,11 @@ program.command("submit").description(
|
|
|
3163
3214
|
).option(
|
|
3164
3215
|
"--rollout <fraction>",
|
|
3165
3216
|
"android/androidtv only: staged-rollout fraction, 0 < f < 1 (requires --release-status inProgress)"
|
|
3166
|
-
).option(
|
|
3217
|
+
).option(
|
|
3218
|
+
"--check",
|
|
3219
|
+
"Only check store readiness: does the store know this app with your stored key? Takes --platform plus --bundle-id (ios/tvos) or --package (android/androidtv); no build needed. Exit 0 when ready",
|
|
3220
|
+
false
|
|
3221
|
+
).option("--bundle-id <id>", "ios/tvos, with --check: the bundle identifier to look up").option("--no-wait", "Print the submission id and exit without waiting for completion").option("--json", "Emit line-delimited JSON events on stdout instead of human output", false).action((opts) => submitCommand(opts));
|
|
3167
3222
|
var builds = program.command("builds").description("Manage cloud builds (see `vibeview build --cloud`)");
|
|
3168
3223
|
builds.command("list").description("List cloud builds in your organization").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--json", "Print the raw build summaries as a JSON array", false).option("--limit <n>", "Max builds to return (default 50, max 200)").action((opts) => buildsList(opts));
|
|
3169
3224
|
builds.command("logs <id>").description("Print a cloud build's log output").option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").option("--json", "Print NDJSON log/outcome events instead of raw text", false).option("--follow", "Keep polling until the build reaches a terminal status", false).action((id, opts) => buildsLogs(id, opts));
|
|
@@ -3255,7 +3310,7 @@ program.command("dev-stop").description("Stop a `vibeview dev --detach` session
|
|
|
3255
3310
|
program.command("mcp").description(
|
|
3256
3311
|
"Run an MCP stdio server exposing the agent verbs (tap, swipe, type, ...) plus dev_start/dev_stop as tools"
|
|
3257
3312
|
).option("--token <token>", "API token (or set VIBEVIEW_API_TOKEN)").action(async (opts) => {
|
|
3258
|
-
const { runMcpServer } = await import("./server-
|
|
3313
|
+
const { runMcpServer } = await import("./server-WWNWYD4Q.js");
|
|
3259
3314
|
await runMcpServer(opts);
|
|
3260
3315
|
});
|
|
3261
3316
|
program.command("agent-setup").description(
|
|
@@ -11,11 +11,11 @@ import {
|
|
|
11
11
|
readDevState,
|
|
12
12
|
renderEnvelope,
|
|
13
13
|
startDevSession
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-VVKF7GGL.js";
|
|
15
15
|
import {
|
|
16
16
|
ApiClient,
|
|
17
17
|
resolveAuth
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-KON2FOEC.js";
|
|
19
19
|
|
|
20
20
|
// src/mcp/server.ts
|
|
21
21
|
import { writeFileSync } from "fs";
|
|
@@ -239,7 +239,7 @@ async function handleUploadApp(args, deps) {
|
|
|
239
239
|
}
|
|
240
240
|
const name = typeof args.name === "string" && args.name ? args.name : void 0;
|
|
241
241
|
const upload = deps.uploadApp ?? (async (f, n) => {
|
|
242
|
-
const { uploadAppBuild } = await import("./upload-app-
|
|
242
|
+
const { uploadAppBuild } = await import("./upload-app-W6NOSJPA.js");
|
|
243
243
|
const { result: result2 } = await uploadAppBuild(f, { ...deps.auth, name: n });
|
|
244
244
|
return result2;
|
|
245
245
|
});
|
package/package.json
CHANGED
|
@@ -5,8 +5,8 @@ description: Verify a React Native change on a real running app — install/laun
|
|
|
5
5
|
|
|
6
6
|
# VibeView agent control
|
|
7
7
|
|
|
8
|
-
Drive a live iOS
|
|
9
|
-
Native change actually works, not just that it compiles. Requires the
|
|
8
|
+
Drive a live iOS, Android, Apple TV or Android TV VibeView session from the
|
|
9
|
+
CLI to verify a React Native change actually works, not just that it compiles. Requires the
|
|
10
10
|
`vibeview` CLI installed and authenticated (`vibeview login`, or
|
|
11
11
|
`VIBEVIEW_API_TOKEN` set).
|
|
12
12
|
|
|
@@ -137,13 +137,15 @@ it rather than letting it appear unexplained in their `git status`.
|
|
|
137
137
|
```
|
|
138
138
|
Use `--press-ms 500` or more for long-press-to-reorder lists, and
|
|
139
139
|
`--velocity 150` for slow, precise slider adjustments.
|
|
140
|
-
- **
|
|
140
|
+
- **System alerts** (permission prompts and similar) sit above the app
|
|
141
141
|
and block it. Call `alert get` first to read the message and the exact
|
|
142
142
|
button labels, then act on one:
|
|
143
143
|
```bash
|
|
144
144
|
vibeview alert get --session <id>
|
|
145
145
|
vibeview alert accept --button "Allow" --session <id>
|
|
146
146
|
```
|
|
147
|
+
On Apple TV this also covers the "Open in …?" prompt a deep link raises;
|
|
148
|
+
the button is answered with the remote.
|
|
147
149
|
- Use `open-url` to jump straight to a deep link instead of navigating by
|
|
148
150
|
hand:
|
|
149
151
|
```bash
|
|
@@ -200,7 +202,7 @@ human-readable text.
|
|
|
200
202
|
| `scroll` | `<direction>` | Scroll the current view up, down, left, or right using a gesture preset. |
|
|
201
203
|
| `scroll-to` | `<text>` `[--direction <up\|down\|left\|right>] [--max-scrolls <n>] [--element-type <type>]` | Scroll until an element matching the text is visible. Stops at end of list. |
|
|
202
204
|
| `drag` | `<from>` `<to>` `[--velocity <n>] [--press-ms <n>] [--hold-ms <n>]` | Drag between two points, each an `@ref` or `x,y`. The only precise two-point gesture. |
|
|
203
|
-
| `alert` | `<get\|accept\|dismiss>` `[--button <label>]` | Inspect or respond to a
|
|
205
|
+
| `alert` | `<get\|accept\|dismiss>` `[--button <label>]` | Inspect or respond to a system alert on iOS or Apple TV. |
|
|
204
206
|
| `type` | `<text>` | Type text into the currently focused input field. |
|
|
205
207
|
| `clear-text` | — | Clear the text in the currently focused input field. |
|
|
206
208
|
| `press` | `<button>` | Press a device button or perform a system gesture (home, back, d-pad, etc). |
|