@yoqa/cli 0.3.26 → 0.3.28
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 +2 -2
- package/dist/main.js +117 -17
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @yoqa/cli
|
|
2
2
|
|
|
3
|
-
CLI for [Yoqa](https://yoqa.
|
|
3
|
+
CLI for [Yoqa](https://yoqa.arisn.dev/docs/overview) — drive a local runner over HTTP from your terminal or CI.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm install -g @yoqa/cli
|
|
@@ -18,4 +18,4 @@ yoqa serve
|
|
|
18
18
|
|
|
19
19
|
Disable auto-start with `YOQA_NO_AUTOSTART=1`. Override the URL with `YOQA_RUNNER_HOST` / `YOQA_RUNNER_PORT` / `YOQA_RUNNER_URL`.
|
|
20
20
|
|
|
21
|
-
See [CLI docs](https://yoqa.
|
|
21
|
+
See [CLI docs](https://yoqa.arisn.dev/docs/cli) and [GitHub Actions](https://yoqa.arisn.dev/docs/github-actions).
|
package/dist/main.js
CHANGED
|
@@ -6263,6 +6263,7 @@ var catalogAppSchema = exports_external.object({
|
|
|
6263
6263
|
name: exports_external.string().min(1),
|
|
6264
6264
|
prefix: exports_external.string().min(1),
|
|
6265
6265
|
context: exports_external.string(),
|
|
6266
|
+
knowledge: exports_external.string(),
|
|
6266
6267
|
iosBundleId: exports_external.string(),
|
|
6267
6268
|
iosAppStoreId: exports_external.string(),
|
|
6268
6269
|
androidApplicationId: exports_external.string(),
|
|
@@ -6278,6 +6279,7 @@ var updateAppRequestSchema = exports_external.object({
|
|
|
6278
6279
|
name: exports_external.string().min(1).optional(),
|
|
6279
6280
|
prefix: exports_external.string().min(1).optional(),
|
|
6280
6281
|
context: exports_external.string().optional(),
|
|
6282
|
+
knowledge: exports_external.string().optional(),
|
|
6281
6283
|
iosBundleId: exports_external.string().optional(),
|
|
6282
6284
|
iosAppStoreId: exports_external.string().optional(),
|
|
6283
6285
|
androidApplicationId: exports_external.string().optional(),
|
|
@@ -6591,7 +6593,8 @@ var probeProviderResponseSchema = exports_external.object({
|
|
|
6591
6593
|
var providerModelSchema = exports_external.object({
|
|
6592
6594
|
id: exports_external.string().min(1),
|
|
6593
6595
|
name: exports_external.string().min(1),
|
|
6594
|
-
provider: exports_external.string().min(1).optional()
|
|
6596
|
+
provider: exports_external.string().min(1).optional(),
|
|
6597
|
+
vision: exports_external.boolean().optional()
|
|
6595
6598
|
});
|
|
6596
6599
|
var listProviderModelsResponseSchema = exports_external.object({
|
|
6597
6600
|
models: exports_external.array(providerModelSchema),
|
|
@@ -6620,6 +6623,7 @@ var runExecutionModeSchema = exports_external.union([
|
|
|
6620
6623
|
exports_external.literal("script"),
|
|
6621
6624
|
exports_external.literal("agent")
|
|
6622
6625
|
]);
|
|
6626
|
+
var runScreenModeSchema = exports_external.union([exports_external.literal("vision"), exports_external.literal("tree")]);
|
|
6623
6627
|
var createRunRequestSchema = exports_external.object({
|
|
6624
6628
|
appId: exports_external.string().min(1),
|
|
6625
6629
|
caseIds: exports_external.array(exports_external.string().min(1)).min(1),
|
|
@@ -6627,7 +6631,17 @@ var createRunRequestSchema = exports_external.object({
|
|
|
6627
6631
|
platform: devicePlatformSchema,
|
|
6628
6632
|
buildId: exports_external.string().min(1).optional(),
|
|
6629
6633
|
buildPath: exports_external.string().min(1).optional(),
|
|
6630
|
-
executionMode: runExecutionModeSchema.optional()
|
|
6634
|
+
executionMode: runExecutionModeSchema.optional(),
|
|
6635
|
+
screenMode: runScreenModeSchema.optional()
|
|
6636
|
+
});
|
|
6637
|
+
var stepPhasesSchema = exports_external.object({
|
|
6638
|
+
captureMs: exports_external.number().nonnegative(),
|
|
6639
|
+
screenMs: exports_external.number().nonnegative(),
|
|
6640
|
+
prepareMs: exports_external.number().nonnegative(),
|
|
6641
|
+
decideMs: exports_external.number().nonnegative(),
|
|
6642
|
+
actionMs: exports_external.number().nonnegative(),
|
|
6643
|
+
settleMs: exports_external.number().nonnegative(),
|
|
6644
|
+
decideRetries: exports_external.number().int().nonnegative()
|
|
6631
6645
|
});
|
|
6632
6646
|
var runStepSchema = exports_external.object({
|
|
6633
6647
|
id: exports_external.string().min(1),
|
|
@@ -6637,6 +6651,7 @@ var runStepSchema = exports_external.object({
|
|
|
6637
6651
|
screenshotUri: exports_external.string().nullable(),
|
|
6638
6652
|
ok: exports_external.boolean(),
|
|
6639
6653
|
latencyMs: exports_external.number().nonnegative(),
|
|
6654
|
+
phases: stepPhasesSchema.nullable().optional(),
|
|
6640
6655
|
detail: exports_external.string().nullable(),
|
|
6641
6656
|
command: exports_external.string().nullable().optional(),
|
|
6642
6657
|
createdAt: exports_external.number().int().nonnegative()
|
|
@@ -6661,6 +6676,7 @@ var runSchema = exports_external.object({
|
|
|
6661
6676
|
buildId: exports_external.string().nullable(),
|
|
6662
6677
|
status: runStatusSchema,
|
|
6663
6678
|
executionMode: runExecutionModeSchema,
|
|
6679
|
+
screenMode: runScreenModeSchema.optional(),
|
|
6664
6680
|
error: exports_external.string().nullable(),
|
|
6665
6681
|
createdAt: exports_external.number().int().nonnegative(),
|
|
6666
6682
|
startedAt: exports_external.number().int().nonnegative().nullable(),
|
|
@@ -6746,7 +6762,16 @@ var actionRequestSchema = exports_external.object({
|
|
|
6746
6762
|
appId: exports_external.string().optional(),
|
|
6747
6763
|
url: exports_external.string().optional(),
|
|
6748
6764
|
alertAction: exports_external.union([exports_external.literal("accept"), exports_external.literal("dismiss")]).optional(),
|
|
6749
|
-
seconds: exports_external.number().optional()
|
|
6765
|
+
seconds: exports_external.number().optional(),
|
|
6766
|
+
screenshot: exports_external.boolean().optional(),
|
|
6767
|
+
settleMs: exports_external.number().int().min(0).max(1e4).optional()
|
|
6768
|
+
});
|
|
6769
|
+
var actionResultScreenshotSchema = exports_external.object({
|
|
6770
|
+
path: exports_external.string().min(1),
|
|
6771
|
+
annotatedPath: exports_external.string().min(1).optional(),
|
|
6772
|
+
settled: exports_external.boolean(),
|
|
6773
|
+
waitedMs: exports_external.number(),
|
|
6774
|
+
changed: exports_external.boolean().nullable()
|
|
6750
6775
|
});
|
|
6751
6776
|
var actionResponseSchema = exports_external.object({
|
|
6752
6777
|
ok: exports_external.literal(true),
|
|
@@ -6754,7 +6779,8 @@ var actionResponseSchema = exports_external.object({
|
|
|
6754
6779
|
resolved: exports_external.object({
|
|
6755
6780
|
x: exports_external.number().optional(),
|
|
6756
6781
|
y: exports_external.number().optional()
|
|
6757
|
-
}).optional()
|
|
6782
|
+
}).optional(),
|
|
6783
|
+
screenshot: actionResultScreenshotSchema.optional()
|
|
6758
6784
|
});
|
|
6759
6785
|
var yoqaStatusResponseSchema = exports_external.object({
|
|
6760
6786
|
runner: exports_external.object({
|
|
@@ -7309,10 +7335,28 @@ async function runYoqaShellScript(client, text, options = {}) {
|
|
|
7309
7335
|
}
|
|
7310
7336
|
|
|
7311
7337
|
// ../runner-client/src/run-report.ts
|
|
7312
|
-
function
|
|
7313
|
-
if (!action || typeof action !== "object")
|
|
7314
|
-
return
|
|
7315
|
-
const
|
|
7338
|
+
function readStepCycle(action) {
|
|
7339
|
+
if (!action || typeof action !== "object" || !("cycle" in action))
|
|
7340
|
+
return null;
|
|
7341
|
+
const cycle = action.cycle;
|
|
7342
|
+
if (!cycle || typeof cycle !== "object")
|
|
7343
|
+
return null;
|
|
7344
|
+
const record = cycle;
|
|
7345
|
+
const asRecord = (value) => value && typeof value === "object" ? value : null;
|
|
7346
|
+
const verify = asRecord(record.verify);
|
|
7347
|
+
if (!verify || typeof verify.type !== "string" || !verify.type)
|
|
7348
|
+
return null;
|
|
7349
|
+
return {
|
|
7350
|
+
action: asRecord(record.action),
|
|
7351
|
+
decision: asRecord(record.decision),
|
|
7352
|
+
verify: {
|
|
7353
|
+
type: verify.type,
|
|
7354
|
+
reason: typeof verify.reason === "string" ? verify.reason : null,
|
|
7355
|
+
thoughts: typeof verify.thoughts === "string" ? verify.thoughts : null
|
|
7356
|
+
}
|
|
7357
|
+
};
|
|
7358
|
+
}
|
|
7359
|
+
function summarizeActionRecord(record) {
|
|
7316
7360
|
const type = typeof record.type === "string" ? record.type : "step";
|
|
7317
7361
|
if (type === "tap") {
|
|
7318
7362
|
if (typeof record.label === "string" && record.label.trim())
|
|
@@ -7382,6 +7426,16 @@ function actionSummary(action) {
|
|
|
7382
7426
|
}
|
|
7383
7427
|
return type.charAt(0).toUpperCase() + type.slice(1);
|
|
7384
7428
|
}
|
|
7429
|
+
function actionSummary(action) {
|
|
7430
|
+
if (!action || typeof action !== "object")
|
|
7431
|
+
return "Step";
|
|
7432
|
+
const cycle = readStepCycle(action);
|
|
7433
|
+
if (cycle?.action)
|
|
7434
|
+
return summarizeActionRecord(cycle.action);
|
|
7435
|
+
if (cycle?.decision)
|
|
7436
|
+
return summarizeActionRecord(cycle.decision);
|
|
7437
|
+
return summarizeActionRecord(action);
|
|
7438
|
+
}
|
|
7385
7439
|
function optionalTrimmedString(value) {
|
|
7386
7440
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
7387
7441
|
}
|
|
@@ -7489,6 +7543,20 @@ function toReportStatus(status) {
|
|
|
7489
7543
|
return status;
|
|
7490
7544
|
return null;
|
|
7491
7545
|
}
|
|
7546
|
+
function formatStepPhases(phases) {
|
|
7547
|
+
const parts = [
|
|
7548
|
+
`capture ${Math.round(phases.captureMs)}ms`,
|
|
7549
|
+
`screen ${Math.round(phases.screenMs)}ms`,
|
|
7550
|
+
`image ${Math.round(phases.prepareMs)}ms`,
|
|
7551
|
+
`decide ${Math.round(phases.decideMs)}ms`,
|
|
7552
|
+
`action ${Math.round(phases.actionMs)}ms`,
|
|
7553
|
+
`settle ${Math.round(phases.settleMs)}ms`
|
|
7554
|
+
];
|
|
7555
|
+
if (phases.decideRetries > 0) {
|
|
7556
|
+
parts.push(`retries ${phases.decideRetries}`);
|
|
7557
|
+
}
|
|
7558
|
+
return parts.join(" · ");
|
|
7559
|
+
}
|
|
7492
7560
|
function mapCatalogStep(step, screenshotsByStepId) {
|
|
7493
7561
|
const { reason, thoughts } = stepReasoning(step);
|
|
7494
7562
|
return {
|
|
@@ -7497,6 +7565,7 @@ function mapCatalogStep(step, screenshotsByStepId) {
|
|
|
7497
7565
|
summary: actionSummary(step.action),
|
|
7498
7566
|
ok: step.ok,
|
|
7499
7567
|
latencyMs: step.latencyMs,
|
|
7568
|
+
phases: step.phases ?? null,
|
|
7500
7569
|
detail: step.detail,
|
|
7501
7570
|
reason,
|
|
7502
7571
|
thoughts,
|
|
@@ -7530,6 +7599,7 @@ function buildRunReportFromCatalogRun(run, meta = {}, screenshotsByStepId = {})
|
|
|
7530
7599
|
deviceLabel: meta.deviceLabel ?? null,
|
|
7531
7600
|
platform: run.platform,
|
|
7532
7601
|
executionMode: run.executionMode,
|
|
7602
|
+
screenMode: run.screenMode ?? null,
|
|
7533
7603
|
error: run.error,
|
|
7534
7604
|
createdAt: run.createdAt,
|
|
7535
7605
|
startedAt: run.startedAt,
|
|
@@ -7577,6 +7647,7 @@ function pngDataUri(base64) {
|
|
|
7577
7647
|
}
|
|
7578
7648
|
function formatRunReportHtml(doc) {
|
|
7579
7649
|
const accent = statusAccent(doc.status);
|
|
7650
|
+
const screenRows = doc.screenMode ? [["Screen", doc.screenMode]] : [];
|
|
7580
7651
|
const metaRows = [
|
|
7581
7652
|
["Status", accent.label],
|
|
7582
7653
|
["Source", doc.source === "catalog" ? "Catalog run" : "Manual Inspector"],
|
|
@@ -7584,6 +7655,7 @@ function formatRunReportHtml(doc) {
|
|
|
7584
7655
|
["Device", doc.deviceLabel ?? "—"],
|
|
7585
7656
|
["Platform", doc.platform ?? "—"],
|
|
7586
7657
|
["Mode", doc.executionMode ?? "—"],
|
|
7658
|
+
...screenRows,
|
|
7587
7659
|
["Started", formatWhen(doc.startedAt ?? doc.createdAt)],
|
|
7588
7660
|
["Finished", formatWhen(doc.finishedAt)],
|
|
7589
7661
|
["Duration", formatDuration(doc.startedAt ?? doc.createdAt, doc.finishedAt)],
|
|
@@ -7599,6 +7671,7 @@ function formatRunReportHtml(doc) {
|
|
|
7599
7671
|
const detailBlock = step.detail && step.detail !== step.reason ? `<p class="detail">${escapeHtml(step.detail)}</p>` : "";
|
|
7600
7672
|
const shot = step.screenshotBase64 ? `<img class="shot" alt="Step ${step.index} screenshot" src="${pngDataUri(step.screenshotBase64)}" />` : `<p class="muted">No screenshot</p>`;
|
|
7601
7673
|
const latency = step.latencyMs != null ? `<span class="muted">${step.latencyMs}ms</span>` : "";
|
|
7674
|
+
const phases = step.phases ? `<p class="muted phases">Phases: ${escapeHtml(formatStepPhases(step.phases))}</p>` : "";
|
|
7602
7675
|
const commandBlock = step.command ? `<pre class="command"><code>${escapeHtml(step.command)}</code></pre>` : "";
|
|
7603
7676
|
return `
|
|
7604
7677
|
<article class="step ${step.ok ? "ok" : "fail"}">
|
|
@@ -7610,6 +7683,7 @@ function formatRunReportHtml(doc) {
|
|
|
7610
7683
|
</div>
|
|
7611
7684
|
</header>
|
|
7612
7685
|
${commandBlock}
|
|
7686
|
+
${phases}
|
|
7613
7687
|
${reasonBlock}
|
|
7614
7688
|
${detailBlock}
|
|
7615
7689
|
${thoughtsBlock}
|
|
@@ -7707,6 +7781,7 @@ function formatRunReportMarkdown(doc) {
|
|
|
7707
7781
|
`| Device | ${escapeMd(doc.deviceLabel ?? "—")} |`,
|
|
7708
7782
|
`| Platform | ${escapeMd(doc.platform ?? "—")} |`,
|
|
7709
7783
|
`| Mode | ${escapeMd(doc.executionMode ?? "—")} |`,
|
|
7784
|
+
...doc.screenMode ? [`| Screen | ${escapeMd(doc.screenMode)} |`] : [],
|
|
7710
7785
|
`| Started | ${escapeMd(formatWhen(doc.startedAt ?? doc.createdAt))} |`,
|
|
7711
7786
|
`| Finished | ${escapeMd(formatWhen(doc.finishedAt))} |`,
|
|
7712
7787
|
`| Duration | ${escapeMd(formatDuration(doc.startedAt ?? doc.createdAt, doc.finishedAt))} |`,
|
|
@@ -7735,6 +7810,8 @@ function formatRunReportMarkdown(doc) {
|
|
|
7735
7810
|
lines.push(`- Command: \`${step.command.replace(/`/g, "'")}\``);
|
|
7736
7811
|
if (step.latencyMs != null)
|
|
7737
7812
|
lines.push(`- Latency: ${step.latencyMs}ms`);
|
|
7813
|
+
if (step.phases)
|
|
7814
|
+
lines.push(`- Phases: ${formatStepPhases(step.phases)}`);
|
|
7738
7815
|
if (step.reason)
|
|
7739
7816
|
lines.push(`- Reason: ${step.reason}`);
|
|
7740
7817
|
if (step.detail && step.detail !== step.reason)
|
|
@@ -7771,6 +7848,7 @@ function formatRunReportGithubSummary(doc) {
|
|
|
7771
7848
|
`| Device | ${escapeMd(doc.deviceLabel ?? "—")} |`,
|
|
7772
7849
|
`| Platform | ${escapeMd(doc.platform ?? "—")} |`,
|
|
7773
7850
|
`| Mode | ${escapeMd(doc.executionMode ?? "—")} |`,
|
|
7851
|
+
...doc.screenMode ? [`| Screen | ${escapeMd(doc.screenMode)} |`] : [],
|
|
7774
7852
|
`| Duration | ${escapeMd(formatDuration(doc.startedAt ?? doc.createdAt, doc.finishedAt))} |`,
|
|
7775
7853
|
`| Run ID | \`${doc.id}\` |`,
|
|
7776
7854
|
""
|
|
@@ -8277,7 +8355,7 @@ var {
|
|
|
8277
8355
|
// package.json
|
|
8278
8356
|
var package_default = {
|
|
8279
8357
|
name: "@yoqa/cli",
|
|
8280
|
-
version: "0.3.
|
|
8358
|
+
version: "0.3.28",
|
|
8281
8359
|
description: "Yoqa CLI — drive local mobile QA from the terminal or CI (talks to the Yoqa runner over HTTP)",
|
|
8282
8360
|
license: "UNLICENSED",
|
|
8283
8361
|
type: "module",
|
|
@@ -8295,7 +8373,7 @@ var package_default = {
|
|
|
8295
8373
|
url: "git+https://github.com/Aris-ngoy/qa-agent.git",
|
|
8296
8374
|
directory: "packages/cli"
|
|
8297
8375
|
},
|
|
8298
|
-
homepage: "https://yoqa.
|
|
8376
|
+
homepage: "https://yoqa.arisn.dev/docs/cli",
|
|
8299
8377
|
bugs: {
|
|
8300
8378
|
url: "https://github.com/Aris-ngoy/qa-agent/issues"
|
|
8301
8379
|
},
|
|
@@ -8315,7 +8393,7 @@ var package_default = {
|
|
|
8315
8393
|
health: "bun run src/main.ts health"
|
|
8316
8394
|
},
|
|
8317
8395
|
dependencies: {
|
|
8318
|
-
"@yoqa/runner": "0.3.
|
|
8396
|
+
"@yoqa/runner": "0.3.28"
|
|
8319
8397
|
},
|
|
8320
8398
|
devDependencies: {
|
|
8321
8399
|
"@types/node": "^22.15.30",
|
|
@@ -9244,7 +9322,14 @@ program2.command("screenshot").description("Capture a screenshot from the active
|
|
|
9244
9322
|
});
|
|
9245
9323
|
var action = program2.command("action").description("Perform an action on the active device");
|
|
9246
9324
|
function addActionOptions(cmd) {
|
|
9247
|
-
return cmd.option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").option("-d, --description <text>", "Ground target by natural language").option("--label <text>", "Tap/focus by accessibility label (cleaned screen tree)").option("--id <text>", "Tap/focus by resource-id / accessibility id").option("--x <n>", "X in 0–1000", (v) => Number(v)).option("--y <n>", "Y in 0–1000", (v) => Number(v)).option("--x2 <n>", "End X in 0–1000", (v) => Number(v)).option("--y2 <n>", "End Y in 0–1000", (v) => Number(v)).option("--duration <ms>", "Gesture duration ms (long-press for tap)", (v) => Number(v)).option("--double", "Double-tap (tap only)").option("--text <text>", "Text to type").option("--app-id <id>", "Bundle id / application id").option("--url <url>", "URL to open").option("--seconds <n>", "Background seconds", (v) => Number(v));
|
|
9325
|
+
return cmd.option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").option("-d, --description <text>", "Ground target by natural language").option("--label <text>", "Tap/focus by accessibility label (cleaned screen tree)").option("--id <text>", "Tap/focus by resource-id / accessibility id").option("--x <n>", "X in 0–1000", (v) => Number(v)).option("--y <n>", "Y in 0–1000", (v) => Number(v)).option("--x2 <n>", "End X in 0–1000", (v) => Number(v)).option("--y2 <n>", "End Y in 0–1000", (v) => Number(v)).option("--duration <ms>", "Gesture duration ms (long-press for tap)", (v) => Number(v)).option("--double", "Double-tap (tap only)").option("--text <text>", "Text to type").option("--app-id <id>", "Bundle id / application id").option("--url <url>", "URL to open").option("--seconds <n>", "Background seconds", (v) => Number(v)).option("--screenshot", "Wait for the screen to settle, then return the result screenshot (and a copy marking where the tap or swipe landed)").option("--settle <ms>", "With --screenshot: longest wait for the screen to settle (default 1500)", (v) => Number(v));
|
|
9326
|
+
}
|
|
9327
|
+
function printResultScreenshot(shot) {
|
|
9328
|
+
console.log(`screenshot ${shot.path}`);
|
|
9329
|
+
if (shot.annotatedPath)
|
|
9330
|
+
console.log(`marked ${shot.annotatedPath}`);
|
|
9331
|
+
console.log(`settled ${shot.settled} (${Math.round(shot.waitedMs)}ms)`);
|
|
9332
|
+
console.log(`changed ${shot.changed === null ? "unknown (screen still animating)" : shot.changed}`);
|
|
9248
9333
|
}
|
|
9249
9334
|
for (const kind of [
|
|
9250
9335
|
"tap",
|
|
@@ -9273,7 +9358,9 @@ for (const kind of [
|
|
|
9273
9358
|
description: options.description,
|
|
9274
9359
|
appId: options.appId,
|
|
9275
9360
|
url: options.url,
|
|
9276
|
-
seconds: options.seconds
|
|
9361
|
+
seconds: options.seconds,
|
|
9362
|
+
screenshot: options.screenshot === true ? true : undefined,
|
|
9363
|
+
settleMs: options.settle
|
|
9277
9364
|
});
|
|
9278
9365
|
if (options.json) {
|
|
9279
9366
|
console.log(JSON.stringify(body, null, 2));
|
|
@@ -9283,6 +9370,8 @@ for (const kind of [
|
|
|
9283
9370
|
if (body.resolved?.x != null && body.resolved?.y != null) {
|
|
9284
9371
|
console.log(`resolved ${body.resolved.x},${body.resolved.y}`);
|
|
9285
9372
|
}
|
|
9373
|
+
if (body.screenshot)
|
|
9374
|
+
printResultScreenshot(body.screenshot);
|
|
9286
9375
|
} catch (error) {
|
|
9287
9376
|
fail(`action ${kind}`, error);
|
|
9288
9377
|
}
|
|
@@ -9292,13 +9381,17 @@ addActionOptions(action.command("alert").description("Accept or dismiss a system
|
|
|
9292
9381
|
try {
|
|
9293
9382
|
const body = await client(String(options.baseUrl)).performAction({
|
|
9294
9383
|
kind: "alert",
|
|
9295
|
-
alertAction: options.dismiss ? "dismiss" : "accept"
|
|
9384
|
+
alertAction: options.dismiss ? "dismiss" : "accept",
|
|
9385
|
+
screenshot: options.screenshot === true ? true : undefined,
|
|
9386
|
+
settleMs: options.settle
|
|
9296
9387
|
});
|
|
9297
9388
|
if (options.json) {
|
|
9298
9389
|
console.log(JSON.stringify(body, null, 2));
|
|
9299
9390
|
return;
|
|
9300
9391
|
}
|
|
9301
9392
|
console.log(`ok ${body.kind}`);
|
|
9393
|
+
if (body.screenshot)
|
|
9394
|
+
printResultScreenshot(body.screenshot);
|
|
9302
9395
|
} catch (error) {
|
|
9303
9396
|
fail("action alert", error);
|
|
9304
9397
|
}
|
|
@@ -9588,13 +9681,14 @@ appsCmd.command("get").argument("<app>", "App prefix or id").option("--base-url
|
|
|
9588
9681
|
console.log(`prefix: ${app.prefix}`);
|
|
9589
9682
|
console.log(`name: ${app.name}`);
|
|
9590
9683
|
console.log(`app_context: ${app.context || "(empty)"}`);
|
|
9684
|
+
console.log(`app_knowledge: ${app.knowledge || "(empty)"}`);
|
|
9591
9685
|
console.log(`ios_bundle_id: ${app.iosBundleId || "(empty)"}`);
|
|
9592
9686
|
console.log(`android_application_id: ${app.androidApplicationId || "(empty)"}`);
|
|
9593
9687
|
} catch (error) {
|
|
9594
9688
|
fail("apps get", error);
|
|
9595
9689
|
}
|
|
9596
9690
|
});
|
|
9597
|
-
appsCmd.command("update").argument("<app>", "App prefix or id").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--name <name>", "Display name").option("--prefix <prefix>", "CLI prefix").option("--context <text>", "App context / shared rules").option("--ios-bundle-id <id>", "iOS bundle id").option("--android-application-id <id>", "Android application id").option("--json", "Print raw JSON").action(async (appArg, options) => {
|
|
9691
|
+
appsCmd.command("update").argument("<app>", "App prefix or id").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--name <name>", "Display name").option("--prefix <prefix>", "CLI prefix").option("--context <text>", "App context / shared rules").option("--knowledge <text>", "App knowledge notes injected into agent runs").option("--ios-bundle-id <id>", "iOS bundle id").option("--android-application-id <id>", "Android application id").option("--json", "Print raw JSON").action(async (appArg, options) => {
|
|
9598
9692
|
try {
|
|
9599
9693
|
const c = client(options.baseUrl);
|
|
9600
9694
|
const resolved = await resolveAppId(c, appArg);
|
|
@@ -9602,6 +9696,7 @@ appsCmd.command("update").argument("<app>", "App prefix or id").option("--base-u
|
|
|
9602
9696
|
name: options.name,
|
|
9603
9697
|
prefix: options.prefix,
|
|
9604
9698
|
context: options.context,
|
|
9699
|
+
knowledge: options.knowledge,
|
|
9605
9700
|
iosBundleId: options.iosBundleId,
|
|
9606
9701
|
androidApplicationId: options.androidApplicationId
|
|
9607
9702
|
});
|
|
@@ -9927,7 +10022,7 @@ runsCmd.command("delete").argument("<runId>", "Run id").option("--base-url <url>
|
|
|
9927
10022
|
fail("runs delete", error);
|
|
9928
10023
|
}
|
|
9929
10024
|
});
|
|
9930
|
-
runsCmd.command("create").argument("<app>", "App prefix or id").requiredOption("--cases <numbers>", "Comma-separated case numbers, e.g. 1,2,5").option("--device <id>", "Device id (defaults to active session)").option("--platform <platform>", "ios | android (defaults to active session)").option("--build-id <id>", "Registered build id to install before run").option("--build-path <path>", "Absolute build path to register + install").option("--mode <mode>", "auto | script | agent (default: auto)").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").option("--wait", "Wait until the run finishes (passed / errored / cancelled)").option("--timeout <seconds>", "Wait timeout in seconds (default: 1800)", String(DEFAULT_RUN_WAIT_TIMEOUT_SECONDS)).option("--github-output", "Write run_id and status to $GITHUB_OUTPUT").option("--no-github-output", "Do not write GitHub step outputs").action(async (appArg, options) => {
|
|
10025
|
+
runsCmd.command("create").argument("<app>", "App prefix or id").requiredOption("--cases <numbers>", "Comma-separated case numbers, e.g. 1,2,5").option("--device <id>", "Device id (defaults to active session)").option("--platform <platform>", "ios | android (defaults to active session)").option("--build-id <id>", "Registered build id to install before run").option("--build-path <path>", "Absolute build path to register + install").option("--mode <mode>", "auto | script | agent (default: auto)").option("--screen-mode <mode>", "vision | tree — what the agent sees: screenshot only, or also the accessibility tree (default: vision)").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").option("--wait", "Wait until the run finishes (passed / errored / cancelled)").option("--timeout <seconds>", "Wait timeout in seconds (default: 1800)", String(DEFAULT_RUN_WAIT_TIMEOUT_SECONDS)).option("--github-output", "Write run_id and status to $GITHUB_OUTPUT").option("--no-github-output", "Do not write GitHub step outputs").action(async (appArg, options) => {
|
|
9931
10026
|
try {
|
|
9932
10027
|
const c = client(options.baseUrl);
|
|
9933
10028
|
const resolved = await resolveAppId(c, appArg);
|
|
@@ -9959,6 +10054,10 @@ runsCmd.command("create").argument("<app>", "App prefix or id").requiredOption("
|
|
|
9959
10054
|
if (options.mode && !executionMode) {
|
|
9960
10055
|
throw new Error("--mode must be auto, script, or agent");
|
|
9961
10056
|
}
|
|
10057
|
+
const screenMode = options.screenMode === "vision" || options.screenMode === "tree" ? options.screenMode : undefined;
|
|
10058
|
+
if (options.screenMode && !screenMode) {
|
|
10059
|
+
throw new Error("--screen-mode must be vision or tree");
|
|
10060
|
+
}
|
|
9962
10061
|
let run = await c.createRun({
|
|
9963
10062
|
appId: resolved.id,
|
|
9964
10063
|
caseIds,
|
|
@@ -9966,7 +10065,8 @@ runsCmd.command("create").argument("<app>", "App prefix or id").requiredOption("
|
|
|
9966
10065
|
platform,
|
|
9967
10066
|
buildId: options.buildId,
|
|
9968
10067
|
buildPath: options.buildPath,
|
|
9969
|
-
executionMode
|
|
10068
|
+
executionMode,
|
|
10069
|
+
screenMode
|
|
9970
10070
|
});
|
|
9971
10071
|
if (options.wait) {
|
|
9972
10072
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yoqa/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.28",
|
|
4
4
|
"description": "Yoqa CLI — drive local mobile QA from the terminal or CI (talks to the Yoqa runner over HTTP)",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"url": "git+https://github.com/Aris-ngoy/qa-agent.git",
|
|
19
19
|
"directory": "packages/cli"
|
|
20
20
|
},
|
|
21
|
-
"homepage": "https://yoqa.
|
|
21
|
+
"homepage": "https://yoqa.arisn.dev/docs/cli",
|
|
22
22
|
"bugs": {
|
|
23
23
|
"url": "https://github.com/Aris-ngoy/qa-agent/issues"
|
|
24
24
|
},
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"health": "bun run src/main.ts health"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@yoqa/runner": "0.3.
|
|
41
|
+
"@yoqa/runner": "0.3.28"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^22.15.30",
|