@yoqa/cli 0.3.8 → 0.3.10
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/main.js +307 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -6184,6 +6184,75 @@ var ensureRuntimeResponseSchema = exports_external.object({
|
|
|
6184
6184
|
installed: exports_external.array(setupPlatformResponseSchema),
|
|
6185
6185
|
message: exports_external.string().min(1)
|
|
6186
6186
|
});
|
|
6187
|
+
var serverKindSchema = exports_external.union([
|
|
6188
|
+
exports_external.literal("appium"),
|
|
6189
|
+
exports_external.literal("runner"),
|
|
6190
|
+
exports_external.literal("device-session")
|
|
6191
|
+
]);
|
|
6192
|
+
var serverOwnershipSchema = exports_external.union([
|
|
6193
|
+
exports_external.literal("managed"),
|
|
6194
|
+
exports_external.literal("foreign"),
|
|
6195
|
+
exports_external.literal("self")
|
|
6196
|
+
]);
|
|
6197
|
+
var serverActionSchema = exports_external.union([exports_external.literal("stop"), exports_external.literal("restart")]);
|
|
6198
|
+
var serverEntrySchema = exports_external.object({
|
|
6199
|
+
id: exports_external.string().min(1),
|
|
6200
|
+
kind: serverKindSchema,
|
|
6201
|
+
ownership: serverOwnershipSchema,
|
|
6202
|
+
label: exports_external.string().min(1),
|
|
6203
|
+
status: exports_external.string().min(1),
|
|
6204
|
+
pid: exports_external.number().int().positive().optional(),
|
|
6205
|
+
port: exports_external.number().int().positive().optional(),
|
|
6206
|
+
deviceId: exports_external.string().min(1).optional(),
|
|
6207
|
+
platform: devicePlatformSchema.optional(),
|
|
6208
|
+
startedAt: exports_external.number().nonnegative().optional(),
|
|
6209
|
+
actions: exports_external.array(serverActionSchema)
|
|
6210
|
+
});
|
|
6211
|
+
var listServersResponseSchema = exports_external.object({
|
|
6212
|
+
servers: exports_external.array(serverEntrySchema)
|
|
6213
|
+
});
|
|
6214
|
+
var serverMutationResponseSchema = exports_external.object({
|
|
6215
|
+
ok: exports_external.literal(true),
|
|
6216
|
+
message: exports_external.string().min(1),
|
|
6217
|
+
servers: exports_external.array(serverEntrySchema)
|
|
6218
|
+
});
|
|
6219
|
+
var doctorCheckStatusSchema = exports_external.union([
|
|
6220
|
+
exports_external.literal("pass"),
|
|
6221
|
+
exports_external.literal("fail"),
|
|
6222
|
+
exports_external.literal("warn")
|
|
6223
|
+
]);
|
|
6224
|
+
var doctorRepairIdSchema = exports_external.union([
|
|
6225
|
+
exports_external.literal("ensure-runtime"),
|
|
6226
|
+
exports_external.literal("stop-foreign-appium"),
|
|
6227
|
+
exports_external.literal("disconnect-session")
|
|
6228
|
+
]);
|
|
6229
|
+
var doctorCheckSchema = exports_external.object({
|
|
6230
|
+
id: exports_external.string().min(1),
|
|
6231
|
+
label: exports_external.string().min(1),
|
|
6232
|
+
status: doctorCheckStatusSchema,
|
|
6233
|
+
detail: exports_external.string().optional(),
|
|
6234
|
+
fixHint: exports_external.string().optional()
|
|
6235
|
+
});
|
|
6236
|
+
var doctorStepSchema = exports_external.object({
|
|
6237
|
+
severity: exports_external.union([exports_external.literal("error"), exports_external.literal("warn"), exports_external.literal("info")]),
|
|
6238
|
+
title: exports_external.string().min(1),
|
|
6239
|
+
detail: exports_external.string().min(1),
|
|
6240
|
+
repair: doctorRepairIdSchema.optional()
|
|
6241
|
+
});
|
|
6242
|
+
var doctorReportSchema = exports_external.object({
|
|
6243
|
+
ok: exports_external.boolean(),
|
|
6244
|
+
checks: exports_external.array(doctorCheckSchema),
|
|
6245
|
+
servers: exports_external.array(serverEntrySchema),
|
|
6246
|
+
steps: exports_external.array(doctorStepSchema)
|
|
6247
|
+
});
|
|
6248
|
+
var doctorRepairRequestSchema = exports_external.object({
|
|
6249
|
+
repairs: exports_external.array(doctorRepairIdSchema).min(1)
|
|
6250
|
+
});
|
|
6251
|
+
var doctorRepairResponseSchema = exports_external.object({
|
|
6252
|
+
ok: exports_external.literal(true),
|
|
6253
|
+
message: exports_external.string().min(1),
|
|
6254
|
+
report: doctorReportSchema
|
|
6255
|
+
});
|
|
6187
6256
|
var capabilitySchema = exports_external.object({
|
|
6188
6257
|
id: exports_external.string().min(1),
|
|
6189
6258
|
key: exports_external.string(),
|
|
@@ -6384,6 +6453,22 @@ var aiProviderSchema = exports_external.object({
|
|
|
6384
6453
|
var listProvidersResponseSchema = exports_external.object({
|
|
6385
6454
|
providers: exports_external.array(aiProviderSchema)
|
|
6386
6455
|
});
|
|
6456
|
+
var providerDriverCapabilitiesSchema = exports_external.object({
|
|
6457
|
+
vision: exports_external.boolean()
|
|
6458
|
+
});
|
|
6459
|
+
var providerDriverCatalogEntrySchema = exports_external.object({
|
|
6460
|
+
kind: providerKindSchema,
|
|
6461
|
+
label: exports_external.string().min(1),
|
|
6462
|
+
description: exports_external.string().nullable(),
|
|
6463
|
+
authModes: exports_external.array(providerAuthModeSchema).min(1),
|
|
6464
|
+
defaultBinary: exports_external.string().nullable(),
|
|
6465
|
+
envHints: exports_external.array(exports_external.string()),
|
|
6466
|
+
loginInstructions: exports_external.string().nullable(),
|
|
6467
|
+
capabilities: providerDriverCapabilitiesSchema
|
|
6468
|
+
});
|
|
6469
|
+
var listProviderCatalogResponseSchema = exports_external.object({
|
|
6470
|
+
drivers: exports_external.array(providerDriverCatalogEntrySchema)
|
|
6471
|
+
});
|
|
6387
6472
|
var createProviderRequestSchema = exports_external.object({
|
|
6388
6473
|
kind: providerKindSchema,
|
|
6389
6474
|
authMode: providerAuthModeSchema.optional(),
|
|
@@ -7396,6 +7481,73 @@ class RunnerClient {
|
|
|
7396
7481
|
}
|
|
7397
7482
|
return ensureRuntimeResponseSchema.parse(json);
|
|
7398
7483
|
}
|
|
7484
|
+
async listServers(options = {}) {
|
|
7485
|
+
const response = await this.fetchImpl(`${this.baseUrl}/servers`, {
|
|
7486
|
+
signal: options.signal
|
|
7487
|
+
});
|
|
7488
|
+
const json = await response.json().catch(() => null);
|
|
7489
|
+
if (!response.ok) {
|
|
7490
|
+
throw new Error(errorMessageFromBody(json, `List servers failed: HTTP ${response.status}`));
|
|
7491
|
+
}
|
|
7492
|
+
return listServersResponseSchema.parse(json);
|
|
7493
|
+
}
|
|
7494
|
+
async stopAllServers(options = {}) {
|
|
7495
|
+
const response = await this.fetchImpl(`${this.baseUrl}/servers/stop-all`, {
|
|
7496
|
+
method: "POST",
|
|
7497
|
+
signal: options.signal
|
|
7498
|
+
});
|
|
7499
|
+
const json = await response.json().catch(() => null);
|
|
7500
|
+
if (!response.ok) {
|
|
7501
|
+
throw new Error(errorMessageFromBody(json, `Stop all servers failed: HTTP ${response.status}`));
|
|
7502
|
+
}
|
|
7503
|
+
return serverMutationResponseSchema.parse(json);
|
|
7504
|
+
}
|
|
7505
|
+
async stopServer(id, options = {}) {
|
|
7506
|
+
const response = await this.fetchImpl(`${this.baseUrl}/servers/${encodeURIComponent(id)}/stop`, {
|
|
7507
|
+
method: "POST",
|
|
7508
|
+
signal: options.signal
|
|
7509
|
+
});
|
|
7510
|
+
const json = await response.json().catch(() => null);
|
|
7511
|
+
if (!response.ok) {
|
|
7512
|
+
throw new Error(errorMessageFromBody(json, `Stop server failed: HTTP ${response.status}`));
|
|
7513
|
+
}
|
|
7514
|
+
return serverMutationResponseSchema.parse(json);
|
|
7515
|
+
}
|
|
7516
|
+
async restartServer(id, options = {}) {
|
|
7517
|
+
const response = await this.fetchImpl(`${this.baseUrl}/servers/${encodeURIComponent(id)}/restart`, {
|
|
7518
|
+
method: "POST",
|
|
7519
|
+
signal: options.signal
|
|
7520
|
+
});
|
|
7521
|
+
const json = await response.json().catch(() => null);
|
|
7522
|
+
if (!response.ok) {
|
|
7523
|
+
throw new Error(errorMessageFromBody(json, `Restart server failed: HTTP ${response.status}`));
|
|
7524
|
+
}
|
|
7525
|
+
return serverMutationResponseSchema.parse(json);
|
|
7526
|
+
}
|
|
7527
|
+
async getDoctorReport(options = {}) {
|
|
7528
|
+
const response = await this.fetchImpl(`${this.baseUrl}/doctor`, {
|
|
7529
|
+
signal: options.signal
|
|
7530
|
+
});
|
|
7531
|
+
const json = await response.json().catch(() => null);
|
|
7532
|
+
if (!response.ok) {
|
|
7533
|
+
throw new Error(errorMessageFromBody(json, `Doctor failed: HTTP ${response.status}`));
|
|
7534
|
+
}
|
|
7535
|
+
return doctorReportSchema.parse(json);
|
|
7536
|
+
}
|
|
7537
|
+
async repairDoctor(request, options = {}) {
|
|
7538
|
+
const body = doctorRepairRequestSchema.parse(request);
|
|
7539
|
+
const response = await this.fetchImpl(`${this.baseUrl}/doctor/repair`, {
|
|
7540
|
+
method: "POST",
|
|
7541
|
+
headers: { "Content-Type": "application/json" },
|
|
7542
|
+
body: JSON.stringify(body),
|
|
7543
|
+
signal: options.signal
|
|
7544
|
+
});
|
|
7545
|
+
const json = await response.json().catch(() => null);
|
|
7546
|
+
if (!response.ok) {
|
|
7547
|
+
throw new Error(errorMessageFromBody(json, `Doctor repair failed: HTTP ${response.status}`));
|
|
7548
|
+
}
|
|
7549
|
+
return doctorRepairResponseSchema.parse(json);
|
|
7550
|
+
}
|
|
7399
7551
|
async listApps() {
|
|
7400
7552
|
const json = await this.requestJson("/apps", undefined, "List apps failed");
|
|
7401
7553
|
return listAppsResponseSchema.parse(json).apps;
|
|
@@ -7499,6 +7651,10 @@ class RunnerClient {
|
|
|
7499
7651
|
const json = await this.requestJson("/providers", undefined, "List providers failed");
|
|
7500
7652
|
return listProvidersResponseSchema.parse(json).providers;
|
|
7501
7653
|
}
|
|
7654
|
+
async listProviderCatalog() {
|
|
7655
|
+
const json = await this.requestJson("/providers/catalog", undefined, "List provider catalog failed");
|
|
7656
|
+
return listProviderCatalogResponseSchema.parse(json).drivers;
|
|
7657
|
+
}
|
|
7502
7658
|
async getProvider(providerId) {
|
|
7503
7659
|
const json = await this.requestJson(`/providers/${encodeURIComponent(providerId)}`, undefined, "Get provider failed");
|
|
7504
7660
|
return aiProviderSchema.parse(json);
|
|
@@ -7694,7 +7850,7 @@ var {
|
|
|
7694
7850
|
// package.json
|
|
7695
7851
|
var package_default = {
|
|
7696
7852
|
name: "@yoqa/cli",
|
|
7697
|
-
version: "0.3.
|
|
7853
|
+
version: "0.3.10",
|
|
7698
7854
|
description: "Yoqa CLI — drive local mobile QA from the terminal or CI (talks to the Yoqa runner over HTTP)",
|
|
7699
7855
|
license: "UNLICENSED",
|
|
7700
7856
|
type: "module",
|
|
@@ -8036,6 +8192,156 @@ runtime.command("ensure").description("Install Appium + both platform drivers if
|
|
|
8036
8192
|
fail("runtime ensure", error);
|
|
8037
8193
|
}
|
|
8038
8194
|
});
|
|
8195
|
+
var servers = program2.command("servers").description("List or control local Appium, runner, and device sessions").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").action(async (options) => {
|
|
8196
|
+
try {
|
|
8197
|
+
const body = await client(options.baseUrl).listServers();
|
|
8198
|
+
if (options.json) {
|
|
8199
|
+
console.log(JSON.stringify(body, null, 2));
|
|
8200
|
+
return;
|
|
8201
|
+
}
|
|
8202
|
+
if (body.servers.length === 0) {
|
|
8203
|
+
console.log("No servers running");
|
|
8204
|
+
return;
|
|
8205
|
+
}
|
|
8206
|
+
for (const entry of body.servers) {
|
|
8207
|
+
const meta = [
|
|
8208
|
+
entry.kind,
|
|
8209
|
+
entry.ownership,
|
|
8210
|
+
entry.status,
|
|
8211
|
+
entry.port ? `:${entry.port}` : null,
|
|
8212
|
+
entry.pid ? `pid ${entry.pid}` : null,
|
|
8213
|
+
entry.actions.length > 0 ? `actions=${entry.actions.join(",")}` : "actions=none"
|
|
8214
|
+
].filter(Boolean).join(" · ");
|
|
8215
|
+
console.log(`${entry.id} ${entry.label} ${meta}`);
|
|
8216
|
+
}
|
|
8217
|
+
} catch (error) {
|
|
8218
|
+
fail("servers", error);
|
|
8219
|
+
}
|
|
8220
|
+
});
|
|
8221
|
+
servers.command("list").description("List running servers").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").action(async (options) => {
|
|
8222
|
+
try {
|
|
8223
|
+
const body = await client(options.baseUrl).listServers();
|
|
8224
|
+
if (options.json) {
|
|
8225
|
+
console.log(JSON.stringify(body, null, 2));
|
|
8226
|
+
return;
|
|
8227
|
+
}
|
|
8228
|
+
if (body.servers.length === 0) {
|
|
8229
|
+
console.log("No servers running");
|
|
8230
|
+
return;
|
|
8231
|
+
}
|
|
8232
|
+
for (const entry of body.servers) {
|
|
8233
|
+
const meta = [
|
|
8234
|
+
entry.kind,
|
|
8235
|
+
entry.ownership,
|
|
8236
|
+
entry.status,
|
|
8237
|
+
entry.port ? `:${entry.port}` : null,
|
|
8238
|
+
entry.pid ? `pid ${entry.pid}` : null,
|
|
8239
|
+
entry.actions.length > 0 ? `actions=${entry.actions.join(",")}` : "actions=none"
|
|
8240
|
+
].filter(Boolean).join(" · ");
|
|
8241
|
+
console.log(`${entry.id} ${entry.label} ${meta}`);
|
|
8242
|
+
}
|
|
8243
|
+
} catch (error) {
|
|
8244
|
+
fail("servers list", error);
|
|
8245
|
+
}
|
|
8246
|
+
});
|
|
8247
|
+
servers.command("stop-all").description("Stop Appium processes and disconnect the device session (does not stop the runner)").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").action(async (options) => {
|
|
8248
|
+
try {
|
|
8249
|
+
const body = await client(options.baseUrl).stopAllServers();
|
|
8250
|
+
if (options.json) {
|
|
8251
|
+
console.log(JSON.stringify(body, null, 2));
|
|
8252
|
+
return;
|
|
8253
|
+
}
|
|
8254
|
+
console.log(body.message);
|
|
8255
|
+
} catch (error) {
|
|
8256
|
+
fail("servers stop-all", error);
|
|
8257
|
+
}
|
|
8258
|
+
});
|
|
8259
|
+
servers.command("stop").description("Stop one server by id").argument("<id>", "Server id from yoqa servers list").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").action(async (id, options) => {
|
|
8260
|
+
try {
|
|
8261
|
+
if (id === "runner-self") {
|
|
8262
|
+
throw new Error("Stopping the runner over HTTP is not supported. Quit the desktop app or kill the process on the runner port.");
|
|
8263
|
+
}
|
|
8264
|
+
const body = await client(options.baseUrl).stopServer(id);
|
|
8265
|
+
if (options.json) {
|
|
8266
|
+
console.log(JSON.stringify(body, null, 2));
|
|
8267
|
+
return;
|
|
8268
|
+
}
|
|
8269
|
+
console.log(body.message);
|
|
8270
|
+
} catch (error) {
|
|
8271
|
+
fail("servers stop", error);
|
|
8272
|
+
}
|
|
8273
|
+
});
|
|
8274
|
+
servers.command("restart").description("Restart one server by id").argument("<id>", "Server id from yoqa servers list").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").action(async (id, options) => {
|
|
8275
|
+
try {
|
|
8276
|
+
if (id === "runner-self") {
|
|
8277
|
+
throw new Error("Restarting the runner over HTTP is not supported while it is serving requests. Prefer the desktop Servers panel.");
|
|
8278
|
+
}
|
|
8279
|
+
const body = await client(options.baseUrl).restartServer(id);
|
|
8280
|
+
if (options.json) {
|
|
8281
|
+
console.log(JSON.stringify(body, null, 2));
|
|
8282
|
+
return;
|
|
8283
|
+
}
|
|
8284
|
+
console.log(body.message);
|
|
8285
|
+
} catch (error) {
|
|
8286
|
+
fail("servers restart", error);
|
|
8287
|
+
}
|
|
8288
|
+
});
|
|
8289
|
+
program2.command("doctor").description("Diagnose local tooling, drivers, and leftover Appium processes").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").option("--fix", "Apply safe repairs (ensure runtime, stop foreign Appium, disconnect session)").action(async (options) => {
|
|
8290
|
+
try {
|
|
8291
|
+
const c = client(options.baseUrl);
|
|
8292
|
+
if (options.fix) {
|
|
8293
|
+
const report2 = await c.getDoctorReport();
|
|
8294
|
+
const repairs = [
|
|
8295
|
+
...new Set(report2.steps.map((step) => step.repair).filter((id) => Boolean(id)))
|
|
8296
|
+
];
|
|
8297
|
+
if (repairs.length === 0) {
|
|
8298
|
+
if (options.json) {
|
|
8299
|
+
console.log(JSON.stringify({ ok: true, message: "No safe repairs", report: report2 }, null, 2));
|
|
8300
|
+
} else {
|
|
8301
|
+
console.log("No safe repairs to apply");
|
|
8302
|
+
}
|
|
8303
|
+
if (!report2.ok)
|
|
8304
|
+
process.exitCode = 1;
|
|
8305
|
+
return;
|
|
8306
|
+
}
|
|
8307
|
+
const result = await c.repairDoctor({ repairs });
|
|
8308
|
+
if (options.json) {
|
|
8309
|
+
console.log(JSON.stringify(result, null, 2));
|
|
8310
|
+
} else {
|
|
8311
|
+
console.log(result.message);
|
|
8312
|
+
console.log(result.report.ok ? "doctor: ok" : "doctor: issues remain");
|
|
8313
|
+
for (const check of result.report.checks) {
|
|
8314
|
+
console.log(` [${check.status}] ${check.label}${check.detail ? ` — ${check.detail}` : ""}`);
|
|
8315
|
+
}
|
|
8316
|
+
for (const step of result.report.steps) {
|
|
8317
|
+
console.log(` → [${step.severity}] ${step.title}: ${step.detail}`);
|
|
8318
|
+
}
|
|
8319
|
+
}
|
|
8320
|
+
if (!result.report.ok)
|
|
8321
|
+
process.exitCode = 1;
|
|
8322
|
+
return;
|
|
8323
|
+
}
|
|
8324
|
+
const report = await c.getDoctorReport();
|
|
8325
|
+
if (options.json) {
|
|
8326
|
+
console.log(JSON.stringify(report, null, 2));
|
|
8327
|
+
} else {
|
|
8328
|
+
console.log(report.ok ? "doctor: ok" : "doctor: issues found");
|
|
8329
|
+
for (const check of report.checks) {
|
|
8330
|
+
console.log(` [${check.status}] ${check.label}${check.detail ? ` — ${check.detail}` : ""}`);
|
|
8331
|
+
}
|
|
8332
|
+
if (report.steps.length > 0) {
|
|
8333
|
+
console.log("steps:");
|
|
8334
|
+
for (const step of report.steps) {
|
|
8335
|
+
console.log(` → [${step.severity}] ${step.title}: ${step.detail}`);
|
|
8336
|
+
}
|
|
8337
|
+
}
|
|
8338
|
+
}
|
|
8339
|
+
if (!report.ok)
|
|
8340
|
+
process.exitCode = 1;
|
|
8341
|
+
} catch (error) {
|
|
8342
|
+
fail("doctor", error);
|
|
8343
|
+
}
|
|
8344
|
+
});
|
|
8039
8345
|
var assertCmd = program2.command("assert").description("Assert text visibility on the active device");
|
|
8040
8346
|
for (const kind of ["visible", "not-visible"]) {
|
|
8041
8347
|
assertCmd.command(kind).description(kind === "visible" ? "Fail unless matching text appears in the cleaned screen tree" : "Fail if matching text is still present in the cleaned screen tree").option("--base-url <url>", "Runner base URL", runnerBaseUrl()).option("--json", "Print raw JSON").requiredOption("-t, --text <text>", "Text / label substring to match").option("--timeout <seconds>", "Seconds to wait before failing", (v) => Number(v), 5).action(async (options) => {
|