@qawolf/cli 1.1.0 → 1.2.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 +1 -1
- package/dist/cli.js +337 -64
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Try it without installing:
|
|
|
23
23
|
npx @qawolf/cli --help
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
Supported Node versions:
|
|
26
|
+
Supported Node versions: Node 20.19+. Node 20 reached [end-of-life](https://endoflife.date/nodejs) on 2026-04-30 and no longer receives security updates; it remains supported here only for environments still pinned to Node 20. Prefer Node 22+ where possible.
|
|
27
27
|
|
|
28
28
|
### Standalone binaries
|
|
29
29
|
|
package/dist/cli.js
CHANGED
|
@@ -8514,7 +8514,7 @@ var require_BufferList = __commonJS((exports, module) => {
|
|
|
8514
8514
|
this.head = this.tail = null;
|
|
8515
8515
|
this.length = 0;
|
|
8516
8516
|
};
|
|
8517
|
-
BufferList.prototype.join = function
|
|
8517
|
+
BufferList.prototype.join = function join32(s3) {
|
|
8518
8518
|
if (this.length === 0)
|
|
8519
8519
|
return "";
|
|
8520
8520
|
var p3 = this.head;
|
|
@@ -23070,7 +23070,7 @@ var require_BufferList2 = __commonJS((exports, module) => {
|
|
|
23070
23070
|
this.head = this.tail = null;
|
|
23071
23071
|
this.length = 0;
|
|
23072
23072
|
};
|
|
23073
|
-
BufferList.prototype.join = function
|
|
23073
|
+
BufferList.prototype.join = function join32(s3) {
|
|
23074
23074
|
if (this.length === 0)
|
|
23075
23075
|
return "";
|
|
23076
23076
|
var p3 = this.head;
|
|
@@ -155130,6 +155130,15 @@ function errorCode(err) {
|
|
|
155130
155130
|
function isNoEntError(err) {
|
|
155131
155131
|
return errorCode(err) === "ENOENT";
|
|
155132
155132
|
}
|
|
155133
|
+
var missingPackagePattern = /Cannot find (?:package|module) '([^']+)'/;
|
|
155134
|
+
var pathLikeSpecifierPattern = /^(?:\.|\/|[A-Za-z]:[\\/])/;
|
|
155135
|
+
function extractMissingPackage(text) {
|
|
155136
|
+
const specifier = missingPackagePattern.exec(text)?.[1];
|
|
155137
|
+
if (specifier === undefined || pathLikeSpecifierPattern.test(specifier)) {
|
|
155138
|
+
return;
|
|
155139
|
+
}
|
|
155140
|
+
return specifier;
|
|
155141
|
+
}
|
|
155133
155142
|
|
|
155134
155143
|
// src/core/messages/auth.ts
|
|
155135
155144
|
var authMessages = {
|
|
@@ -155391,7 +155400,10 @@ var runnerMessages = {
|
|
|
155391
155400
|
retrying: (attempt, maxAttempts) => `Retrying (${attempt} of ${maxAttempts})...`,
|
|
155392
155401
|
screenshot: (path) => `Screenshot: ${path}`,
|
|
155393
155402
|
managedRuntimeNote: (dir) => `Using managed runtime — override with --deps <dir> or QAWOLF_RUNTIME_DIR:
|
|
155394
|
-
${dir}
|
|
155403
|
+
${dir}`,
|
|
155404
|
+
installingProjectDeps: (count) => `Installing ${pluralize(count, "project dependency", "project dependencies")}…`,
|
|
155405
|
+
outerHopCandidateRejected: (dir, missing) => `outer-hop candidate rejected: ${dir} missing ${missing.join(", ")}`,
|
|
155406
|
+
moduleNotFoundHint: (pkg, projectDir) => projectDir === undefined ? `Hint: '${pkg}' could not be resolved. Run from within your flows project so its dependencies can be found.` : `Hint: '${pkg}' could not be resolved. Ensure it is declared in ${projectDir}/package.json "dependencies" and run npm install in that project.`
|
|
155395
155407
|
};
|
|
155396
155408
|
// node_modules/env-paths/index.js
|
|
155397
155409
|
import path from "node:path";
|
|
@@ -173618,7 +173630,7 @@ function registerAuthCommand(program2, signals) {
|
|
|
173618
173630
|
// package.json
|
|
173619
173631
|
var package_default = {
|
|
173620
173632
|
name: "@qawolf/cli",
|
|
173621
|
-
version: "1.
|
|
173633
|
+
version: "1.2.0",
|
|
173622
173634
|
description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
173623
173635
|
keywords: [
|
|
173624
173636
|
"automation",
|
|
@@ -173676,6 +173688,7 @@ var package_default = {
|
|
|
173676
173688
|
dependencies: {
|
|
173677
173689
|
"@clack/prompts": "1.5.1",
|
|
173678
173690
|
"@napi-rs/keyring": "1.3.0",
|
|
173691
|
+
"@oxc-node/core": "0.1.0",
|
|
173679
173692
|
"@playwright/test": "1.60.0",
|
|
173680
173693
|
"@qawolf/api-contracts": "0.1.0",
|
|
173681
173694
|
"@qawolf/emails": "1.1.1",
|
|
@@ -173709,7 +173722,7 @@ var package_default = {
|
|
|
173709
173722
|
typescript: "6.0.3"
|
|
173710
173723
|
},
|
|
173711
173724
|
engines: {
|
|
173712
|
-
node: ">=
|
|
173725
|
+
node: ">=20.19.0"
|
|
173713
173726
|
},
|
|
173714
173727
|
packageManager: "bun@1.3.13"
|
|
173715
173728
|
};
|
|
@@ -174035,15 +174048,15 @@ async function checkFileAssets(deps) {
|
|
|
174035
174048
|
|
|
174036
174049
|
// src/domains/doctor/checks/nodeVersion.ts
|
|
174037
174050
|
async function checkNodeVersion(deps) {
|
|
174038
|
-
const
|
|
174039
|
-
if (
|
|
174051
|
+
const min = parseVersion(deps.enginesNode, /^>=\s*(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
|
|
174052
|
+
if (min === undefined) {
|
|
174040
174053
|
return {
|
|
174041
174054
|
name: "node-version",
|
|
174042
174055
|
status: "fail",
|
|
174043
174056
|
detail: doctorMessages.nodeVersion.couldNotParseEngines(deps.enginesNode)
|
|
174044
174057
|
};
|
|
174045
174058
|
}
|
|
174046
|
-
const actual =
|
|
174059
|
+
const actual = parseVersion(deps.processVersion, /^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
|
|
174047
174060
|
if (actual === undefined) {
|
|
174048
174061
|
return {
|
|
174049
174062
|
name: "node-version",
|
|
@@ -174051,7 +174064,7 @@ async function checkNodeVersion(deps) {
|
|
|
174051
174064
|
detail: doctorMessages.nodeVersion.couldNotParseVersion(deps.processVersion)
|
|
174052
174065
|
};
|
|
174053
174066
|
}
|
|
174054
|
-
if (actual <
|
|
174067
|
+
if (compareVersions(actual, min) < 0) {
|
|
174055
174068
|
return {
|
|
174056
174069
|
name: "node-version",
|
|
174057
174070
|
status: "fail",
|
|
@@ -174065,9 +174078,18 @@ async function checkNodeVersion(deps) {
|
|
|
174065
174078
|
version: deps.processVersion.replace(/^v/, "")
|
|
174066
174079
|
};
|
|
174067
174080
|
}
|
|
174068
|
-
function
|
|
174069
|
-
const
|
|
174070
|
-
|
|
174081
|
+
function parseVersion(input, pattern) {
|
|
174082
|
+
const match = input.trim().match(pattern);
|
|
174083
|
+
if (match?.[1] === undefined)
|
|
174084
|
+
return;
|
|
174085
|
+
return [
|
|
174086
|
+
Number.parseInt(match[1], 10),
|
|
174087
|
+
match[2] === undefined ? 0 : Number.parseInt(match[2], 10),
|
|
174088
|
+
match[3] === undefined ? 0 : Number.parseInt(match[3], 10)
|
|
174089
|
+
];
|
|
174090
|
+
}
|
|
174091
|
+
function compareVersions(a2, b2) {
|
|
174092
|
+
return a2[0] - b2[0] || a2[1] - b2[1] || a2[2] - b2[2];
|
|
174071
174093
|
}
|
|
174072
174094
|
|
|
174073
174095
|
// src/domains/doctor/checks/npmRegistry.ts
|
|
@@ -180085,28 +180107,35 @@ var executorPackageNames = new Set(pinnedPackages.map((p3) => p3.name));
|
|
|
180085
180107
|
async function populateOuterHop(args) {
|
|
180086
180108
|
const { projectDir, runDir, fs: fs3 } = args;
|
|
180087
180109
|
if (projectDir === undefined)
|
|
180088
|
-
return;
|
|
180089
|
-
const nearestNm = await findNearestNodeModulesDir(projectDir);
|
|
180090
|
-
if (nearestNm !== undefined) {
|
|
180091
|
-
await createDirSymlink(nearestNm, join27(runDir, "node_modules"));
|
|
180092
|
-
return;
|
|
180093
|
-
}
|
|
180110
|
+
return { mode: "none" };
|
|
180094
180111
|
const installableDeps = await readInstallableDeps(projectDir, fs3);
|
|
180095
|
-
|
|
180096
|
-
|
|
180097
|
-
|
|
180098
|
-
|
|
180099
|
-
|
|
180112
|
+
const depNames = Object.keys(installableDeps);
|
|
180113
|
+
const { satisfying, rejected } = await findSatisfyingNodeModulesDir(projectDir, depNames, fs3);
|
|
180114
|
+
if (satisfying !== undefined) {
|
|
180115
|
+
await createDirSymlink(satisfying, join27(runDir, "node_modules"));
|
|
180116
|
+
return { mode: "symlink", nodeModulesDir: satisfying };
|
|
180117
|
+
}
|
|
180118
|
+
if (depNames.length === 0)
|
|
180119
|
+
return { mode: "none" };
|
|
180120
|
+
args.onInstallStart?.(depNames.length);
|
|
180121
|
+
await installOuterDeps(runDir, installableDeps, fs3, args.install ?? spawnNpmInstall);
|
|
180122
|
+
return { mode: "install", depCount: depNames.length, rejected };
|
|
180123
|
+
}
|
|
180124
|
+
async function findSatisfyingNodeModulesDir(startDir, depNames, fs3) {
|
|
180125
|
+
const rejected = [];
|
|
180100
180126
|
let dir = startDir;
|
|
180101
180127
|
while (true) {
|
|
180102
180128
|
const candidate = join27(dir, "node_modules");
|
|
180103
180129
|
const stats = await lstatSafe(candidate);
|
|
180104
180130
|
if (stats !== undefined && stats.isDirectory() && !stats.isSymbolicLink()) {
|
|
180105
|
-
|
|
180131
|
+
const missing = depNames.filter((name) => !fs3.existsSync(join27(candidate, name, "package.json")));
|
|
180132
|
+
if (missing.length === 0)
|
|
180133
|
+
return { satisfying: candidate, rejected };
|
|
180134
|
+
rejected.push({ dir: candidate, missing });
|
|
180106
180135
|
}
|
|
180107
180136
|
const parent = dirname8(dir);
|
|
180108
180137
|
if (parent === dir)
|
|
180109
|
-
return;
|
|
180138
|
+
return { satisfying: undefined, rejected };
|
|
180110
180139
|
dir = parent;
|
|
180111
180140
|
}
|
|
180112
180141
|
}
|
|
@@ -180124,7 +180153,12 @@ async function readInstallableDeps(projectDir, fs3) {
|
|
|
180124
180153
|
} catch {
|
|
180125
180154
|
return {};
|
|
180126
180155
|
}
|
|
180127
|
-
|
|
180156
|
+
let parsed;
|
|
180157
|
+
try {
|
|
180158
|
+
parsed = JSON.parse(content);
|
|
180159
|
+
} catch {
|
|
180160
|
+
return {};
|
|
180161
|
+
}
|
|
180128
180162
|
if (typeof parsed !== "object" || parsed === null)
|
|
180129
180163
|
return {};
|
|
180130
180164
|
const rawDeps = parsed["dependencies"];
|
|
@@ -180132,11 +180166,11 @@ async function readInstallableDeps(projectDir, fs3) {
|
|
|
180132
180166
|
return {};
|
|
180133
180167
|
return Object.fromEntries(Object.entries(rawDeps).filter(([name]) => !executorPackageNames.has(name)).filter((entry) => typeof entry[1] === "string"));
|
|
180134
180168
|
}
|
|
180135
|
-
async function installOuterDeps(runDir, deps, fs3) {
|
|
180169
|
+
async function installOuterDeps(runDir, deps, fs3, install) {
|
|
180136
180170
|
await fs3.writeFile(join27(runDir, "package.json"), JSON.stringify({ name: "qawolf-run", private: true, dependencies: deps }, undefined, 2));
|
|
180137
180171
|
await fs3.writeFile(join27(runDir, ".npmrc"), `@qawolf:registry=https://registry.npmjs.org/
|
|
180138
180172
|
`);
|
|
180139
|
-
const result = await
|
|
180173
|
+
const result = await install(runDir);
|
|
180140
180174
|
if (result.exitCode !== 0) {
|
|
180141
180175
|
throw new Error(`Failed to install project dependencies into ${runDir}: ${result.stderr.trim()}`);
|
|
180142
180176
|
}
|
|
@@ -180158,10 +180192,16 @@ async function prepareRunDir(args) {
|
|
|
180158
180192
|
if (projectDir !== undefined) {
|
|
180159
180193
|
await writeExecSubpathImports({ execDir, fs: fs3 });
|
|
180160
180194
|
}
|
|
180161
|
-
await populateOuterHop({
|
|
180195
|
+
const outerHop = await populateOuterHop({
|
|
180196
|
+
projectDir,
|
|
180197
|
+
runDir,
|
|
180198
|
+
fs: fs3,
|
|
180199
|
+
...args.onInstallStart !== undefined ? { onInstallStart: args.onInstallStart } : {}
|
|
180200
|
+
});
|
|
180162
180201
|
return {
|
|
180163
180202
|
files: stagedFiles,
|
|
180164
180203
|
runDir,
|
|
180204
|
+
outerHop,
|
|
180165
180205
|
cleanup: () => fs3.rm(runDir, { recursive: true, force: true })
|
|
180166
180206
|
};
|
|
180167
180207
|
}
|
|
@@ -180244,8 +180284,143 @@ function resolveDepsRoot(args) {
|
|
|
180244
180284
|
}, { fs: fs3 });
|
|
180245
180285
|
}
|
|
180246
180286
|
|
|
180247
|
-
// src/
|
|
180287
|
+
// src/domains/emails/configureEmails.ts
|
|
180288
|
+
async function loadSdkDeps2(cwd) {
|
|
180289
|
+
try {
|
|
180290
|
+
const emailsPath = resolveFromEnvDir(cwd, "@qawolf/emails");
|
|
180291
|
+
return await import(emailsPath);
|
|
180292
|
+
} catch (err) {
|
|
180293
|
+
throw new Error("Could not load @qawolf/emails. Install it in your project: `npm install @qawolf/emails` or `bun add @qawolf/emails`.", { cause: err });
|
|
180294
|
+
}
|
|
180295
|
+
}
|
|
180296
|
+
async function configureEmails(config2, cwd, deps) {
|
|
180297
|
+
const { createEmailsClient, configureEmailsClient } = deps ?? await loadSdkDeps2(cwd);
|
|
180298
|
+
const client = await createEmailsClient({
|
|
180299
|
+
...config2,
|
|
180300
|
+
pollForEmailsDefaultTimeoutMs: 60000,
|
|
180301
|
+
waitForMessagesDefaultDelayMs: 1000
|
|
180302
|
+
});
|
|
180303
|
+
configureEmailsClient(client);
|
|
180304
|
+
return client;
|
|
180305
|
+
}
|
|
180306
|
+
async function registerLazyEmailsClient(getInbox, cwd, deps) {
|
|
180307
|
+
const { configureEmailsClient } = deps ?? await loadSdkDeps2(cwd);
|
|
180308
|
+
configureEmailsClient({ getInbox });
|
|
180309
|
+
}
|
|
180310
|
+
|
|
180311
|
+
// src/commands/flows/envVarDeps.ts
|
|
180248
180312
|
import { join as join30 } from "node:path";
|
|
180313
|
+
function envFilePath(envDir) {
|
|
180314
|
+
return join30(envDir, ".env");
|
|
180315
|
+
}
|
|
180316
|
+
async function readEnv(envDir, fs3) {
|
|
180317
|
+
try {
|
|
180318
|
+
return parseDotenv(await fs3.readFile(envFilePath(envDir)));
|
|
180319
|
+
} catch (err) {
|
|
180320
|
+
if (isNoEntError(err))
|
|
180321
|
+
return {};
|
|
180322
|
+
throw err;
|
|
180323
|
+
}
|
|
180324
|
+
}
|
|
180325
|
+
async function writeEnv(envDir, fs3, vars) {
|
|
180326
|
+
const target = envFilePath(envDir);
|
|
180327
|
+
const tmp = `${target}.${process.pid}.tmp`;
|
|
180328
|
+
await fs3.writeFile(tmp, serializeDotenv(vars), { mode: 384 });
|
|
180329
|
+
await fs3.rename(tmp, target);
|
|
180330
|
+
}
|
|
180331
|
+
function makeEnvVarDeps(envDir, fs3) {
|
|
180332
|
+
return {
|
|
180333
|
+
setEnvironmentVariable: async (key, value) => {
|
|
180334
|
+
const vars = await readEnv(envDir, fs3);
|
|
180335
|
+
vars[key] = value;
|
|
180336
|
+
await writeEnv(envDir, fs3, vars);
|
|
180337
|
+
process.env[key] = value;
|
|
180338
|
+
},
|
|
180339
|
+
fetchLatestEnvironmentVariables: async () => {
|
|
180340
|
+
const vars = await readEnv(envDir, fs3);
|
|
180341
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
180342
|
+
process.env[key] = value;
|
|
180343
|
+
}
|
|
180344
|
+
}
|
|
180345
|
+
};
|
|
180346
|
+
}
|
|
180347
|
+
|
|
180348
|
+
// src/commands/flows/flowRuntimeDeps.ts
|
|
180349
|
+
async function maybeGetIdentityTeamId(platform) {
|
|
180350
|
+
const identity = await platform.getIdentity();
|
|
180351
|
+
return identity.ok ? identity.value.team.id : undefined;
|
|
180352
|
+
}
|
|
180353
|
+
function lazyGetInbox({
|
|
180354
|
+
envDir,
|
|
180355
|
+
ctx,
|
|
180356
|
+
platform,
|
|
180357
|
+
env: env2,
|
|
180358
|
+
resolveApiKeyFn,
|
|
180359
|
+
configureEmailsFn,
|
|
180360
|
+
createPlatform
|
|
180361
|
+
}) {
|
|
180362
|
+
let getInboxPromise;
|
|
180363
|
+
async function configure() {
|
|
180364
|
+
const explicitEmailerUrl = env2["EMAILER_URL"];
|
|
180365
|
+
let teamId = env2["CLOUD_AGENTS_INBOX_TEAM_ID"];
|
|
180366
|
+
const apiKeyResult = explicitEmailerUrl === undefined ? await resolveApiKeyFn(ctx.configDir, ctx.fs) : undefined;
|
|
180367
|
+
if (teamId === undefined && platform !== undefined) {
|
|
180368
|
+
teamId = await maybeGetIdentityTeamId(platform);
|
|
180369
|
+
}
|
|
180370
|
+
if (teamId === undefined && apiKeyResult !== undefined) {
|
|
180371
|
+
const identityPlatform = createPlatform(apiKeyResult.key, {
|
|
180372
|
+
baseUrl: ctx.apiBaseUrl,
|
|
180373
|
+
fetch: globalThis.fetch,
|
|
180374
|
+
...ctx.log ? { logger: ctx.log("trpc") } : {}
|
|
180375
|
+
});
|
|
180376
|
+
teamId = await maybeGetIdentityTeamId(identityPlatform);
|
|
180377
|
+
}
|
|
180378
|
+
const teamIdPart = teamId !== undefined ? { teamId } : {};
|
|
180379
|
+
if (explicitEmailerUrl !== undefined) {
|
|
180380
|
+
const client2 = await configureEmailsFn({ emailerUrl: explicitEmailerUrl, ...teamIdPart }, envDir);
|
|
180381
|
+
return client2.getInbox;
|
|
180382
|
+
}
|
|
180383
|
+
if (apiKeyResult === undefined) {
|
|
180384
|
+
throw new Error("getInbox requires EMAILER_URL, QAWOLF_API_KEY, or stored QA Wolf credentials. Run 'qawolf auth login'.");
|
|
180385
|
+
}
|
|
180386
|
+
const client = await configureEmailsFn({ apiKey: apiKeyResult.key, url: `${ctx.apiBaseUrl}/api`, ...teamIdPart }, envDir);
|
|
180387
|
+
return client.getInbox;
|
|
180388
|
+
}
|
|
180389
|
+
return async (...args) => {
|
|
180390
|
+
getInboxPromise ??= configure();
|
|
180391
|
+
const getInbox = await getInboxPromise;
|
|
180392
|
+
return getInbox(...args);
|
|
180393
|
+
};
|
|
180394
|
+
}
|
|
180395
|
+
async function createFlowRuntimeDeps({
|
|
180396
|
+
envDir,
|
|
180397
|
+
ctx,
|
|
180398
|
+
platform,
|
|
180399
|
+
env: env2 = process.env,
|
|
180400
|
+
resolveApiKeyFn = resolveApiKey,
|
|
180401
|
+
configureEmailsFn = configureEmails,
|
|
180402
|
+
createPlatform = createPlatformClient
|
|
180403
|
+
}) {
|
|
180404
|
+
const getInbox = lazyGetInbox({
|
|
180405
|
+
envDir,
|
|
180406
|
+
ctx,
|
|
180407
|
+
platform,
|
|
180408
|
+
env: env2,
|
|
180409
|
+
resolveApiKeyFn,
|
|
180410
|
+
configureEmailsFn,
|
|
180411
|
+
createPlatform
|
|
180412
|
+
});
|
|
180413
|
+
try {
|
|
180414
|
+
await registerLazyEmailsClient(getInbox, envDir);
|
|
180415
|
+
} catch {}
|
|
180416
|
+
return {
|
|
180417
|
+
...makeEnvVarDeps(envDir, ctx.fs),
|
|
180418
|
+
getInbox
|
|
180419
|
+
};
|
|
180420
|
+
}
|
|
180421
|
+
|
|
180422
|
+
// src/shell/appium/createAppiumServer.ts
|
|
180423
|
+
import { join as join31 } from "node:path";
|
|
180249
180424
|
|
|
180250
180425
|
// src/shell/appium/spawnAppium.ts
|
|
180251
180426
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -180320,7 +180495,7 @@ async function createAppiumServer(envDir, signals, params) {
|
|
|
180320
180495
|
const spawnFn = params?.deps?.spawn ?? defaultSpawnAppium;
|
|
180321
180496
|
const findFreePortFn = params?.deps?.findFreePort ?? findFreePort;
|
|
180322
180497
|
const resolveAppiumBinFn = params?.deps?.resolveAppiumBin ?? resolveAppiumBin;
|
|
180323
|
-
const appiumHome2 = params?.options?.appiumHome ??
|
|
180498
|
+
const appiumHome2 = params?.options?.appiumHome ?? join31(envPaths("qawolf").data, "appium");
|
|
180324
180499
|
const timeoutMs3 = params?.options?.startTimeoutMs ?? defaultStartTimeoutMs;
|
|
180325
180500
|
const bin = resolveAppiumBinFn(envDir);
|
|
180326
180501
|
const port = await findFreePortFn();
|
|
@@ -180806,6 +180981,9 @@ function createAndroidLaunchContext({
|
|
|
180806
180981
|
import path11 from "node:path";
|
|
180807
180982
|
import { pathToFileURL } from "node:url";
|
|
180808
180983
|
|
|
180984
|
+
// src/shell/resolver/detectRuntimeCapabilities.ts
|
|
180985
|
+
import nodeModule2 from "node:module";
|
|
180986
|
+
|
|
180809
180987
|
// src/shell/resolver/registerFlowModuleResolver.ts
|
|
180810
180988
|
import nodeModule from "node:module";
|
|
180811
180989
|
|
|
@@ -180872,6 +181050,50 @@ function registerFlowModuleResolver() {
|
|
|
180872
181050
|
registerHooks({ resolve: flowResolveHook });
|
|
180873
181051
|
}
|
|
180874
181052
|
|
|
181053
|
+
// src/shell/resolver/detectRuntimeCapabilities.ts
|
|
181054
|
+
function detectRuntimeCapabilities() {
|
|
181055
|
+
return {
|
|
181056
|
+
isBun: globalThis.Bun !== undefined,
|
|
181057
|
+
hasSyncHooks: resolveRegisterHooks(nodeModule2) !== undefined,
|
|
181058
|
+
hasNativeTypeScript: Boolean(process.features.typescript),
|
|
181059
|
+
hasAsyncRegister: typeof nodeModule2.register === "function"
|
|
181060
|
+
};
|
|
181061
|
+
}
|
|
181062
|
+
|
|
181063
|
+
// src/shell/resolver/selectFlowLoaderStrategy.ts
|
|
181064
|
+
function selectFlowLoaderStrategy(caps) {
|
|
181065
|
+
if (caps.isBun)
|
|
181066
|
+
return "none";
|
|
181067
|
+
if (caps.hasNativeTypeScript) {
|
|
181068
|
+
return caps.hasSyncHooks ? "sync-alias" : "none";
|
|
181069
|
+
}
|
|
181070
|
+
return caps.hasAsyncRegister ? "oxc-transpile" : "unsupported";
|
|
181071
|
+
}
|
|
181072
|
+
|
|
181073
|
+
// src/shell/resolver/registerFlowLoader.ts
|
|
181074
|
+
async function defaultRegisterOxcLoader() {
|
|
181075
|
+
try {
|
|
181076
|
+
await import("@oxc-node/core/register");
|
|
181077
|
+
} catch (cause) {
|
|
181078
|
+
throw new Error(`Failed to load the @oxc-node/core TypeScript loader needed to run flows on Node ${process.version}. Ensure @oxc-node/core is installed for this platform (${process.platform}-${process.arch}).`, { cause });
|
|
181079
|
+
}
|
|
181080
|
+
}
|
|
181081
|
+
async function registerFlowLoader(deps = {}) {
|
|
181082
|
+
const {
|
|
181083
|
+
capabilities = detectRuntimeCapabilities(),
|
|
181084
|
+
registerSyncAlias = registerFlowModuleResolver,
|
|
181085
|
+
registerOxcLoader = defaultRegisterOxcLoader
|
|
181086
|
+
} = deps;
|
|
181087
|
+
const strategy = selectFlowLoaderStrategy(capabilities);
|
|
181088
|
+
if (strategy === "sync-alias") {
|
|
181089
|
+
registerSyncAlias();
|
|
181090
|
+
} else if (strategy === "oxc-transpile") {
|
|
181091
|
+
await registerOxcLoader();
|
|
181092
|
+
} else if (strategy === "unsupported") {
|
|
181093
|
+
throw new Error(`Running TypeScript flows requires Node 20.6+ (for module.register) or a runtime with native TypeScript support. Current runtime: ${process.version}. Upgrade Node to 20.6 or newer.`);
|
|
181094
|
+
}
|
|
181095
|
+
}
|
|
181096
|
+
|
|
180875
181097
|
// src/domains/runner/executorPlugin.ts
|
|
180876
181098
|
import path10 from "node:path";
|
|
180877
181099
|
var executorImportDetect = /from ['"]@qawolf\/(?:flows|testkit|emails)/;
|
|
@@ -180971,7 +181193,7 @@ async function loadFlowDefault(args) {
|
|
|
180971
181193
|
depsRoot = ""
|
|
180972
181194
|
} = args;
|
|
180973
181195
|
if (bundleFlow === undefined) {
|
|
180974
|
-
|
|
181196
|
+
await registerFlowLoader();
|
|
180975
181197
|
return importDefaultExport(pathToFileURL(flowPath).href, flowPath);
|
|
180976
181198
|
}
|
|
180977
181199
|
const code = await bundleFlow(flowPath, depsRoot);
|
|
@@ -181180,6 +181402,7 @@ async function runAndroidFlow({
|
|
|
181180
181402
|
callback: async (flowDeps) => {
|
|
181181
181403
|
const androidDeps = {
|
|
181182
181404
|
...Object.fromEntries(unsupportedAndroidDepNames.map((name) => [name, notSupported(name)])),
|
|
181405
|
+
...deps.flowRuntimeDeps,
|
|
181183
181406
|
inputs: flowDeps.flowInputs,
|
|
181184
181407
|
workflowInputs: flowDeps.flowInputs,
|
|
181185
181408
|
setOutput: flowDeps.setOutput,
|
|
@@ -181390,6 +181613,7 @@ async function runWebFlow({
|
|
|
181390
181613
|
callback: async (flowDeps) => {
|
|
181391
181614
|
const webDeps = {
|
|
181392
181615
|
...Object.fromEntries(unsupportedWebDepNames.map((name) => [name, notSupported(name)])),
|
|
181616
|
+
...deps.flowRuntimeDeps,
|
|
181393
181617
|
launch,
|
|
181394
181618
|
launchWithGpu: launch,
|
|
181395
181619
|
isGpuAvailable: () => false,
|
|
@@ -181423,14 +181647,14 @@ async function runWebFlow({
|
|
|
181423
181647
|
|
|
181424
181648
|
// src/shell/embeddedWorkerCli.ts
|
|
181425
181649
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
181426
|
-
import { basename as basename6, join as
|
|
181650
|
+
import { basename as basename6, join as join32 } from "node:path";
|
|
181427
181651
|
var embeddedCliPathEnv = "QAWOLF_EMBEDDED_CLI_PATH";
|
|
181428
181652
|
function extractEmbeddedWorkerCli() {
|
|
181429
181653
|
const assetPath = process.env[embeddedCliPathEnv];
|
|
181430
181654
|
if (assetPath === undefined || assetPath === "")
|
|
181431
181655
|
return;
|
|
181432
|
-
const dir =
|
|
181433
|
-
const dest =
|
|
181656
|
+
const dir = join32(getDataDir(), "worker");
|
|
181657
|
+
const dest = join32(dir, basename6(assetPath));
|
|
181434
181658
|
if (existsSync3(dest))
|
|
181435
181659
|
return dest;
|
|
181436
181660
|
mkdirSync2(dir, { recursive: true });
|
|
@@ -181675,6 +181899,12 @@ function createConsoleReporter(deps) {
|
|
|
181675
181899
|
deps.stderr.write(`${formatted}
|
|
181676
181900
|
|
|
181677
181901
|
`);
|
|
181902
|
+
const missingPackage = extractMissingPackage(errStr);
|
|
181903
|
+
if (missingPackage !== undefined) {
|
|
181904
|
+
deps.stderr.write(`${styleText3("yellow", `${indent}${runnerMessages.moduleNotFoundHint(missingPackage, deps.projectDir)}`)}
|
|
181905
|
+
|
|
181906
|
+
`);
|
|
181907
|
+
}
|
|
181678
181908
|
const counts = tests.total > 0 ? `${tests.passed}/${tests.total} tests ` : "";
|
|
181679
181909
|
deps.stdout.write(` ${styleText3("red", "✗")} ${counts}passed ${styleText3("dim", fmtDuration(durationMs))}
|
|
181680
181910
|
`);
|
|
@@ -181727,7 +181957,7 @@ function createCompositeReporter(reporters) {
|
|
|
181727
181957
|
};
|
|
181728
181958
|
}
|
|
181729
181959
|
// src/shell/reporter/createJUnitReporter.ts
|
|
181730
|
-
import { join as
|
|
181960
|
+
import { join as join33 } from "node:path";
|
|
181731
181961
|
|
|
181732
181962
|
// src/shell/reporter/junitXml.ts
|
|
181733
181963
|
function escapeXml(str) {
|
|
@@ -181766,7 +181996,7 @@ ${suites}`;
|
|
|
181766
181996
|
|
|
181767
181997
|
// src/shell/reporter/createJUnitReporter.ts
|
|
181768
181998
|
function resolveJUnitOutputPath(junit, outputDir) {
|
|
181769
|
-
return typeof junit === "string" && junit.trim() !== "" ? junit :
|
|
181999
|
+
return typeof junit === "string" && junit.trim() !== "" ? junit : join33(outputDir, "junit-report.xml");
|
|
181770
182000
|
}
|
|
181771
182001
|
function createJUnitReporter(deps) {
|
|
181772
182002
|
const flows = [];
|
|
@@ -181795,7 +182025,11 @@ function createJUnitReporter(deps) {
|
|
|
181795
182025
|
function buildRunReporter(flags, deps) {
|
|
181796
182026
|
const stdout2 = deps.stdout ?? process.stdout;
|
|
181797
182027
|
const stderr = deps.stderr ?? process.stderr;
|
|
181798
|
-
const console2 = createConsoleReporter({
|
|
182028
|
+
const console2 = createConsoleReporter({
|
|
182029
|
+
stdout: stdout2,
|
|
182030
|
+
stderr,
|
|
182031
|
+
...deps.projectDir !== undefined ? { projectDir: deps.projectDir } : {}
|
|
182032
|
+
});
|
|
181799
182033
|
if (flags.junit === undefined)
|
|
181800
182034
|
return console2;
|
|
181801
182035
|
const junit = createJUnitReporter({
|
|
@@ -181811,7 +182045,15 @@ function buildRunReporter(flags, deps) {
|
|
|
181811
182045
|
|
|
181812
182046
|
// src/commands/flows/buildFlowsRunDeps.ts
|
|
181813
182047
|
function buildFlowsRunDeps(args) {
|
|
181814
|
-
const {
|
|
182048
|
+
const {
|
|
182049
|
+
ctx,
|
|
182050
|
+
resolvedDir,
|
|
182051
|
+
android,
|
|
182052
|
+
runWebFlowDeps,
|
|
182053
|
+
flowRuntimeDeps,
|
|
182054
|
+
flags,
|
|
182055
|
+
projectDir
|
|
182056
|
+
} = args;
|
|
181815
182057
|
return {
|
|
181816
182058
|
peekFlowMeta: makePeekFlowMeta(ctx.fs),
|
|
181817
182059
|
installBrowsers: (innerCtx, browsers) => installBrowserList(innerCtx, browsers, {
|
|
@@ -181820,9 +182062,9 @@ function buildFlowsRunDeps(args) {
|
|
|
181820
182062
|
playwrightCliPath: resolvePlaywrightCli(resolvedDir, process.platform)
|
|
181821
182063
|
}),
|
|
181822
182064
|
runWebFlow,
|
|
181823
|
-
runWebFlowDeps,
|
|
182065
|
+
runWebFlowDeps: { ...runWebFlowDeps, flowRuntimeDeps },
|
|
181824
182066
|
runAndroidFlow,
|
|
181825
|
-
runAndroidFlowDeps: android.deps,
|
|
182067
|
+
runAndroidFlowDeps: { ...android.deps, flowRuntimeDeps },
|
|
181826
182068
|
bootAndroid: android.boot,
|
|
181827
182069
|
shutdownAndroid: android.shutdown,
|
|
181828
182070
|
createPooledDispatch: makePooledDispatch(resolvedDir),
|
|
@@ -181832,7 +182074,8 @@ function buildFlowsRunDeps(args) {
|
|
|
181832
182074
|
reporter: buildRunReporter(flags, {
|
|
181833
182075
|
fs: ctx.fs,
|
|
181834
182076
|
stdout: { write: (text3) => ctx.ui.write(text3) },
|
|
181835
|
-
stderr: { write: (text3) => ctx.ui.write(text3) }
|
|
182077
|
+
stderr: { write: (text3) => ctx.ui.write(text3) },
|
|
182078
|
+
...projectDir !== undefined ? { projectDir } : {}
|
|
181836
182079
|
}),
|
|
181837
182080
|
now: () => Date.now()
|
|
181838
182081
|
};
|
|
@@ -181840,11 +182083,11 @@ function buildFlowsRunDeps(args) {
|
|
|
181840
182083
|
|
|
181841
182084
|
// src/commands/flows/loadEnvFile.ts
|
|
181842
182085
|
import { readFile } from "node:fs/promises";
|
|
181843
|
-
import { join as
|
|
182086
|
+
import { join as join34 } from "node:path";
|
|
181844
182087
|
async function loadEnvFile(envDir) {
|
|
181845
182088
|
let content;
|
|
181846
182089
|
try {
|
|
181847
|
-
content = await readFile(
|
|
182090
|
+
content = await readFile(join34(envDir, ".env"), "utf8");
|
|
181848
182091
|
} catch (err) {
|
|
181849
182092
|
if (isNoEntError(err))
|
|
181850
182093
|
return;
|
|
@@ -181880,15 +182123,34 @@ async function runStagedFlows(args) {
|
|
|
181880
182123
|
files,
|
|
181881
182124
|
projectDir,
|
|
181882
182125
|
depsRoot: runtimeEnv.depsRoot,
|
|
181883
|
-
runRoot: runStagingRoot()
|
|
182126
|
+
runRoot: runStagingRoot(),
|
|
182127
|
+
onInstallStart: (depCount) => ctx.ui.info(runnerMessages.installingProjectDeps(depCount))
|
|
181884
182128
|
});
|
|
182129
|
+
if (staged.outerHop.mode === "install") {
|
|
182130
|
+
const log31 = ctx.log("runner");
|
|
182131
|
+
for (const candidate of staged.outerHop.rejected) {
|
|
182132
|
+
log31.debug(runnerMessages.outerHopCandidateRejected(candidate.dir, candidate.missing));
|
|
182133
|
+
}
|
|
182134
|
+
}
|
|
181885
182135
|
const unregisterCleanup = ctx.signals.register(staged.cleanup);
|
|
181886
182136
|
try {
|
|
181887
182137
|
const resolvedDir = runtimeEnv.depsRoot;
|
|
181888
182138
|
await deps.configureTestkit(resolvedDir);
|
|
181889
182139
|
const android = createAndroidDeps(resolvedDir, ctx.signals);
|
|
181890
182140
|
const runWebFlowDeps = await deps.runWebFlowDeps(resolvedDir, ctx.signals);
|
|
181891
|
-
|
|
182141
|
+
const flowRuntimeDeps = await deps.createFlowRuntimeDeps({
|
|
182142
|
+
envDir: resolvedDir,
|
|
182143
|
+
ctx
|
|
182144
|
+
});
|
|
182145
|
+
return await deps.flowsRun(ctx, staged.files, flags, buildFlowsRunDeps({
|
|
182146
|
+
ctx,
|
|
182147
|
+
resolvedDir,
|
|
182148
|
+
android,
|
|
182149
|
+
runWebFlowDeps,
|
|
182150
|
+
flowRuntimeDeps,
|
|
182151
|
+
flags,
|
|
182152
|
+
projectDir
|
|
182153
|
+
}));
|
|
181892
182154
|
} finally {
|
|
181893
182155
|
unregisterCleanup();
|
|
181894
182156
|
await staged.cleanup();
|
|
@@ -181903,6 +182165,7 @@ function makeDefaultDeps2(fs9) {
|
|
|
181903
182165
|
prepareRunDir: (args) => prepareRunDir({ ...args, fs: fs9 }),
|
|
181904
182166
|
configureTestkit,
|
|
181905
182167
|
runWebFlowDeps: defaultRunWebFlowDeps,
|
|
182168
|
+
createFlowRuntimeDeps,
|
|
181906
182169
|
flowsRun
|
|
181907
182170
|
};
|
|
181908
182171
|
}
|
|
@@ -181924,7 +182187,7 @@ async function handleFlowsRun(ctx, pattern, flags, deps) {
|
|
|
181924
182187
|
}
|
|
181925
182188
|
|
|
181926
182189
|
// src/commands/flows/hybridRunDefaults.ts
|
|
181927
|
-
import { join as
|
|
182190
|
+
import { join as join35, resolve as resolve9 } from "node:path";
|
|
181928
182191
|
function makeDefaultHybridDeps(fs9) {
|
|
181929
182192
|
return {
|
|
181930
182193
|
expandPatterns: (patterns, cwd, logger) => expandPatterns(patterns, cwd, logger, fs9),
|
|
@@ -181933,7 +182196,8 @@ function makeDefaultHybridDeps(fs9) {
|
|
|
181933
182196
|
prepareRunDir: (args) => prepareRunDir({ ...args, fs: fs9 }),
|
|
181934
182197
|
configureTestkit,
|
|
181935
182198
|
flowsRun,
|
|
181936
|
-
runWebFlowDeps: defaultRunWebFlowDeps
|
|
182199
|
+
runWebFlowDeps: defaultRunWebFlowDeps,
|
|
182200
|
+
createFlowRuntimeDeps
|
|
181937
182201
|
};
|
|
181938
182202
|
}
|
|
181939
182203
|
async function handleHybridFlowsRun(ctx, pattern, flags, deps) {
|
|
@@ -181942,7 +182206,7 @@ async function handleHybridFlowsRun(ctx, pattern, flags, deps) {
|
|
|
181942
182206
|
if (validation !== "ok") {
|
|
181943
182207
|
return { error: validation.error, exitCode: 2 };
|
|
181944
182208
|
}
|
|
181945
|
-
const envDir = resolve9(
|
|
182209
|
+
const envDir = resolve9(join35(".qawolf", flags.env));
|
|
181946
182210
|
const patternArgs = buildPatternArgs(pattern);
|
|
181947
182211
|
const globFlows = () => resolvedDeps.expandPatterns(patternArgs, envDir, ctx.log("flows"));
|
|
181948
182212
|
let files = await globFlows();
|
|
@@ -182015,7 +182279,16 @@ async function runWorker(signals) {
|
|
|
182015
182279
|
if (input.flow.kind !== "web")
|
|
182016
182280
|
throw new Error("worker subprocess currently supports web flows only");
|
|
182017
182281
|
await configureTestkit(input.resolvedDir);
|
|
182018
|
-
const
|
|
182282
|
+
const fs9 = makeDefaultFs();
|
|
182283
|
+
const apiBaseUrl = process.env["QAWOLF_API_URL"]?.replace(/\/+$/, "") || "https://app.qawolf.com";
|
|
182284
|
+
const flowRuntimeDeps = await createFlowRuntimeDeps({
|
|
182285
|
+
envDir: input.resolvedDir,
|
|
182286
|
+
ctx: { apiBaseUrl, configDir: getConfigDir(), fs: fs9 }
|
|
182287
|
+
});
|
|
182288
|
+
const runWebFlowDeps = {
|
|
182289
|
+
...await defaultRunWebFlowDeps(input.resolvedDir, signals),
|
|
182290
|
+
flowRuntimeDeps
|
|
182291
|
+
};
|
|
182019
182292
|
const reporter = {};
|
|
182020
182293
|
const deps = {
|
|
182021
182294
|
peekFlowMeta: unavailable("peekFlowMeta"),
|
|
@@ -182073,7 +182346,7 @@ function registerFlowsCommand(program2, signals) {
|
|
|
182073
182346
|
}
|
|
182074
182347
|
|
|
182075
182348
|
// src/domains/init/init.ts
|
|
182076
|
-
import { dirname as dirname12, join as
|
|
182349
|
+
import { dirname as dirname12, join as join36, relative as relative7 } from "node:path";
|
|
182077
182350
|
|
|
182078
182351
|
// src/domains/init/templates.ts
|
|
182079
182352
|
var qawolfConfigTs = `export default {
|
|
@@ -182111,9 +182384,9 @@ function makeDefaultInitDeps() {
|
|
|
182111
182384
|
async function handleInit(ctx, opts, deps = makeDefaultInitDeps()) {
|
|
182112
182385
|
ctx.ui.gap();
|
|
182113
182386
|
ctx.ui.intro(initMessages.title);
|
|
182114
|
-
const configPath =
|
|
182115
|
-
const flowPath =
|
|
182116
|
-
const gitignorePath =
|
|
182387
|
+
const configPath = join36(deps.cwd, "qawolf.config.ts");
|
|
182388
|
+
const flowPath = join36(deps.cwd, "src", "flows", "example.flow.ts");
|
|
182389
|
+
const gitignorePath = join36(deps.cwd, ".qawolf", ".gitignore");
|
|
182117
182390
|
await writeWithPrompt(ctx, configPath, qawolfConfigTs, opts.yes, deps);
|
|
182118
182391
|
await writeWithPrompt(ctx, flowPath, exampleFlowTs, opts.yes, deps);
|
|
182119
182392
|
await writeWithPrompt(ctx, gitignorePath, qawolfGitignore, opts.yes, deps);
|
|
@@ -182137,7 +182410,7 @@ async function writeWithPrompt(ctx, filePath, content, yes, deps) {
|
|
|
182137
182410
|
ctx.ui.step(initMessages.createdFile(relPath));
|
|
182138
182411
|
}
|
|
182139
182412
|
async function ensurePackageJson(ctx, yes, deps) {
|
|
182140
|
-
const pkgPath =
|
|
182413
|
+
const pkgPath = join36(deps.cwd, "package.json");
|
|
182141
182414
|
if (!await deps.fs.pathExists(pkgPath)) {
|
|
182142
182415
|
const confirmed2 = await ctx.ui.confirm(initMessages.createPackageJsonPrompt, { yes });
|
|
182143
182416
|
if (!confirmed2.ok || !confirmed2.value) {
|
|
@@ -182196,19 +182469,19 @@ Examples:
|
|
|
182196
182469
|
}
|
|
182197
182470
|
|
|
182198
182471
|
// src/commands/install/android.ts
|
|
182199
|
-
import { join as
|
|
182472
|
+
import { join as join39 } from "node:path";
|
|
182200
182473
|
|
|
182201
182474
|
// src/domains/install/android/index.ts
|
|
182202
182475
|
import { parseExecutionTarget as parseExecutionTarget4 } from "@qawolf/flow-targets";
|
|
182203
182476
|
|
|
182204
182477
|
// src/domains/install/android/avd.ts
|
|
182205
|
-
import { join as
|
|
182478
|
+
import { join as join37 } from "node:path";
|
|
182206
182479
|
async function installAvds(ctx, specs, deps) {
|
|
182207
182480
|
const versionResult = await deps.spawn(deps.sdkManagerPath, ["--version"]);
|
|
182208
182481
|
if (versionResult.exitCode !== 0) {
|
|
182209
182482
|
throw new Error(installMessages.android.sdkmanagerNotFound(deps.sdkManagerPath));
|
|
182210
182483
|
}
|
|
182211
|
-
const licenseFile =
|
|
182484
|
+
const licenseFile = join37(deps.androidHome, "licenses", "android-sdk-license");
|
|
182212
182485
|
if (deps.checkExists(licenseFile)) {
|
|
182213
182486
|
ctx.ui.info(installMessages.android.licensesAlreadyAccepted);
|
|
182214
182487
|
} else {
|
|
@@ -182222,7 +182495,7 @@ async function installAvds(ctx, specs, deps) {
|
|
|
182222
182495
|
for (const spec of specs) {
|
|
182223
182496
|
if (installedImages.has(spec.systemImage))
|
|
182224
182497
|
continue;
|
|
182225
|
-
const systemImg =
|
|
182498
|
+
const systemImg = join37(deps.androidHome, ...spec.systemImage.split(";"), "system.img");
|
|
182226
182499
|
if (deps.checkExists(systemImg)) {
|
|
182227
182500
|
ctx.ui.info(installMessages.android.systemImageAlreadyInstalled(spec.systemImage));
|
|
182228
182501
|
installedImages.add(spec.systemImage);
|
|
@@ -182270,9 +182543,9 @@ async function installAvds(ctx, specs, deps) {
|
|
|
182270
182543
|
}
|
|
182271
182544
|
|
|
182272
182545
|
// src/domains/install/android/driver.ts
|
|
182273
|
-
import { join as
|
|
182546
|
+
import { join as join38 } from "node:path";
|
|
182274
182547
|
var appiumEnv = {
|
|
182275
|
-
APPIUM_HOME:
|
|
182548
|
+
APPIUM_HOME: join38(envPaths("qawolf").data, "appium")
|
|
182276
182549
|
};
|
|
182277
182550
|
async function installUiautomator2Driver(ctx, deps) {
|
|
182278
182551
|
const listResult = await deps.spawn(deps.appiumBinPath, ["driver", "list", "--installed"], { env: appiumEnv });
|
|
@@ -182359,8 +182632,8 @@ async function handleInstallAndroid(ctx, pattern, envDir) {
|
|
|
182359
182632
|
arch: process.arch,
|
|
182360
182633
|
androidHome: androidHome2,
|
|
182361
182634
|
checkExists: (path9) => fs9.existsSync(path9),
|
|
182362
|
-
sdkManagerPath:
|
|
182363
|
-
avdManagerPath:
|
|
182635
|
+
sdkManagerPath: join39(androidHome2, "cmdline-tools", "latest", "bin", "sdkmanager"),
|
|
182636
|
+
avdManagerPath: join39(androidHome2, "cmdline-tools", "latest", "bin", "avdmanager"),
|
|
182364
182637
|
expandPatterns: (patterns, cwd) => expandPatterns(patterns, cwd ?? process.cwd(), undefined, fs9),
|
|
182365
182638
|
peekFlowMeta: makePeekFlowMeta(fs9),
|
|
182366
182639
|
resolveDepsRoot: async (files) => envDir ?? (await resolveDepsRoot({ files, fs: fs9 })).depsRoot,
|
|
@@ -182773,4 +183046,4 @@ createProgram({ signals }).parseAsync().catch(() => {
|
|
|
182773
183046
|
process.exitCode = 1;
|
|
182774
183047
|
}).finally(() => flushAndExit(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
182775
183048
|
|
|
182776
|
-
//# debugId=
|
|
183049
|
+
//# debugId=2C8E0221ECEF946764756E2164756E21
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qawolf/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"@clack/prompts": "1.5.1",
|
|
60
60
|
"@napi-rs/keyring": "1.3.0",
|
|
61
|
+
"@oxc-node/core": "0.1.0",
|
|
61
62
|
"@playwright/test": "1.60.0",
|
|
62
63
|
"@qawolf/api-contracts": "0.1.0",
|
|
63
64
|
"@qawolf/emails": "1.1.1",
|
|
@@ -91,7 +92,7 @@
|
|
|
91
92
|
"typescript": "6.0.3"
|
|
92
93
|
},
|
|
93
94
|
"engines": {
|
|
94
|
-
"node": ">=
|
|
95
|
+
"node": ">=20.19.0"
|
|
95
96
|
},
|
|
96
97
|
"packageManager": "bun@1.3.13"
|
|
97
98
|
}
|