@qawolf/cli 1.19.2 → 1.20.1
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/cli.js +985 -324
- package/package.json +1 -1
- package/skills/qawolf-cli/SKILL.md +5 -2
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 join38(s3) {
|
|
8518
8518
|
if (this.length === 0)
|
|
8519
8519
|
return "";
|
|
8520
8520
|
var p3 = this.head;
|
|
@@ -20220,8 +20220,8 @@ var require_readdir_glob = __commonJS((exports, module) => {
|
|
|
20220
20220
|
useStat = true;
|
|
20221
20221
|
}
|
|
20222
20222
|
const filename = dir + "/" + name;
|
|
20223
|
-
const
|
|
20224
|
-
const absolute = path3 + "/" +
|
|
20223
|
+
const relative8 = filename.slice(1);
|
|
20224
|
+
const absolute = path3 + "/" + relative8;
|
|
20225
20225
|
let stats = null;
|
|
20226
20226
|
if (useStat || followSymlinks) {
|
|
20227
20227
|
stats = await stat2(absolute, followSymlinks);
|
|
@@ -20233,12 +20233,12 @@ var require_readdir_glob = __commonJS((exports, module) => {
|
|
|
20233
20233
|
stats = { isDirectory: () => false };
|
|
20234
20234
|
}
|
|
20235
20235
|
if (stats.isDirectory()) {
|
|
20236
|
-
if (!shouldSkip(
|
|
20237
|
-
yield { relative:
|
|
20236
|
+
if (!shouldSkip(relative8)) {
|
|
20237
|
+
yield { relative: relative8, absolute, stats };
|
|
20238
20238
|
yield* exploreWalkAsync(filename, path3, followSymlinks, useStat, shouldSkip, false);
|
|
20239
20239
|
}
|
|
20240
20240
|
} else {
|
|
20241
|
-
yield { relative:
|
|
20241
|
+
yield { relative: relative8, absolute, stats };
|
|
20242
20242
|
}
|
|
20243
20243
|
}
|
|
20244
20244
|
}
|
|
@@ -20303,11 +20303,11 @@ var require_readdir_glob = __commonJS((exports, module) => {
|
|
|
20303
20303
|
}
|
|
20304
20304
|
setTimeout(() => this._next(), 0);
|
|
20305
20305
|
}
|
|
20306
|
-
_shouldSkipDirectory(
|
|
20307
|
-
return this.skipMatchers.some((m4) => m4.match(
|
|
20306
|
+
_shouldSkipDirectory(relative8) {
|
|
20307
|
+
return this.skipMatchers.some((m4) => m4.match(relative8));
|
|
20308
20308
|
}
|
|
20309
|
-
_fileMatches(
|
|
20310
|
-
const file2 =
|
|
20309
|
+
_fileMatches(relative8, isDirectory) {
|
|
20310
|
+
const file2 = relative8 + (isDirectory ? "/" : "");
|
|
20311
20311
|
return (this.matchers.length === 0 || this.matchers.some((m4) => m4.match(file2))) && !this.ignoreMatchers.some((m4) => m4.match(file2)) && (!this.options.nodir || !isDirectory);
|
|
20312
20312
|
}
|
|
20313
20313
|
_next() {
|
|
@@ -20316,16 +20316,16 @@ var require_readdir_glob = __commonJS((exports, module) => {
|
|
|
20316
20316
|
if (!obj.done) {
|
|
20317
20317
|
const isDirectory = obj.value.stats.isDirectory();
|
|
20318
20318
|
if (this._fileMatches(obj.value.relative, isDirectory)) {
|
|
20319
|
-
let
|
|
20319
|
+
let relative8 = obj.value.relative;
|
|
20320
20320
|
let absolute = obj.value.absolute;
|
|
20321
20321
|
if (this.options.mark && isDirectory) {
|
|
20322
|
-
|
|
20322
|
+
relative8 += "/";
|
|
20323
20323
|
absolute += "/";
|
|
20324
20324
|
}
|
|
20325
20325
|
if (this.options.stat) {
|
|
20326
|
-
this.emit("match", { relative:
|
|
20326
|
+
this.emit("match", { relative: relative8, absolute, stat: obj.value.stats });
|
|
20327
20327
|
} else {
|
|
20328
|
-
this.emit("match", { relative:
|
|
20328
|
+
this.emit("match", { relative: relative8, absolute });
|
|
20329
20329
|
}
|
|
20330
20330
|
}
|
|
20331
20331
|
this._next(this.iterator);
|
|
@@ -23182,7 +23182,7 @@ var require_BufferList2 = __commonJS((exports, module) => {
|
|
|
23182
23182
|
this.head = this.tail = null;
|
|
23183
23183
|
this.length = 0;
|
|
23184
23184
|
};
|
|
23185
|
-
BufferList.prototype.join = function
|
|
23185
|
+
BufferList.prototype.join = function join38(s3) {
|
|
23186
23186
|
if (this.length === 0)
|
|
23187
23187
|
return "";
|
|
23188
23188
|
var p3 = this.head;
|
|
@@ -36236,7 +36236,7 @@ var require_commonjs4 = __commonJS((exports) => {
|
|
|
36236
36236
|
var TYPEMASK = 1023;
|
|
36237
36237
|
var entToType = (s3) => s3.isFile() ? IFREG : s3.isDirectory() ? IFDIR : s3.isSymbolicLink() ? IFLNK : s3.isCharacterDevice() ? IFCHR : s3.isBlockDevice() ? IFBLK : s3.isSocket() ? IFSOCK : s3.isFIFO() ? IFIFO : UNKNOWN;
|
|
36238
36238
|
var normalizeCache = new Map;
|
|
36239
|
-
var
|
|
36239
|
+
var normalize4 = (s3) => {
|
|
36240
36240
|
const c3 = normalizeCache.get(s3);
|
|
36241
36241
|
if (c3)
|
|
36242
36242
|
return c3;
|
|
@@ -36249,7 +36249,7 @@ var require_commonjs4 = __commonJS((exports) => {
|
|
|
36249
36249
|
const c3 = normalizeNocaseCache.get(s3);
|
|
36250
36250
|
if (c3)
|
|
36251
36251
|
return c3;
|
|
36252
|
-
const n2 =
|
|
36252
|
+
const n2 = normalize4(s3.toLowerCase());
|
|
36253
36253
|
normalizeNocaseCache.set(s3, n2);
|
|
36254
36254
|
return n2;
|
|
36255
36255
|
};
|
|
@@ -36370,7 +36370,7 @@ var require_commonjs4 = __commonJS((exports) => {
|
|
|
36370
36370
|
}
|
|
36371
36371
|
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
|
|
36372
36372
|
this.name = name;
|
|
36373
|
-
this.#matchName = nocase ? normalizeNocase(name) :
|
|
36373
|
+
this.#matchName = nocase ? normalizeNocase(name) : normalize4(name);
|
|
36374
36374
|
this.#type = type & TYPEMASK;
|
|
36375
36375
|
this.nocase = nocase;
|
|
36376
36376
|
this.roots = roots;
|
|
@@ -36431,7 +36431,7 @@ var require_commonjs4 = __commonJS((exports) => {
|
|
|
36431
36431
|
return this.parent || this;
|
|
36432
36432
|
}
|
|
36433
36433
|
const children = this.children();
|
|
36434
|
-
const name = this.nocase ? normalizeNocase(pathPart) :
|
|
36434
|
+
const name = this.nocase ? normalizeNocase(pathPart) : normalize4(pathPart);
|
|
36435
36435
|
for (const p3 of children) {
|
|
36436
36436
|
if (p3.#matchName === name) {
|
|
36437
36437
|
return p3;
|
|
@@ -36568,7 +36568,7 @@ var require_commonjs4 = __commonJS((exports) => {
|
|
|
36568
36568
|
return !!(this.#type & ENOENT);
|
|
36569
36569
|
}
|
|
36570
36570
|
isNamed(n2) {
|
|
36571
|
-
return !this.nocase ? this.#matchName ===
|
|
36571
|
+
return !this.nocase ? this.#matchName === normalize4(n2) : this.#matchName === normalizeNocase(n2);
|
|
36572
36572
|
}
|
|
36573
36573
|
async readlink() {
|
|
36574
36574
|
const target = this.#linkTarget;
|
|
@@ -36695,7 +36695,7 @@ var require_commonjs4 = __commonJS((exports) => {
|
|
|
36695
36695
|
#readdirMaybePromoteChild(e, c3) {
|
|
36696
36696
|
for (let p3 = c3.provisional;p3 < c3.length; p3++) {
|
|
36697
36697
|
const pchild = c3[p3];
|
|
36698
|
-
const name = this.nocase ? normalizeNocase(e.name) :
|
|
36698
|
+
const name = this.nocase ? normalizeNocase(e.name) : normalize4(e.name);
|
|
36699
36699
|
if (name !== pchild.#matchName) {
|
|
36700
36700
|
continue;
|
|
36701
36701
|
}
|
|
@@ -37688,10 +37688,10 @@ var require_ignore = __commonJS((exports) => {
|
|
|
37688
37688
|
ignored(p3) {
|
|
37689
37689
|
const fullpath = p3.fullpath();
|
|
37690
37690
|
const fullpaths = `${fullpath}/`;
|
|
37691
|
-
const
|
|
37692
|
-
const relatives = `${
|
|
37691
|
+
const relative8 = p3.relative() || ".";
|
|
37692
|
+
const relatives = `${relative8}/`;
|
|
37693
37693
|
for (const m4 of this.relative) {
|
|
37694
|
-
if (m4.match(
|
|
37694
|
+
if (m4.match(relative8) || m4.match(relatives))
|
|
37695
37695
|
return true;
|
|
37696
37696
|
}
|
|
37697
37697
|
for (const m4 of this.absolute) {
|
|
@@ -37702,9 +37702,9 @@ var require_ignore = __commonJS((exports) => {
|
|
|
37702
37702
|
}
|
|
37703
37703
|
childrenIgnored(p3) {
|
|
37704
37704
|
const fullpath = p3.fullpath() + "/";
|
|
37705
|
-
const
|
|
37705
|
+
const relative8 = (p3.relative() || ".") + "/";
|
|
37706
37706
|
for (const m4 of this.relativeChildren) {
|
|
37707
|
-
if (m4.match(
|
|
37707
|
+
if (m4.match(relative8))
|
|
37708
37708
|
return true;
|
|
37709
37709
|
}
|
|
37710
37710
|
for (const m4 of this.absoluteChildren) {
|
|
@@ -101117,10 +101117,10 @@ function compareDocumentPosition(nodeA, nodeB) {
|
|
|
101117
101117
|
function uniqueSort(nodes) {
|
|
101118
101118
|
nodes = nodes.filter((node2, i2, arr) => !arr.includes(node2, i2 + 1));
|
|
101119
101119
|
nodes.sort((a3, b4) => {
|
|
101120
|
-
const
|
|
101121
|
-
if (
|
|
101120
|
+
const relative8 = compareDocumentPosition(a3, b4);
|
|
101121
|
+
if (relative8 & DocumentPosition.PRECEDING) {
|
|
101122
101122
|
return -1;
|
|
101123
|
-
} else if (
|
|
101123
|
+
} else if (relative8 & DocumentPosition.FOLLOWING) {
|
|
101124
101124
|
return 1;
|
|
101125
101125
|
}
|
|
101126
101126
|
return 0;
|
|
@@ -134710,7 +134710,7 @@ var require_snapshot_utils = __commonJS((exports, module) => {
|
|
|
134710
134710
|
// node_modules/undici/lib/mock/snapshot-recorder.js
|
|
134711
134711
|
var require_snapshot_recorder = __commonJS((exports, module) => {
|
|
134712
134712
|
var { writeFile, readFile, mkdir } = __require("node:fs/promises");
|
|
134713
|
-
var { dirname:
|
|
134713
|
+
var { dirname: dirname13, resolve: resolve10 } = __require("node:path");
|
|
134714
134714
|
var { setTimeout: setTimeout3, clearTimeout: clearTimeout2 } = __require("node:timers");
|
|
134715
134715
|
var { InvalidArgumentError: InvalidArgumentError3, UndiciError } = require_errors7();
|
|
134716
134716
|
var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
|
|
@@ -134905,7 +134905,7 @@ var require_snapshot_recorder = __commonJS((exports, module) => {
|
|
|
134905
134905
|
throw new InvalidArgumentError3("Snapshot path is required");
|
|
134906
134906
|
}
|
|
134907
134907
|
const resolvedPath = resolve10(path4);
|
|
134908
|
-
await mkdir(
|
|
134908
|
+
await mkdir(dirname13(resolvedPath), { recursive: true });
|
|
134909
134909
|
const data2 = Array.from(this.#snapshots.entries()).map(([hash2, snapshot]) => ({
|
|
134910
134910
|
hash: hash2,
|
|
134911
134911
|
snapshot
|
|
@@ -160719,11 +160719,11 @@ m2: ${this.mapper2.__debugToString().split(`
|
|
|
160719
160719
|
return height2 + 1;
|
|
160720
160720
|
}
|
|
160721
160721
|
function computeColumnWidths(height2) {
|
|
160722
|
-
const
|
|
160722
|
+
const columns = fill(Array(height2), 0);
|
|
160723
160723
|
for (const node2 of nodes) {
|
|
160724
|
-
|
|
160724
|
+
columns[node2.level] = Math.max(columns[node2.level], node2.text.length);
|
|
160725
160725
|
}
|
|
160726
|
-
return
|
|
160726
|
+
return columns;
|
|
160727
160727
|
}
|
|
160728
160728
|
function computeLanes(node2, lane) {
|
|
160729
160729
|
if (node2.lane === -1) {
|
|
@@ -165092,11 +165092,11 @@ ${lanes.join(`
|
|
|
165092
165092
|
return toComponents;
|
|
165093
165093
|
}
|
|
165094
165094
|
const components = toComponents.slice(start);
|
|
165095
|
-
const
|
|
165095
|
+
const relative10 = [];
|
|
165096
165096
|
for (;start < fromComponents.length; start++) {
|
|
165097
|
-
|
|
165097
|
+
relative10.push("..");
|
|
165098
165098
|
}
|
|
165099
|
-
return ["", ...
|
|
165099
|
+
return ["", ...relative10, ...components];
|
|
165100
165100
|
}
|
|
165101
165101
|
function getRelativePathFromDirectory(fromDirectory, to2, getCanonicalFileNameOrIgnoreCase) {
|
|
165102
165102
|
Debug.assert(getRootLength(fromDirectory) > 0 === getRootLength(to2) > 0, "Paths must either both be absolute or both be relative");
|
|
@@ -202471,9 +202471,9 @@ ${lanes.join(`
|
|
|
202471
202471
|
if (!startsWithDirectory(target, realPathDirectory, getCanonicalFileName)) {
|
|
202472
202472
|
return;
|
|
202473
202473
|
}
|
|
202474
|
-
const
|
|
202474
|
+
const relative10 = getRelativePathFromDirectory(realPathDirectory, target, getCanonicalFileName);
|
|
202475
202475
|
for (const symlinkDirectory of symlinkDirectories) {
|
|
202476
|
-
const option = resolvePath(symlinkDirectory,
|
|
202476
|
+
const option = resolvePath(symlinkDirectory, relative10);
|
|
202477
202477
|
const result2 = cb(option, target === referenceRedirect);
|
|
202478
202478
|
shouldFilterIgnoredPaths = true;
|
|
202479
202479
|
if (result2)
|
|
@@ -264788,10 +264788,10 @@ ${lanes.join(`
|
|
|
264788
264788
|
}
|
|
264789
264789
|
function getDefaultLibFilePriority(a3) {
|
|
264790
264790
|
if (containsPath(defaultLibraryPath, a3.fileName, false)) {
|
|
264791
|
-
const
|
|
264792
|
-
if (
|
|
264791
|
+
const basename8 = getBaseFileName(a3.fileName);
|
|
264792
|
+
if (basename8 === "lib.d.ts" || basename8 === "lib.es6.d.ts")
|
|
264793
264793
|
return 0;
|
|
264794
|
-
const name = removeSuffix(removePrefix(
|
|
264794
|
+
const name = removeSuffix(removePrefix(basename8, "lib."), ".d.ts");
|
|
264795
264795
|
const index2 = libs.indexOf(name);
|
|
264796
264796
|
if (index2 !== -1)
|
|
264797
264797
|
return index2 + 1;
|
|
@@ -317475,8 +317475,8 @@ ${options.prefix}` : `
|
|
|
317475
317475
|
}
|
|
317476
317476
|
};
|
|
317477
317477
|
for (const file2 of files) {
|
|
317478
|
-
const
|
|
317479
|
-
if (
|
|
317478
|
+
const basename8 = getBaseFileName(file2);
|
|
317479
|
+
if (basename8 === "package.json" || basename8 === "bower.json") {
|
|
317480
317480
|
createProjectWatcher(file2, "FileWatcher");
|
|
317481
317481
|
continue;
|
|
317482
317482
|
}
|
|
@@ -320363,8 +320363,8 @@ All files are: ${JSON.stringify(names)}`, "Err");
|
|
|
320363
320363
|
const fileOrDirectoryPath = removeIgnoredPath(this.toPath(fileOrDirectory));
|
|
320364
320364
|
if (!fileOrDirectoryPath)
|
|
320365
320365
|
return;
|
|
320366
|
-
const
|
|
320367
|
-
if (((_a6 = result.affectedModuleSpecifierCacheProjects) == null ? undefined : _a6.size) && (
|
|
320366
|
+
const basename8 = getBaseFileName(fileOrDirectoryPath);
|
|
320367
|
+
if (((_a6 = result.affectedModuleSpecifierCacheProjects) == null ? undefined : _a6.size) && (basename8 === "package.json" || basename8 === "node_modules")) {
|
|
320368
320368
|
result.affectedModuleSpecifierCacheProjects.forEach((project) => {
|
|
320369
320369
|
var _a22;
|
|
320370
320370
|
(_a22 = project.getModuleSpecifierCache()) == null || _a22.clear();
|
|
@@ -325953,6 +325953,7 @@ var environmentsMessages = {
|
|
|
325953
325953
|
resolvedAlias: (ref, id) => `Environment ${ref} resolved to ${id}.`,
|
|
325954
325954
|
couldNotResolve: (ref, detail) => `Could not resolve environment ${ref}: ${detail} If ${ref} is an alias, note that aliases require a team API key.`,
|
|
325955
325955
|
aborted: "Aborted; no environment selected.",
|
|
325956
|
+
usingPulledEnv: (env) => `Could not reach the platform to resolve environment ${env}; using the copy pulled into .qawolf/${env}.`,
|
|
325956
325957
|
tooManyPages: (pages) => `Stopped listing environments after ${pages} pages. Pass --env explicitly.`
|
|
325957
325958
|
};
|
|
325958
325959
|
// src/core/pluralize.ts
|
|
@@ -325967,7 +325968,23 @@ var flowsMessages = {
|
|
|
325967
325968
|
flowCount: (count) => pluralize(count, "flow"),
|
|
325968
325969
|
list: {
|
|
325969
325970
|
remoteRequiresEnv: "--remote requires an environment. Pass --env <env> or set QAWOLF_ENVIRONMENT.",
|
|
325970
|
-
|
|
325971
|
+
draftsRequireRemote: "--include-drafts requires --remote"
|
|
325972
|
+
},
|
|
325973
|
+
selectors: {
|
|
325974
|
+
tagsNotCached: "No cached tags found. Run 'qawolf flows pull --env <env>' to cache them, or pass --remote to read tags from the platform.",
|
|
325975
|
+
tagsUnavailable: (env) => `Could not reach the platform and no tags are cached for environment '${env}'. Run 'qawolf flows pull --env ${env}' while online.`,
|
|
325976
|
+
usingCachedTags: (fetchedAt) => `Could not reach the platform. Using tags cached at ${fetchedAt}; tag names were not validated.`,
|
|
325977
|
+
unknownTag: (name, suggestion) => suggestion === undefined ? `No tag named '${name}' on this team. Run 'qawolf tag list' to see available tags.` : `No tag named '${name}' on this team. Did you mean '${suggestion}'?`,
|
|
325978
|
+
unknownPulledEnv: (name, pulled, suggestion) => {
|
|
325979
|
+
const known = pulled.length === 0 ? "No environments have been pulled yet." : `Pulled environments: ${pulled.join(", ")}.`;
|
|
325980
|
+
const hint = suggestion === undefined ? "" : ` Did you mean '${suggestion}'?`;
|
|
325981
|
+
return `No pulled environment named '${name}'.${hint} ${known}`;
|
|
325982
|
+
},
|
|
325983
|
+
allEnvsWithEnv: "--all-envs has no effect with --env: the run is already scoped to that environment.",
|
|
325984
|
+
allEnvsWithoutTag: "--all-envs has no effect without --tag: a pattern run already includes every environment.",
|
|
325985
|
+
chooseEnv: "Which environment should these flows run against?",
|
|
325986
|
+
ambiguousEnvs: (labels) => `The selection matches flows in several pulled environments: ${labels.join(", ")}. Pass --env <name> to choose one, or --all-envs to run every match.`,
|
|
325987
|
+
noFlowsSelected: (selectors) => `No flows matched tags ${selectors.tags.join(", ")}.`
|
|
325971
325988
|
},
|
|
325972
325989
|
run: {
|
|
325973
325990
|
requiresEnv: "An environment is required. Pass --env <env> or set QAWOLF_ENVIRONMENT."
|
|
@@ -325976,6 +325993,7 @@ var flowsMessages = {
|
|
|
325976
325993
|
requiresEnv: "An environment is required. Pass --env <env> or set QAWOLF_ENVIRONMENT.",
|
|
325977
325994
|
downloadingBundle: "Downloading flows bundle",
|
|
325978
325995
|
fetchingEnvVars: "Fetching environment variables",
|
|
325996
|
+
fetchingTags: "Fetching flow tags",
|
|
325979
325997
|
downloadComplete: "Downloaded flows bundle and environment variables",
|
|
325980
325998
|
needsYesError: "Re-run with --yes to overwrite locally-modified files",
|
|
325981
325999
|
aborted: "Aborted; no changes.",
|
|
@@ -341138,10 +341156,12 @@ async function requestWithRetry(args) {
|
|
|
341138
341156
|
const retryable = result.error.kind === "network" || result.error.kind === "timeout";
|
|
341139
341157
|
if (backoff === undefined || !retryable) {
|
|
341140
341158
|
const mayHaveArrived = result.error.kind !== "http";
|
|
341159
|
+
const unreachable = result.error.kind === "network" || result.error.kind === "timeout";
|
|
341141
341160
|
return {
|
|
341142
341161
|
ok: false,
|
|
341143
341162
|
...args.describe(result.error),
|
|
341144
|
-
...mayHaveArrived ? { mayHaveArrived } : {}
|
|
341163
|
+
...mayHaveArrived ? { mayHaveArrived } : {},
|
|
341164
|
+
...unreachable ? { unreachable } : {}
|
|
341145
341165
|
};
|
|
341146
341166
|
}
|
|
341147
341167
|
await sleep2(backoff);
|
|
@@ -346136,7 +346156,7 @@ function startUpdateCheck(deps) {
|
|
|
346136
346156
|
// package.json
|
|
346137
346157
|
var package_default = {
|
|
346138
346158
|
name: "@qawolf/cli",
|
|
346139
|
-
version: "1.
|
|
346159
|
+
version: "1.20.1",
|
|
346140
346160
|
description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
346141
346161
|
keywords: [
|
|
346142
346162
|
"automation",
|
|
@@ -348625,9 +348645,280 @@ Examples:
|
|
|
348625
348645
|
});
|
|
348626
348646
|
}
|
|
348627
348647
|
|
|
348648
|
+
// src/domains/runner/runFlagParsers.ts
|
|
348649
|
+
function parseInteger(name, options = {}) {
|
|
348650
|
+
return (value) => {
|
|
348651
|
+
const n2 = Number.parseInt(value, 10);
|
|
348652
|
+
if (!Number.isFinite(n2) || String(n2) !== value) {
|
|
348653
|
+
throw new InvalidArgumentError(`${name} must be an integer`);
|
|
348654
|
+
}
|
|
348655
|
+
if (options.min !== undefined && n2 < options.min) {
|
|
348656
|
+
throw new InvalidArgumentError(`${name} must be >= ${options.min}`);
|
|
348657
|
+
}
|
|
348658
|
+
return n2;
|
|
348659
|
+
};
|
|
348660
|
+
}
|
|
348661
|
+
function parseEnum(name, values) {
|
|
348662
|
+
return (value) => {
|
|
348663
|
+
if (!values.includes(value)) {
|
|
348664
|
+
throw new InvalidArgumentError(`${name} must be one of: ${values.join(", ")}`);
|
|
348665
|
+
}
|
|
348666
|
+
return value;
|
|
348667
|
+
};
|
|
348668
|
+
}
|
|
348669
|
+
function collectValue(value, previous) {
|
|
348670
|
+
return [...previous, value];
|
|
348671
|
+
}
|
|
348672
|
+
|
|
348673
|
+
// src/shell/manifest/pulledEnv.ts
|
|
348674
|
+
import { join as join22 } from "node:path";
|
|
348675
|
+
|
|
348676
|
+
// src/shell/manifest/io.ts
|
|
348677
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
348678
|
+
import { join as join21 } from "node:path";
|
|
348679
|
+
var manifestFilename = ".manifest.json";
|
|
348680
|
+
var flowEntrySchema = exports_external.object({
|
|
348681
|
+
path: exports_external.string(),
|
|
348682
|
+
contentHash: exports_external.string(),
|
|
348683
|
+
tags: exports_external.array(exports_external.string()).optional()
|
|
348684
|
+
});
|
|
348685
|
+
var manifestSchema = exports_external.object({
|
|
348686
|
+
envId: exports_external.string(),
|
|
348687
|
+
envSlug: exports_external.string().optional(),
|
|
348688
|
+
envName: exports_external.string().optional(),
|
|
348689
|
+
fetchedAt: exports_external.string(),
|
|
348690
|
+
envVarsFetchedAt: exports_external.string().optional(),
|
|
348691
|
+
cliFlowsVersion: exports_external.string(),
|
|
348692
|
+
qawolfCommitSha: exports_external.string().optional(),
|
|
348693
|
+
qawolfCommittedAt: exports_external.string().optional(),
|
|
348694
|
+
tagsFetchedAt: exports_external.string().optional(),
|
|
348695
|
+
flows: exports_external.array(flowEntrySchema)
|
|
348696
|
+
});
|
|
348697
|
+
async function readManifest(envDir, fs3 = makeDefaultFs()) {
|
|
348698
|
+
let raw;
|
|
348699
|
+
try {
|
|
348700
|
+
raw = await fs3.readFile(join21(envDir, manifestFilename));
|
|
348701
|
+
} catch (err) {
|
|
348702
|
+
if (isNoEntError(err))
|
|
348703
|
+
return "missing";
|
|
348704
|
+
throw err;
|
|
348705
|
+
}
|
|
348706
|
+
let parsed;
|
|
348707
|
+
try {
|
|
348708
|
+
parsed = JSON.parse(raw);
|
|
348709
|
+
} catch {
|
|
348710
|
+
return "malformed";
|
|
348711
|
+
}
|
|
348712
|
+
const result = manifestSchema.safeParse(parsed);
|
|
348713
|
+
if (!result.success)
|
|
348714
|
+
return "malformed";
|
|
348715
|
+
return {
|
|
348716
|
+
envId: result.data.envId,
|
|
348717
|
+
envSlug: result.data.envSlug,
|
|
348718
|
+
envName: result.data.envName,
|
|
348719
|
+
fetchedAt: result.data.fetchedAt,
|
|
348720
|
+
envVarsFetchedAt: result.data.envVarsFetchedAt,
|
|
348721
|
+
cliFlowsVersion: result.data.cliFlowsVersion,
|
|
348722
|
+
qawolfCommitSha: result.data.qawolfCommitSha,
|
|
348723
|
+
qawolfCommittedAt: result.data.qawolfCommittedAt,
|
|
348724
|
+
tagsFetchedAt: result.data.tagsFetchedAt,
|
|
348725
|
+
flows: result.data.flows.map((flow) => ({
|
|
348726
|
+
path: flow.path,
|
|
348727
|
+
contentHash: flow.contentHash,
|
|
348728
|
+
tags: flow.tags
|
|
348729
|
+
}))
|
|
348730
|
+
};
|
|
348731
|
+
}
|
|
348732
|
+
async function writeManifest(envDir, manifest, fs3 = makeDefaultFs()) {
|
|
348733
|
+
const body = JSON.stringify(manifest, undefined, 2);
|
|
348734
|
+
await fs3.writeFile(join21(envDir, manifestFilename), `${body}
|
|
348735
|
+
`);
|
|
348736
|
+
}
|
|
348737
|
+
function hashFile(absPath, fs3 = makeDefaultFs()) {
|
|
348738
|
+
return new Promise((resolve5, reject) => {
|
|
348739
|
+
const hash2 = createHash2("sha256");
|
|
348740
|
+
const stream = fs3.createReadStream(absPath);
|
|
348741
|
+
stream.on("data", (chunk) => hash2.update(chunk));
|
|
348742
|
+
stream.on("end", () => resolve5(hash2.digest("hex")));
|
|
348743
|
+
stream.on("error", reject);
|
|
348744
|
+
});
|
|
348745
|
+
}
|
|
348746
|
+
|
|
348747
|
+
// src/shell/manifest/pulledEnv.ts
|
|
348748
|
+
async function findPulledEnv(ref, cwd, fs3 = makeDefaultFs()) {
|
|
348749
|
+
for (const envDir of await listPulledEnvDirs(cwd, fs3)) {
|
|
348750
|
+
const manifest = await readManifest(envDir, fs3);
|
|
348751
|
+
if (typeof manifest === "string")
|
|
348752
|
+
continue;
|
|
348753
|
+
if (manifest.envId === ref || manifest.envSlug === ref || manifest.envName === ref) {
|
|
348754
|
+
return { dir: envDir, envId: manifest.envId };
|
|
348755
|
+
}
|
|
348756
|
+
}
|
|
348757
|
+
return;
|
|
348758
|
+
}
|
|
348759
|
+
async function listPulledEnvDirs(cwd, fs3 = makeDefaultFs()) {
|
|
348760
|
+
const root = join22(cwd, ".qawolf");
|
|
348761
|
+
let entries;
|
|
348762
|
+
try {
|
|
348763
|
+
entries = await fs3.readdirWithTypes(root);
|
|
348764
|
+
} catch (err) {
|
|
348765
|
+
if (isNoEntError(err))
|
|
348766
|
+
return [];
|
|
348767
|
+
throw err;
|
|
348768
|
+
}
|
|
348769
|
+
const dirs = [];
|
|
348770
|
+
for (const entry of entries) {
|
|
348771
|
+
if (!entry.isDirectory())
|
|
348772
|
+
continue;
|
|
348773
|
+
const envDir = join22(root, entry.name);
|
|
348774
|
+
const manifest = await readManifest(envDir, fs3);
|
|
348775
|
+
if (typeof manifest === "string")
|
|
348776
|
+
continue;
|
|
348777
|
+
dirs.push(envDir);
|
|
348778
|
+
}
|
|
348779
|
+
return dirs;
|
|
348780
|
+
}
|
|
348781
|
+
|
|
348628
348782
|
// src/domains/flows/list.ts
|
|
348629
348783
|
import path2 from "node:path";
|
|
348630
348784
|
|
|
348785
|
+
// src/core/flowSelectors.ts
|
|
348786
|
+
function hasSelectors(selectors) {
|
|
348787
|
+
return selectors.tags.length > 0;
|
|
348788
|
+
}
|
|
348789
|
+
function matchesSelectors(flow, selectors) {
|
|
348790
|
+
if (selectors.tags.length === 0)
|
|
348791
|
+
return true;
|
|
348792
|
+
return selectors.tags.some((tag) => flow.tags?.includes(tag));
|
|
348793
|
+
}
|
|
348794
|
+
|
|
348795
|
+
// src/core/repoRelativePath.ts
|
|
348796
|
+
import { basename as basename3, dirname as dirname6, relative as relative3 } from "node:path";
|
|
348797
|
+
var toPosix = (path2) => path2.replaceAll("\\", "/");
|
|
348798
|
+
function findPulledEnvDir(flowAbsPath) {
|
|
348799
|
+
let current = dirname6(flowAbsPath);
|
|
348800
|
+
while (current !== dirname6(current)) {
|
|
348801
|
+
const parent = dirname6(current);
|
|
348802
|
+
if (basename3(parent) === ".qawolf")
|
|
348803
|
+
return current;
|
|
348804
|
+
current = parent;
|
|
348805
|
+
}
|
|
348806
|
+
return;
|
|
348807
|
+
}
|
|
348808
|
+
function toRepoRelativePath(flowAbsPath, cwd) {
|
|
348809
|
+
const envDir = findPulledEnvDir(flowAbsPath);
|
|
348810
|
+
return toPosix(relative3(envDir ?? cwd, flowAbsPath));
|
|
348811
|
+
}
|
|
348812
|
+
|
|
348813
|
+
// src/domains/flows/envLabels.ts
|
|
348814
|
+
function envLabelFor(file2, labels) {
|
|
348815
|
+
const dir = findPulledEnvDir(file2);
|
|
348816
|
+
return dir === undefined ? undefined : labels.get(dir);
|
|
348817
|
+
}
|
|
348818
|
+
async function readEnvLabels(files, readEnvLabel) {
|
|
348819
|
+
const dirs = new Set(files.map(findPulledEnvDir).filter((dir) => dir !== undefined));
|
|
348820
|
+
const labels = new Map;
|
|
348821
|
+
for (const dir of dirs)
|
|
348822
|
+
labels.set(dir, await readEnvLabel(dir));
|
|
348823
|
+
return labels;
|
|
348824
|
+
}
|
|
348825
|
+
|
|
348826
|
+
// src/core/suggestNearMiss.ts
|
|
348827
|
+
function normalize3(value) {
|
|
348828
|
+
return value.toLowerCase().replace(/[-_\s]+/g, " ").trim();
|
|
348829
|
+
}
|
|
348830
|
+
function editDistance(a2, b2) {
|
|
348831
|
+
let row = Array.from({ length: b2.length + 1 }, (_3, j) => j);
|
|
348832
|
+
for (let i2 = 1;i2 <= a2.length; i2 += 1) {
|
|
348833
|
+
const next = [i2];
|
|
348834
|
+
for (let j = 1;j <= b2.length; j += 1) {
|
|
348835
|
+
const substitution = (row[j - 1] ?? 0) + (a2[i2 - 1] === b2[j - 1] ? 0 : 1);
|
|
348836
|
+
const deletion = (row[j] ?? 0) + 1;
|
|
348837
|
+
const insertion = (next[j - 1] ?? 0) + 1;
|
|
348838
|
+
next.push(Math.min(substitution, deletion, insertion));
|
|
348839
|
+
}
|
|
348840
|
+
row = next;
|
|
348841
|
+
}
|
|
348842
|
+
return row[b2.length] ?? 0;
|
|
348843
|
+
}
|
|
348844
|
+
function distanceBudget(length) {
|
|
348845
|
+
return length >= 4 ? 2 : 1;
|
|
348846
|
+
}
|
|
348847
|
+
function suggestNearMiss(input, candidates) {
|
|
348848
|
+
if (candidates.includes(input))
|
|
348849
|
+
return;
|
|
348850
|
+
const sorted = [...candidates].sort();
|
|
348851
|
+
const normalizedInput = normalize3(input);
|
|
348852
|
+
const presentationMatch = sorted.find((candidate) => normalize3(candidate) === normalizedInput);
|
|
348853
|
+
if (presentationMatch !== undefined)
|
|
348854
|
+
return presentationMatch;
|
|
348855
|
+
let best;
|
|
348856
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
348857
|
+
for (const candidate of sorted) {
|
|
348858
|
+
const distance = editDistance(normalizedInput, normalize3(candidate));
|
|
348859
|
+
if (distance < bestDistance) {
|
|
348860
|
+
bestDistance = distance;
|
|
348861
|
+
best = candidate;
|
|
348862
|
+
}
|
|
348863
|
+
}
|
|
348864
|
+
return bestDistance <= distanceBudget(normalizedInput.length) ? best : undefined;
|
|
348865
|
+
}
|
|
348866
|
+
|
|
348867
|
+
// src/domains/flows/selectPulledEnv.ts
|
|
348868
|
+
async function selectPulledEnv(args) {
|
|
348869
|
+
const found = await args.findPulledEnv(args.ref);
|
|
348870
|
+
if (found !== undefined) {
|
|
348871
|
+
return {
|
|
348872
|
+
kind: "selected",
|
|
348873
|
+
files: args.files.filter((file2) => findPulledEnvDir(file2) === found.dir)
|
|
348874
|
+
};
|
|
348875
|
+
}
|
|
348876
|
+
const dirs = await args.listPulledEnvDirs();
|
|
348877
|
+
const labels = (await Promise.all(dirs.map((dir) => args.readEnvLabel(dir)))).sort();
|
|
348878
|
+
return {
|
|
348879
|
+
kind: "unknown",
|
|
348880
|
+
result: {
|
|
348881
|
+
error: flowsMessages.selectors.unknownPulledEnv(args.ref, labels, suggestNearMiss(args.ref, labels)),
|
|
348882
|
+
exitCode: exitCodes.invalidArgs
|
|
348883
|
+
}
|
|
348884
|
+
};
|
|
348885
|
+
}
|
|
348886
|
+
|
|
348887
|
+
// src/domains/flows/explainEmptySelection.ts
|
|
348888
|
+
function explainEmptySelection(selectors, knownTags) {
|
|
348889
|
+
if (knownTags !== undefined) {
|
|
348890
|
+
const unknownTag = selectors.tags.find((tag) => !knownTags.includes(tag));
|
|
348891
|
+
if (unknownTag !== undefined) {
|
|
348892
|
+
return flowsMessages.selectors.unknownTag(unknownTag, suggestNearMiss(unknownTag, knownTags));
|
|
348893
|
+
}
|
|
348894
|
+
}
|
|
348895
|
+
return flowsMessages.selectors.noFlowsSelected(selectors);
|
|
348896
|
+
}
|
|
348897
|
+
|
|
348898
|
+
// src/domains/flows/selectorGuards.ts
|
|
348899
|
+
function tagsNotCachedResult(selectors, cachedTags) {
|
|
348900
|
+
if (!hasSelectors(selectors) || cachedTags.size > 0)
|
|
348901
|
+
return;
|
|
348902
|
+
return {
|
|
348903
|
+
error: flowsMessages.selectors.tagsNotCached,
|
|
348904
|
+
exitCode: exitCodes.network
|
|
348905
|
+
};
|
|
348906
|
+
}
|
|
348907
|
+
function tagsUnavailableResult(envId) {
|
|
348908
|
+
return {
|
|
348909
|
+
error: flowsMessages.selectors.tagsUnavailable(envId),
|
|
348910
|
+
exitCode: exitCodes.network
|
|
348911
|
+
};
|
|
348912
|
+
}
|
|
348913
|
+
async function emptySelectionResult(selectors, matched, fetchKnownTags) {
|
|
348914
|
+
if (matched > 0 || !hasSelectors(selectors))
|
|
348915
|
+
return;
|
|
348916
|
+
return {
|
|
348917
|
+
error: explainEmptySelection(selectors, await fetchKnownTags?.()),
|
|
348918
|
+
exitCode: exitCodes.invalidArgs
|
|
348919
|
+
};
|
|
348920
|
+
}
|
|
348921
|
+
|
|
348631
348922
|
// src/core/renderTable.ts
|
|
348632
348923
|
var ansiBold = "\x1B[1m";
|
|
348633
348924
|
var ansiReset = "\x1B[0m";
|
|
@@ -348648,29 +348939,75 @@ function renderTable(options) {
|
|
|
348648
348939
|
}
|
|
348649
348940
|
|
|
348650
348941
|
// src/domains/flows/renderListTable.ts
|
|
348651
|
-
var
|
|
348652
|
-
|
|
348653
|
-
|
|
348654
|
-
|
|
348655
|
-
|
|
348942
|
+
var nameColumn = {
|
|
348943
|
+
header: "name",
|
|
348944
|
+
value: (row) => row.name
|
|
348945
|
+
};
|
|
348946
|
+
var targetColumn = {
|
|
348947
|
+
header: "target",
|
|
348948
|
+
value: (row) => row.target
|
|
348949
|
+
};
|
|
348950
|
+
var envColumn = {
|
|
348951
|
+
header: "env",
|
|
348952
|
+
value: (row) => row.env ?? ""
|
|
348953
|
+
};
|
|
348954
|
+
var tagsColumn = {
|
|
348955
|
+
header: "tags",
|
|
348956
|
+
value: (row) => (row.tags ?? []).join(", ")
|
|
348957
|
+
};
|
|
348958
|
+
var fileColumn = {
|
|
348959
|
+
header: "file",
|
|
348960
|
+
value: (row) => row.file
|
|
348961
|
+
};
|
|
348656
348962
|
function renderListTable(rows, boldHeader) {
|
|
348963
|
+
const someTagged = rows.some((row) => (row.tags ?? []).length > 0);
|
|
348964
|
+
const severalEnvs = new Set(rows.map((row) => row.env)).size > 1;
|
|
348965
|
+
const columns = [
|
|
348966
|
+
nameColumn,
|
|
348967
|
+
targetColumn,
|
|
348968
|
+
...severalEnvs ? [envColumn] : [],
|
|
348969
|
+
...someTagged ? [tagsColumn] : [],
|
|
348970
|
+
fileColumn
|
|
348971
|
+
];
|
|
348657
348972
|
return renderTable({ boldHeader, columns, rows });
|
|
348658
348973
|
}
|
|
348659
348974
|
|
|
348660
348975
|
// src/domains/flows/list.ts
|
|
348661
|
-
async function flowsList(ctx, pattern, deps) {
|
|
348976
|
+
async function flowsList(ctx, pattern, deps, selectors = { tags: [] }) {
|
|
348662
348977
|
const patterns = pattern ? [pattern] : [];
|
|
348663
|
-
|
|
348664
|
-
|
|
348978
|
+
let files = await deps.expandPatterns(patterns, deps.cwd);
|
|
348979
|
+
if (selectors.env !== undefined) {
|
|
348980
|
+
const selection = await selectPulledEnv({
|
|
348981
|
+
files,
|
|
348982
|
+
ref: selectors.env,
|
|
348983
|
+
findPulledEnv: deps.findPulledEnv,
|
|
348984
|
+
listPulledEnvDirs: deps.listPulledEnvDirs,
|
|
348985
|
+
readEnvLabel: deps.readEnvLabel
|
|
348986
|
+
});
|
|
348987
|
+
if (selection.kind === "unknown")
|
|
348988
|
+
return selection.result;
|
|
348989
|
+
files = selection.files;
|
|
348990
|
+
}
|
|
348991
|
+
const cachedTags = await deps.readCachedTags(files);
|
|
348992
|
+
const envLabels = await readEnvLabels(files, deps.readEnvLabel);
|
|
348993
|
+
const notCached = tagsNotCachedResult(selectors, cachedTags);
|
|
348994
|
+
if (notCached !== undefined)
|
|
348995
|
+
return notCached;
|
|
348996
|
+
const all = [];
|
|
348665
348997
|
for await (const { file: file2, ...meta3 } of batchMap(files, async (f2) => ({ file: f2, ...await deps.peekFlowMeta(f2) }), flowBatchSize)) {
|
|
348666
|
-
|
|
348998
|
+
all.push({
|
|
348667
348999
|
file: path2.relative(deps.cwd, file2),
|
|
348668
349000
|
name: meta3.name ?? flowBasename(file2),
|
|
348669
|
-
|
|
349001
|
+
env: envLabelFor(file2, envLabels),
|
|
349002
|
+
tags: cachedTags.get(file2),
|
|
348670
349003
|
target: meta3.target,
|
|
348671
349004
|
browser: meta3.target ? targetToBrowser(meta3.target) : undefined
|
|
348672
349005
|
});
|
|
348673
349006
|
}
|
|
349007
|
+
const items = all.filter((item) => matchesSelectors(item, selectors));
|
|
349008
|
+
const empty2 = await emptySelectionResult(selectors, items.length, undefined);
|
|
349009
|
+
if (empty2 !== undefined)
|
|
349010
|
+
return empty2;
|
|
348674
349011
|
if (ctx.ui.mode === "json") {
|
|
348675
349012
|
ctx.ui.json(items);
|
|
348676
349013
|
return;
|
|
@@ -348682,6 +349019,8 @@ async function flowsList(ctx, pattern, deps) {
|
|
|
348682
349019
|
const rows = items.map((it) => ({
|
|
348683
349020
|
name: it.name,
|
|
348684
349021
|
target: it.target ?? "",
|
|
349022
|
+
env: it.env,
|
|
349023
|
+
tags: it.tags,
|
|
348685
349024
|
file: it.file
|
|
348686
349025
|
}));
|
|
348687
349026
|
if (ctx.ui.mode === "agent") {
|
|
@@ -348693,17 +349032,91 @@ async function flowsList(ctx, pattern, deps) {
|
|
|
348693
349032
|
ctx.ui.write(renderListTable(rows, true));
|
|
348694
349033
|
ctx.ui.outro(flowsMessages.flowCount(items.length));
|
|
348695
349034
|
}
|
|
348696
|
-
|
|
349035
|
+
|
|
349036
|
+
// src/domains/flows/readCachedTags.ts
|
|
349037
|
+
import { relative as relative4 } from "node:path";
|
|
349038
|
+
async function readCachedTags(files, fs3 = makeDefaultFs()) {
|
|
349039
|
+
const filesByEnvDir = new Map;
|
|
349040
|
+
for (const file2 of files) {
|
|
349041
|
+
const envDir = findPulledEnvDir(file2);
|
|
349042
|
+
if (envDir === undefined)
|
|
349043
|
+
continue;
|
|
349044
|
+
const group = filesByEnvDir.get(envDir);
|
|
349045
|
+
if (group)
|
|
349046
|
+
group.push(file2);
|
|
349047
|
+
else
|
|
349048
|
+
filesByEnvDir.set(envDir, [file2]);
|
|
349049
|
+
}
|
|
349050
|
+
const tagsByFile = new Map;
|
|
349051
|
+
for (const [envDir, envFiles] of filesByEnvDir) {
|
|
349052
|
+
const manifest = await readManifest(envDir, fs3);
|
|
349053
|
+
if (typeof manifest === "string")
|
|
349054
|
+
continue;
|
|
349055
|
+
if (manifest.tagsFetchedAt === undefined)
|
|
349056
|
+
continue;
|
|
349057
|
+
const entryByPath = new Map(manifest.flows.map((f2) => [toPosix(f2.path), f2]));
|
|
349058
|
+
for (const file2 of envFiles) {
|
|
349059
|
+
const tags = entryByPath.get(toPosix(relative4(envDir, file2)))?.tags;
|
|
349060
|
+
if (tags !== undefined)
|
|
349061
|
+
tagsByFile.set(file2, tags);
|
|
349062
|
+
}
|
|
349063
|
+
}
|
|
349064
|
+
return tagsByFile;
|
|
349065
|
+
}
|
|
349066
|
+
|
|
349067
|
+
// src/domains/flows/readEnvLabel.ts
|
|
349068
|
+
import { basename as basename4 } from "node:path";
|
|
349069
|
+
async function readEnvLabel(envDir, fs3 = makeDefaultFs()) {
|
|
349070
|
+
const manifest = await readManifest(envDir, fs3);
|
|
349071
|
+
if (typeof manifest === "string")
|
|
349072
|
+
return basename4(envDir);
|
|
349073
|
+
return manifest.envSlug ?? manifest.envName ?? basename4(envDir);
|
|
349074
|
+
}
|
|
349075
|
+
|
|
349076
|
+
// src/domains/flows/listDefaults.ts
|
|
349077
|
+
function handleFlowsList(ctx, pattern, selectors) {
|
|
348697
349078
|
const { fs: fs3 } = ctx;
|
|
348698
349079
|
return flowsList(ctx, pattern, {
|
|
348699
349080
|
cwd: process.cwd(),
|
|
348700
349081
|
expandPatterns: (patterns, cwd) => expandPatterns(patterns, cwd, undefined, fs3),
|
|
348701
|
-
peekFlowMeta: makePeekFlowMeta(fs3)
|
|
348702
|
-
|
|
349082
|
+
peekFlowMeta: makePeekFlowMeta(fs3),
|
|
349083
|
+
readCachedTags: (files) => readCachedTags(files, fs3),
|
|
349084
|
+
readEnvLabel: (envDir) => readEnvLabel(envDir, fs3),
|
|
349085
|
+
findPulledEnv: (ref) => findPulledEnv(ref, process.cwd(), fs3),
|
|
349086
|
+
listPulledEnvDirs: () => listPulledEnvDirs(process.cwd(), fs3)
|
|
349087
|
+
}, selectors);
|
|
348703
349088
|
}
|
|
348704
349089
|
|
|
348705
349090
|
// src/domains/flows/listRemote.ts
|
|
348706
349091
|
var import_picomatch2 = __toESM(require_picomatch2(), 1);
|
|
349092
|
+
|
|
349093
|
+
// src/domains/flows/fetchKnownTags.ts
|
|
349094
|
+
var pageSize = 100;
|
|
349095
|
+
var maxPages = 20;
|
|
349096
|
+
async function fetchKnownTags(ctx) {
|
|
349097
|
+
const names = [];
|
|
349098
|
+
let cursor3;
|
|
349099
|
+
try {
|
|
349100
|
+
for (let page = 0;page < maxPages; page += 1) {
|
|
349101
|
+
const result = await ctx.platformClient.callPublicApi(publicContractsV1.tag.list, {
|
|
349102
|
+
includeFlowIds: false,
|
|
349103
|
+
limit: pageSize,
|
|
349104
|
+
...cursor3 === undefined ? {} : { cursor: cursor3 }
|
|
349105
|
+
});
|
|
349106
|
+
if (!result.ok)
|
|
349107
|
+
return;
|
|
349108
|
+
names.push(...result.value.tags.map((tag) => tag.name));
|
|
349109
|
+
cursor3 = result.value.nextCursor;
|
|
349110
|
+
if (cursor3 === undefined)
|
|
349111
|
+
return names;
|
|
349112
|
+
}
|
|
349113
|
+
} catch {
|
|
349114
|
+
return;
|
|
349115
|
+
}
|
|
349116
|
+
return;
|
|
349117
|
+
}
|
|
349118
|
+
|
|
349119
|
+
// src/domains/flows/listRemote.ts
|
|
348707
349120
|
async function flowsListRemote(ctx, pattern, options) {
|
|
348708
349121
|
const result = await ctx.platformClient.callPublicApi(publicContractsV1.flow.list, {
|
|
348709
349122
|
environmentId: options.env,
|
|
@@ -348712,7 +349125,7 @@ async function flowsListRemote(ctx, pattern, options) {
|
|
|
348712
349125
|
if (!result.ok)
|
|
348713
349126
|
return failureFields(result);
|
|
348714
349127
|
const matches = pattern ? import_picomatch2.default(pattern) : undefined;
|
|
348715
|
-
const
|
|
349128
|
+
const all = result.value.flows.filter((f2) => !matches || matches(f2.path)).map((f2) => ({
|
|
348716
349129
|
flowId: f2.flowId,
|
|
348717
349130
|
file: f2.path,
|
|
348718
349131
|
name: f2.name,
|
|
@@ -348720,6 +349133,11 @@ async function flowsListRemote(ctx, pattern, options) {
|
|
|
348720
349133
|
target: typeof f2.executionTarget === "string" ? f2.executionTarget : JSON.stringify(f2.executionTarget),
|
|
348721
349134
|
url: f2.url
|
|
348722
349135
|
}));
|
|
349136
|
+
const selectors = { tags: options.tags };
|
|
349137
|
+
const items = all.filter((item) => matchesSelectors(item, selectors));
|
|
349138
|
+
const empty2 = await emptySelectionResult(selectors, items.length, () => fetchKnownTags(ctx));
|
|
349139
|
+
if (empty2 !== undefined)
|
|
349140
|
+
return empty2;
|
|
348723
349141
|
if (ctx.ui.mode === "json") {
|
|
348724
349142
|
ctx.ui.json(items);
|
|
348725
349143
|
return;
|
|
@@ -348731,6 +349149,8 @@ async function flowsListRemote(ctx, pattern, options) {
|
|
|
348731
349149
|
const rows = items.map((it) => ({
|
|
348732
349150
|
name: it.name,
|
|
348733
349151
|
target: it.target,
|
|
349152
|
+
env: undefined,
|
|
349153
|
+
tags: it.tags,
|
|
348734
349154
|
file: it.file
|
|
348735
349155
|
}));
|
|
348736
349156
|
if (ctx.ui.mode === "agent") {
|
|
@@ -348744,77 +349164,29 @@ async function flowsListRemote(ctx, pattern, options) {
|
|
|
348744
349164
|
}
|
|
348745
349165
|
|
|
348746
349166
|
// src/domains/flows/pull/handler.ts
|
|
348747
|
-
import { dirname as
|
|
349167
|
+
import { dirname as dirname8, join as join27, resolve as resolve8 } from "node:path";
|
|
348748
349168
|
|
|
348749
|
-
// src/
|
|
348750
|
-
|
|
348751
|
-
import { join as join21 } from "node:path";
|
|
348752
|
-
var manifestFilename = ".manifest.json";
|
|
348753
|
-
var flowEntrySchema = exports_external.object({
|
|
348754
|
-
path: exports_external.string(),
|
|
348755
|
-
contentHash: exports_external.string()
|
|
348756
|
-
});
|
|
348757
|
-
var manifestSchema = exports_external.object({
|
|
348758
|
-
envId: exports_external.string(),
|
|
348759
|
-
envSlug: exports_external.string().optional(),
|
|
348760
|
-
fetchedAt: exports_external.string(),
|
|
348761
|
-
envVarsFetchedAt: exports_external.string().optional(),
|
|
348762
|
-
cliFlowsVersion: exports_external.string(),
|
|
348763
|
-
qawolfCommitSha: exports_external.string().optional(),
|
|
348764
|
-
qawolfCommittedAt: exports_external.string().optional(),
|
|
348765
|
-
flows: exports_external.array(flowEntrySchema)
|
|
348766
|
-
});
|
|
348767
|
-
async function readManifest(envDir, fs3 = makeDefaultFs()) {
|
|
348768
|
-
let raw;
|
|
348769
|
-
try {
|
|
348770
|
-
raw = await fs3.readFile(join21(envDir, manifestFilename));
|
|
348771
|
-
} catch (err) {
|
|
348772
|
-
if (isNoEntError(err))
|
|
348773
|
-
return "missing";
|
|
348774
|
-
throw err;
|
|
348775
|
-
}
|
|
348776
|
-
let parsed;
|
|
349169
|
+
// src/domains/flows/pull/fetchPhase.ts
|
|
349170
|
+
async function fetchTags(ctx, envId) {
|
|
348777
349171
|
try {
|
|
348778
|
-
|
|
349172
|
+
const result = await ctx.platformClient.callPublicApi(publicContractsV1.flow.list, { environmentId: envId, includeDrafts: true });
|
|
349173
|
+
if (!result.ok)
|
|
349174
|
+
return;
|
|
349175
|
+
return {
|
|
349176
|
+
fetchedAt: new Date,
|
|
349177
|
+
byPath: new Map(result.value.flows.map((f2) => [f2.path, [...f2.tags]]))
|
|
349178
|
+
};
|
|
348779
349179
|
} catch {
|
|
348780
|
-
return
|
|
349180
|
+
return;
|
|
348781
349181
|
}
|
|
348782
|
-
const result = manifestSchema.safeParse(parsed);
|
|
348783
|
-
if (!result.success)
|
|
348784
|
-
return "malformed";
|
|
348785
|
-
return {
|
|
348786
|
-
envId: result.data.envId,
|
|
348787
|
-
envSlug: result.data.envSlug,
|
|
348788
|
-
fetchedAt: result.data.fetchedAt,
|
|
348789
|
-
envVarsFetchedAt: result.data.envVarsFetchedAt,
|
|
348790
|
-
cliFlowsVersion: result.data.cliFlowsVersion,
|
|
348791
|
-
qawolfCommitSha: result.data.qawolfCommitSha,
|
|
348792
|
-
qawolfCommittedAt: result.data.qawolfCommittedAt,
|
|
348793
|
-
flows: result.data.flows
|
|
348794
|
-
};
|
|
348795
|
-
}
|
|
348796
|
-
async function writeManifest(envDir, manifest, fs3 = makeDefaultFs()) {
|
|
348797
|
-
const body = JSON.stringify(manifest, undefined, 2);
|
|
348798
|
-
await fs3.writeFile(join21(envDir, manifestFilename), `${body}
|
|
348799
|
-
`);
|
|
348800
349182
|
}
|
|
348801
|
-
function hashFile(absPath, fs3 = makeDefaultFs()) {
|
|
348802
|
-
return new Promise((resolve5, reject) => {
|
|
348803
|
-
const hash2 = createHash2("sha256");
|
|
348804
|
-
const stream = fs3.createReadStream(absPath);
|
|
348805
|
-
stream.on("data", (chunk) => hash2.update(chunk));
|
|
348806
|
-
stream.on("end", () => resolve5(hash2.digest("hex")));
|
|
348807
|
-
stream.on("error", reject);
|
|
348808
|
-
});
|
|
348809
|
-
}
|
|
348810
|
-
|
|
348811
|
-
// src/domains/flows/pull/fetchPhase.ts
|
|
348812
349183
|
async function fetchBundleAndEnvVars(ctx, envId) {
|
|
348813
349184
|
const { platformClient } = ctx;
|
|
348814
349185
|
let tmpArchive;
|
|
348815
349186
|
let bundleFetchedAt;
|
|
348816
349187
|
let envVars;
|
|
348817
349188
|
let envVarsFetchedAt;
|
|
349189
|
+
let tags;
|
|
348818
349190
|
await ctx.ui.withProgress([
|
|
348819
349191
|
{
|
|
348820
349192
|
message: flowsMessages.pull.downloadingBundle,
|
|
@@ -348835,19 +349207,25 @@ async function fetchBundleAndEnvVars(ctx, envId) {
|
|
|
348835
349207
|
envVars = result.value;
|
|
348836
349208
|
envVarsFetchedAt = new Date;
|
|
348837
349209
|
}
|
|
349210
|
+
},
|
|
349211
|
+
{
|
|
349212
|
+
message: flowsMessages.pull.fetchingTags,
|
|
349213
|
+
task: async () => {
|
|
349214
|
+
tags = await fetchTags(ctx, envId);
|
|
349215
|
+
}
|
|
348838
349216
|
}
|
|
348839
349217
|
], flowsMessages.pull.downloadComplete);
|
|
348840
349218
|
if (tmpArchive === undefined || bundleFetchedAt === undefined || envVars === undefined || envVarsFetchedAt === undefined) {
|
|
348841
349219
|
throw new Error("Unexpected state: the bundle and env vars were not fetched. " + "This is a bug - please report it at https://github.com/qawolf/cli/issues");
|
|
348842
349220
|
}
|
|
348843
|
-
return { tmpArchive, bundleFetchedAt, envVars, envVarsFetchedAt };
|
|
349221
|
+
return { tmpArchive, bundleFetchedAt, envVars, envVarsFetchedAt, tags };
|
|
348844
349222
|
}
|
|
348845
349223
|
|
|
348846
349224
|
// src/domains/flows/pull/safety.ts
|
|
348847
349225
|
import { resolve as resolve6 } from "node:path";
|
|
348848
349226
|
|
|
348849
349227
|
// src/domains/flows/pull/entryPath.ts
|
|
348850
|
-
import { isAbsolute as isAbsolute3, posix as posix2, relative as
|
|
349228
|
+
import { isAbsolute as isAbsolute3, posix as posix2, relative as relative5, resolve as resolve5 } from "node:path";
|
|
348851
349229
|
function validateEntryPath(name, destResolved) {
|
|
348852
349230
|
if (!name)
|
|
348853
349231
|
throw new Error("empty entry name");
|
|
@@ -348859,7 +349237,7 @@ function validateEntryPath(name, destResolved) {
|
|
|
348859
349237
|
throw new Error(`path traversal: entry escapes destination (${name})`);
|
|
348860
349238
|
}
|
|
348861
349239
|
const target = resolve5(destResolved, name);
|
|
348862
|
-
const rel =
|
|
349240
|
+
const rel = relative5(destResolved, target);
|
|
348863
349241
|
if (rel.startsWith("..") || isAbsolute3(rel)) {
|
|
348864
349242
|
throw new Error(`path traversal: entry resolves outside destination (${name})`);
|
|
348865
349243
|
}
|
|
@@ -348929,8 +349307,28 @@ async function checkSafety(args) {
|
|
|
348929
349307
|
return promptOverwriteIfModified({ ...args, manifest: existing });
|
|
348930
349308
|
}
|
|
348931
349309
|
|
|
349310
|
+
// src/domains/flows/pull/reportPull.ts
|
|
349311
|
+
import { join as join23 } from "node:path";
|
|
349312
|
+
function reportPullResult(ui, args) {
|
|
349313
|
+
if (ui.mode !== "json")
|
|
349314
|
+
return;
|
|
349315
|
+
ui.output({
|
|
349316
|
+
env: args.env,
|
|
349317
|
+
envDir: args.stage.envDir,
|
|
349318
|
+
assetsDir: args.assetsAbs,
|
|
349319
|
+
fetchedAt: args.fetchedAt.toISOString(),
|
|
349320
|
+
flowCount: args.stage.flowCount,
|
|
349321
|
+
envVarCount: args.stage.envVarCount,
|
|
349322
|
+
flowsWithTeamStorageRefs: args.stage.flowsWithTeamStorageRefs,
|
|
349323
|
+
assetDownloadedCount: args.assets.downloadedCount,
|
|
349324
|
+
assetReusedCount: args.assets.reusedCount,
|
|
349325
|
+
assetSkippedCount: args.assets.skippedCount,
|
|
349326
|
+
manifestPath: join23(args.stage.envDir, manifestFilename)
|
|
349327
|
+
}, "");
|
|
349328
|
+
}
|
|
349329
|
+
|
|
348932
349330
|
// src/domains/flows/pull/bundle.ts
|
|
348933
|
-
import { join as
|
|
349331
|
+
import { join as join24, relative as relative6 } from "node:path";
|
|
348934
349332
|
async function flattenSingleWrapper(dir, fs3 = makeDefaultFs()) {
|
|
348935
349333
|
const entries = await fs3.readdir(dir);
|
|
348936
349334
|
if (entries.length !== 1)
|
|
@@ -348938,12 +349336,12 @@ async function flattenSingleWrapper(dir, fs3 = makeDefaultFs()) {
|
|
|
348938
349336
|
const innerName = entries[0];
|
|
348939
349337
|
if (!innerName)
|
|
348940
349338
|
return;
|
|
348941
|
-
const inner =
|
|
349339
|
+
const inner = join24(dir, innerName);
|
|
348942
349340
|
const innerStat = await fs3.stat(inner);
|
|
348943
349341
|
if (!innerStat.isDirectory())
|
|
348944
349342
|
return;
|
|
348945
349343
|
for (const e of await fs3.readdir(inner)) {
|
|
348946
|
-
await fs3.rename(
|
|
349344
|
+
await fs3.rename(join24(inner, e), join24(dir, e));
|
|
348947
349345
|
}
|
|
348948
349346
|
const leftovers = await fs3.readdir(inner);
|
|
348949
349347
|
if (leftovers.length > 0) {
|
|
@@ -348961,17 +349359,20 @@ var flowExtensions = [".flow.ts", ".flow.js"];
|
|
|
348961
349359
|
async function buildManifest(args, fs3 = makeDefaultFs()) {
|
|
348962
349360
|
const flowPaths = await walkForFlows(args.bundleDir, fs3);
|
|
348963
349361
|
const flows = await Promise.all(flowPaths.map(async (rel) => ({
|
|
348964
|
-
path: rel,
|
|
348965
|
-
contentHash: await hashFile(
|
|
349362
|
+
path: toPosix(rel),
|
|
349363
|
+
contentHash: await hashFile(join24(args.bundleDir, rel), fs3),
|
|
349364
|
+
tags: args.tags?.byPath.get(toPosix(rel))
|
|
348966
349365
|
})));
|
|
348967
349366
|
return {
|
|
348968
349367
|
envId: args.envId,
|
|
348969
|
-
envSlug:
|
|
349368
|
+
envSlug: args.envSlug,
|
|
349369
|
+
envName: args.envName,
|
|
348970
349370
|
fetchedAt: args.now.toISOString(),
|
|
348971
349371
|
envVarsFetchedAt: args.envVarsFetchedAt?.toISOString(),
|
|
348972
349372
|
cliFlowsVersion: args.cliFlowsVersion,
|
|
348973
349373
|
qawolfCommitSha: extractQawolfCommitSha(args.wrapperName),
|
|
348974
349374
|
qawolfCommittedAt: args.qawolfCommittedAt,
|
|
349375
|
+
tagsFetchedAt: args.tags?.fetchedAt.toISOString(),
|
|
348975
349376
|
flows
|
|
348976
349377
|
};
|
|
348977
349378
|
}
|
|
@@ -348983,11 +349384,11 @@ async function walkForFlows(root, fs3) {
|
|
|
348983
349384
|
async function walk(current, root, out, fs3) {
|
|
348984
349385
|
const entries = await fs3.readdirWithTypes(current);
|
|
348985
349386
|
for (const e of entries) {
|
|
348986
|
-
const abs =
|
|
349387
|
+
const abs = join24(current, e.name);
|
|
348987
349388
|
if (e.isDirectory()) {
|
|
348988
349389
|
await walk(abs, root, out, fs3);
|
|
348989
349390
|
} else if (e.isFile() && flowExtensions.some((ext) => e.name.endsWith(ext))) {
|
|
348990
|
-
out.push(
|
|
349391
|
+
out.push(relative6(root, abs));
|
|
348991
349392
|
}
|
|
348992
349393
|
}
|
|
348993
349394
|
}
|
|
@@ -348996,11 +349397,11 @@ async function sampleQawolfCommittedAt(bundleDir, fs3 = makeDefaultFs()) {
|
|
|
348996
349397
|
const sample = flowPaths[0];
|
|
348997
349398
|
if (!sample)
|
|
348998
349399
|
return;
|
|
348999
|
-
return (await fs3.stat(
|
|
349400
|
+
return (await fs3.stat(join24(bundleDir, sample))).mtime.toISOString();
|
|
349000
349401
|
}
|
|
349001
349402
|
|
|
349002
349403
|
// src/domains/flows/pull/applyTeamStorageRewrite.ts
|
|
349003
|
-
import { join as
|
|
349404
|
+
import { join as join25, relative as relative7 } from "node:path";
|
|
349004
349405
|
|
|
349005
349406
|
// src/domains/flows/pull/rewriteTeamStorage.ts
|
|
349006
349407
|
var runnerMountPrefix = "/home/wolf/team-storage/";
|
|
@@ -349036,7 +349437,7 @@ function isFlowFile(name) {
|
|
|
349036
349437
|
async function walk2(dir, out, fs3) {
|
|
349037
349438
|
const entries = await fs3.readdirWithTypes(dir);
|
|
349038
349439
|
for (const e of entries) {
|
|
349039
|
-
const abs =
|
|
349440
|
+
const abs = join25(dir, e.name);
|
|
349040
349441
|
if (e.isDirectory()) {
|
|
349041
349442
|
await walk2(abs, out, fs3);
|
|
349042
349443
|
} else if (e.isFile() && isSourceFile(e.name)) {
|
|
@@ -349055,7 +349456,7 @@ async function applyTeamStorageRewrite(rootDir, fs3 = makeDefaultFs()) {
|
|
|
349055
349456
|
await fs3.writeFile(file2, finalSource);
|
|
349056
349457
|
}
|
|
349057
349458
|
if (isFlowFile(file2) && finalSource.includes("process.env.TEAM_STORAGE_DIR")) {
|
|
349058
|
-
return
|
|
349459
|
+
return relative7(rootDir, file2);
|
|
349059
349460
|
}
|
|
349060
349461
|
return;
|
|
349061
349462
|
}));
|
|
@@ -349064,7 +349465,7 @@ async function applyTeamStorageRewrite(rootDir, fs3 = makeDefaultFs()) {
|
|
|
349064
349465
|
}
|
|
349065
349466
|
|
|
349066
349467
|
// src/domains/flows/pull/envVars.ts
|
|
349067
|
-
import { join as
|
|
349468
|
+
import { join as join26 } from "node:path";
|
|
349068
349469
|
|
|
349069
349470
|
// src/core/dotenv.ts
|
|
349070
349471
|
var bareKeyPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -349129,13 +349530,13 @@ function unquote(escaped) {
|
|
|
349129
349530
|
async function writeEnvFile(envDir, vars, fs3 = makeDefaultFs()) {
|
|
349130
349531
|
if (Object.keys(vars).length === 0)
|
|
349131
349532
|
return;
|
|
349132
|
-
await fs3.writeFile(
|
|
349533
|
+
await fs3.writeFile(join26(envDir, ".env"), serializeDotenv(vars), {
|
|
349133
349534
|
mode: 384
|
|
349134
349535
|
});
|
|
349135
349536
|
}
|
|
349136
349537
|
|
|
349137
349538
|
// src/domains/flows/pull/extract.ts
|
|
349138
|
-
import { dirname as
|
|
349539
|
+
import { dirname as dirname7, resolve as resolve7 } from "node:path";
|
|
349139
349540
|
import { createGunzip } from "node:zlib";
|
|
349140
349541
|
|
|
349141
349542
|
// node_modules/tar/dist/esm/index.min.js
|
|
@@ -352452,7 +352853,7 @@ async function handleEntry(args) {
|
|
|
352452
352853
|
total: args.getTotal()
|
|
352453
352854
|
});
|
|
352454
352855
|
args.addTotal(size);
|
|
352455
|
-
args.fs.mkdirSync(
|
|
352856
|
+
args.fs.mkdirSync(dirname7(target), { recursive: true });
|
|
352456
352857
|
const chunks = [];
|
|
352457
352858
|
await new Promise((res, rej) => {
|
|
352458
352859
|
entry.on("data", (chunk) => chunks.push(chunk));
|
|
@@ -352510,6 +352911,9 @@ async function stageBundle(args, fs4 = makeDefaultFs()) {
|
|
|
352510
352911
|
await writeEnvFile(tmpDir, effectiveEnvVars, fs4);
|
|
352511
352912
|
const manifest = await buildManifest({
|
|
352512
352913
|
envId: args.envId,
|
|
352914
|
+
tags: args.tags ?? await carriedTags(args.destAbs, fs4),
|
|
352915
|
+
envSlug: args.envSlug,
|
|
352916
|
+
envName: args.envName,
|
|
352513
352917
|
bundleDir: tmpDir,
|
|
352514
352918
|
cliFlowsVersion: args.cliFlowsVersion,
|
|
352515
352919
|
now: args.now,
|
|
@@ -352543,6 +352947,19 @@ async function stageBundle(args, fs4 = makeDefaultFs()) {
|
|
|
352543
352947
|
throw err;
|
|
352544
352948
|
}
|
|
352545
352949
|
}
|
|
352950
|
+
async function carriedTags(envDir, fs4) {
|
|
352951
|
+
const previous = await readManifest(envDir, fs4);
|
|
352952
|
+
if (typeof previous === "string")
|
|
352953
|
+
return;
|
|
352954
|
+
if (previous.tagsFetchedAt === undefined)
|
|
352955
|
+
return;
|
|
352956
|
+
const byPath = new Map;
|
|
352957
|
+
for (const flow of previous.flows) {
|
|
352958
|
+
if (flow.tags !== undefined)
|
|
352959
|
+
byPath.set(toPosix(flow.path), [...flow.tags]);
|
|
352960
|
+
}
|
|
352961
|
+
return { fetchedAt: new Date(previous.tagsFetchedAt), byPath };
|
|
352962
|
+
}
|
|
352546
352963
|
|
|
352547
352964
|
// src/domains/flows/pull/handler.ts
|
|
352548
352965
|
async function handleFlowsPull(ctx, opts, deps) {
|
|
@@ -352555,8 +352972,8 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
352555
352972
|
ctx.ui.error(validation.error);
|
|
352556
352973
|
return { error: validation.error };
|
|
352557
352974
|
}
|
|
352558
|
-
const destAbs = resolve8(opts.out ??
|
|
352559
|
-
const assetsAbs =
|
|
352975
|
+
const destAbs = resolve8(opts.out ?? join27(".qawolf", opts.env));
|
|
352976
|
+
const assetsAbs = join27(dirname8(destAbs), "assets");
|
|
352560
352977
|
await resolvedDeps.fs.mkdir(assetsAbs, { recursive: true });
|
|
352561
352978
|
const yes = opts.yes ?? false;
|
|
352562
352979
|
let archive;
|
|
@@ -352589,10 +353006,13 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
352589
353006
|
destAbs,
|
|
352590
353007
|
assetsAbs,
|
|
352591
353008
|
envId: opts.env,
|
|
353009
|
+
envSlug: opts.envSlug,
|
|
353010
|
+
envName: opts.envName,
|
|
352592
353011
|
cliFlowsVersion: resolvedDeps.flowsVersion,
|
|
352593
353012
|
now: fetched.bundleFetchedAt,
|
|
352594
353013
|
envVars: fetched.envVars,
|
|
352595
|
-
envVarsFetchedAt: fetched.envVarsFetchedAt
|
|
353014
|
+
envVarsFetchedAt: fetched.envVarsFetchedAt,
|
|
353015
|
+
tags: fetched.tags
|
|
352596
353016
|
}, resolvedDeps.fs)
|
|
352597
353017
|
},
|
|
352598
353018
|
{
|
|
@@ -352612,21 +353032,13 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
352612
353032
|
assetReusedCount: results[1].reusedCount,
|
|
352613
353033
|
assetSkippedCount: results[1].skippedCount
|
|
352614
353034
|
}, assetsAbs));
|
|
352615
|
-
|
|
352616
|
-
|
|
352617
|
-
|
|
352618
|
-
|
|
352619
|
-
|
|
352620
|
-
|
|
352621
|
-
|
|
352622
|
-
envVarCount: result.envVarCount,
|
|
352623
|
-
flowsWithTeamStorageRefs: result.flowsWithTeamStorageRefs,
|
|
352624
|
-
assetDownloadedCount: assetResult.downloadedCount,
|
|
352625
|
-
assetReusedCount: assetResult.reusedCount,
|
|
352626
|
-
assetSkippedCount: assetResult.skippedCount,
|
|
352627
|
-
manifestPath: join25(result.envDir, manifestFilename)
|
|
352628
|
-
}, "");
|
|
352629
|
-
}
|
|
353035
|
+
reportPullResult(ctx.ui, {
|
|
353036
|
+
env: opts.env,
|
|
353037
|
+
assetsAbs,
|
|
353038
|
+
fetchedAt: fetched.bundleFetchedAt,
|
|
353039
|
+
stage: result,
|
|
353040
|
+
assets: assetResult
|
|
353041
|
+
});
|
|
352630
353042
|
} finally {
|
|
352631
353043
|
if (archive !== undefined)
|
|
352632
353044
|
await resolvedDeps.fs.unlink(archive).catch(() => {});
|
|
@@ -352637,16 +353049,25 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
352637
353049
|
var findContract = publicContractsV1.environment.find;
|
|
352638
353050
|
async function pickEnvironment(deps) {
|
|
352639
353051
|
const fetched = await fetchAllEnvironments(deps.platformClient);
|
|
352640
|
-
if (!fetched.ok)
|
|
352641
|
-
return {
|
|
353052
|
+
if (!fetched.ok) {
|
|
353053
|
+
return {
|
|
353054
|
+
...failureFields(fetched),
|
|
353055
|
+
kind: "error",
|
|
353056
|
+
unreachable: fetched.unreachable === true
|
|
353057
|
+
};
|
|
353058
|
+
}
|
|
352642
353059
|
const environments = fetched.environments;
|
|
352643
353060
|
if (environments.length === 0) {
|
|
352644
|
-
return {
|
|
353061
|
+
return {
|
|
353062
|
+
kind: "error",
|
|
353063
|
+
error: environmentsMessages.noEnvironments,
|
|
353064
|
+
unreachable: false
|
|
353065
|
+
};
|
|
352645
353066
|
}
|
|
352646
353067
|
const sole = environments.length === 1 ? environments[0] : undefined;
|
|
352647
353068
|
if (sole) {
|
|
352648
353069
|
deps.ui.info(environmentsMessages.usingEnvironment(sole.name));
|
|
352649
|
-
return
|
|
353070
|
+
return resolvedFrom(sole);
|
|
352650
353071
|
}
|
|
352651
353072
|
const narrowed = await narrowByKind(deps.ui, environments);
|
|
352652
353073
|
if (narrowed === "cancelled")
|
|
@@ -352654,7 +353075,7 @@ async function pickEnvironment(deps) {
|
|
|
352654
353075
|
const soleOfKind = narrowed.length === 1 ? narrowed[0] : undefined;
|
|
352655
353076
|
if (soleOfKind) {
|
|
352656
353077
|
deps.ui.info(environmentsMessages.usingEnvironment(soleOfKind.name));
|
|
352657
|
-
return
|
|
353078
|
+
return resolvedFrom(soleOfKind);
|
|
352658
353079
|
}
|
|
352659
353080
|
const picked = await deps.ui.select(environmentsMessages.whichEnvironment, narrowed.map((e) => ({
|
|
352660
353081
|
value: e.id,
|
|
@@ -352664,7 +353085,16 @@ async function pickEnvironment(deps) {
|
|
|
352664
353085
|
if (!picked.ok)
|
|
352665
353086
|
return { kind: "cancelled" };
|
|
352666
353087
|
deps.ui.info(environmentsMessages.exportHint(picked.value));
|
|
352667
|
-
|
|
353088
|
+
const chosen = narrowed.find((e) => e.id === picked.value);
|
|
353089
|
+
return chosen ? resolvedFrom(chosen) : { kind: "resolved", env: picked.value };
|
|
353090
|
+
}
|
|
353091
|
+
function resolvedFrom(environment) {
|
|
353092
|
+
return {
|
|
353093
|
+
kind: "resolved",
|
|
353094
|
+
env: environment.id,
|
|
353095
|
+
slug: environment.alias ?? undefined,
|
|
353096
|
+
name: environment.name
|
|
353097
|
+
};
|
|
352668
353098
|
}
|
|
352669
353099
|
async function narrowByKind(ui2, environments) {
|
|
352670
353100
|
const byKind = (kind) => environments.filter((e) => e.kind === kind);
|
|
@@ -352689,11 +353119,11 @@ async function narrowByKind(ui2, environments) {
|
|
|
352689
353119
|
return "cancelled";
|
|
352690
353120
|
return picked.value === "static" ? statics : previews;
|
|
352691
353121
|
}
|
|
352692
|
-
var
|
|
353122
|
+
var maxPages2 = 10;
|
|
352693
353123
|
async function fetchAllEnvironments(platformClient) {
|
|
352694
353124
|
const environments = [];
|
|
352695
353125
|
let cursor3;
|
|
352696
|
-
for (let page = 0;page <
|
|
353126
|
+
for (let page = 0;page < maxPages2; page += 1) {
|
|
352697
353127
|
const result = await platformClient.callPublicApi(findContract, {
|
|
352698
353128
|
limit: 100,
|
|
352699
353129
|
cursor: cursor3
|
|
@@ -352705,7 +353135,7 @@ async function fetchAllEnvironments(platformClient) {
|
|
|
352705
353135
|
if (cursor3 === undefined)
|
|
352706
353136
|
return { ok: true, environments };
|
|
352707
353137
|
}
|
|
352708
|
-
return { ok: false, error: environmentsMessages.tooManyPages(
|
|
353138
|
+
return { ok: false, error: environmentsMessages.tooManyPages(maxPages2) };
|
|
352709
353139
|
}
|
|
352710
353140
|
|
|
352711
353141
|
// src/domains/environments/resolveEnvironment.ts
|
|
@@ -352721,7 +353151,7 @@ async function resolveEnvironment(deps, opts) {
|
|
|
352721
353151
|
return resolveRef2(deps, fromEnvVar);
|
|
352722
353152
|
}
|
|
352723
353153
|
if (deps.ui.mode !== "human") {
|
|
352724
|
-
return { kind: "error", error: opts.requiredMessage };
|
|
353154
|
+
return { kind: "error", error: opts.requiredMessage, unreachable: false };
|
|
352725
353155
|
}
|
|
352726
353156
|
return pickEnvironment(deps);
|
|
352727
353157
|
}
|
|
@@ -352733,16 +353163,27 @@ async function resolveRef2(deps, ref) {
|
|
|
352733
353163
|
return {
|
|
352734
353164
|
...failureFields(result),
|
|
352735
353165
|
kind: "error",
|
|
352736
|
-
error: environmentsMessages.couldNotResolve(ref, result.error)
|
|
353166
|
+
error: environmentsMessages.couldNotResolve(ref, result.error),
|
|
353167
|
+
unreachable: result.unreachable === true
|
|
352737
353168
|
};
|
|
352738
353169
|
}
|
|
352739
353170
|
if (result.value.id !== ref) {
|
|
352740
353171
|
deps.ui.info(environmentsMessages.resolvedAlias(ref, result.value.id));
|
|
352741
353172
|
}
|
|
352742
|
-
return {
|
|
353173
|
+
return {
|
|
353174
|
+
kind: "resolved",
|
|
353175
|
+
env: result.value.id,
|
|
353176
|
+
slug: result.value.alias ?? undefined,
|
|
353177
|
+
name: result.value.name
|
|
353178
|
+
};
|
|
352743
353179
|
}
|
|
352744
353180
|
|
|
352745
353181
|
// src/commands/flows/withResolvedEnv.ts
|
|
353182
|
+
async function pulledEnvFallback(outcome, explicit, offlineFallback) {
|
|
353183
|
+
if (!outcome.unreachable)
|
|
353184
|
+
return;
|
|
353185
|
+
return offlineFallback?.(explicit);
|
|
353186
|
+
}
|
|
352746
353187
|
function withResolvedEnv(signals, args, fn) {
|
|
352747
353188
|
return (opts, command) => {
|
|
352748
353189
|
const pickerNeeded = !args.explicit?.trim() && !(process.env["QAWOLF_ENVIRONMENT"] ?? "").trim();
|
|
@@ -352765,9 +353206,17 @@ function withResolvedEnv(signals, args, fn) {
|
|
|
352765
353206
|
return;
|
|
352766
353207
|
}
|
|
352767
353208
|
if (outcome.kind === "error") {
|
|
353209
|
+
const pulled = await pulledEnvFallback(outcome, args.explicit, args.offlineFallback);
|
|
353210
|
+
if (pulled !== undefined) {
|
|
353211
|
+
ctx.ui.warn(environmentsMessages.usingPulledEnv(pulled));
|
|
353212
|
+
return fn(ctx, pulled, { slug: undefined, name: undefined });
|
|
353213
|
+
}
|
|
352768
353214
|
return failureFields(outcome);
|
|
352769
353215
|
}
|
|
352770
|
-
return fn(ctx, outcome.env
|
|
353216
|
+
return fn(ctx, outcome.env, {
|
|
353217
|
+
slug: outcome.slug,
|
|
353218
|
+
name: outcome.name
|
|
353219
|
+
});
|
|
352771
353220
|
})(opts, command);
|
|
352772
353221
|
};
|
|
352773
353222
|
}
|
|
@@ -352780,30 +353229,37 @@ Examples:
|
|
|
352780
353229
|
$ qawolf flows pull --env staging --yes`;
|
|
352781
353230
|
function registerFlowsPullCommand(flows, signals) {
|
|
352782
353231
|
declareCommandKind(flows.command("pull"), "read").description("Download an environment's flows into the local .qawolf/<env>/ cache").option("--env <env>", "Environment to pull from (UUID or kebab-case slug); defaults to QAWOLF_ENVIRONMENT, or an interactive picker").option("--out <path>", "Destination directory (defaults to .qawolf/<env>/)").option("--yes", "Overwrite locally-modified files without prompting", false).addHelpText("after", pullExamples).action((opts, command) => {
|
|
352783
|
-
return withResolvedEnv(signals, { explicit: opts.env, requiredMessage: flowsMessages.pull.requiresEnv }, (ctx, env2) => handleFlowsPull(ctx, {
|
|
353232
|
+
return withResolvedEnv(signals, { explicit: opts.env, requiredMessage: flowsMessages.pull.requiresEnv }, (ctx, env2, identity) => handleFlowsPull(ctx, {
|
|
353233
|
+
...opts,
|
|
353234
|
+
env: env2,
|
|
353235
|
+
envSlug: identity.slug,
|
|
353236
|
+
envName: identity.name
|
|
353237
|
+
}))(opts, command);
|
|
352784
353238
|
});
|
|
352785
353239
|
}
|
|
352786
353240
|
|
|
352787
|
-
// src/
|
|
352788
|
-
|
|
352789
|
-
|
|
352790
|
-
|
|
352791
|
-
|
|
352792
|
-
|
|
352793
|
-
|
|
352794
|
-
|
|
352795
|
-
|
|
352796
|
-
|
|
352797
|
-
|
|
352798
|
-
};
|
|
353241
|
+
// src/commands/flows/runArtifactOptions.ts
|
|
353242
|
+
var videoModes = ["on", "off", "retain-on-failure"];
|
|
353243
|
+
var traceModes = ["on", "off", "retain-on-failure"];
|
|
353244
|
+
var harModes = ["on", "off", "retain-on-failure"];
|
|
353245
|
+
var harContentModes = ["full", "omit"];
|
|
353246
|
+
var videoDefault = "off";
|
|
353247
|
+
var traceDefault = "off";
|
|
353248
|
+
var harDefault = "off";
|
|
353249
|
+
var harContentDefault = "omit";
|
|
353250
|
+
function addRunArtifactOptions(command) {
|
|
353251
|
+
return command.option("--video <mode>", "Record video: on | off | retain-on-failure", parseEnum("--video", videoModes), videoDefault).option("--trace <mode>", "Record Playwright trace: on | off | retain-on-failure", parseEnum("--trace", traceModes), traceDefault).option("--har <mode>", "Record HAR network log: on | off | retain-on-failure", parseEnum("--har", harModes), harDefault).option("--har-content <mode>", "HAR response bodies: omit | full (full uses more memory)", parseEnum("--har-content", harContentModes), harContentDefault).option("--output-dir <path>", "Directory for run artifacts (videos, traces, HAR)", defaultOutputDir).option("--junit [path]", "Write a JUnit XML report (default: <output-dir>/junit-report.xml)");
|
|
352799
353252
|
}
|
|
352800
|
-
|
|
352801
|
-
|
|
352802
|
-
|
|
352803
|
-
|
|
352804
|
-
|
|
352805
|
-
|
|
352806
|
-
|
|
353253
|
+
|
|
353254
|
+
// src/domains/flows/allEnvsWarning.ts
|
|
353255
|
+
function allEnvsNoEffectWarning(args) {
|
|
353256
|
+
if (!args.allEnvs)
|
|
353257
|
+
return;
|
|
353258
|
+
if (args.env !== undefined)
|
|
353259
|
+
return flowsMessages.selectors.allEnvsWithEnv;
|
|
353260
|
+
if (args.tags.length === 0)
|
|
353261
|
+
return flowsMessages.selectors.allEnvsWithoutTag;
|
|
353262
|
+
return;
|
|
352807
353263
|
}
|
|
352808
353264
|
|
|
352809
353265
|
// src/core/patternArgs.ts
|
|
@@ -352811,6 +353267,44 @@ function buildPatternArgs(pattern) {
|
|
|
352811
353267
|
return pattern ? [pattern] : [];
|
|
352812
353268
|
}
|
|
352813
353269
|
|
|
353270
|
+
// src/domains/flows/resolveEnvChoice.ts
|
|
353271
|
+
var allValue = "all";
|
|
353272
|
+
async function resolveEnvChoice(args) {
|
|
353273
|
+
const byEnv = new Map;
|
|
353274
|
+
for (const file2 of args.files) {
|
|
353275
|
+
const key = findPulledEnvDir(file2) ?? "";
|
|
353276
|
+
const group = byEnv.get(key);
|
|
353277
|
+
if (group)
|
|
353278
|
+
group.push(file2);
|
|
353279
|
+
else
|
|
353280
|
+
byEnv.set(key, [file2]);
|
|
353281
|
+
}
|
|
353282
|
+
const envDirs = [...byEnv.keys()].filter((key) => key !== "");
|
|
353283
|
+
if (envDirs.length <= 1 || args.allEnvs) {
|
|
353284
|
+
return { kind: "proceed", files: [...args.files] };
|
|
353285
|
+
}
|
|
353286
|
+
const labels = await Promise.all(envDirs.map(async (dir) => ({ dir, label: await args.readLabel(dir) })));
|
|
353287
|
+
if (args.mode !== "human") {
|
|
353288
|
+
return {
|
|
353289
|
+
kind: "error",
|
|
353290
|
+
error: flowsMessages.selectors.ambiguousEnvs(labels.map((l2) => l2.label))
|
|
353291
|
+
};
|
|
353292
|
+
}
|
|
353293
|
+
const picked = await args.select(flowsMessages.selectors.chooseEnv, [
|
|
353294
|
+
...labels.map(({ dir, label }) => ({ value: dir, label })),
|
|
353295
|
+
{ value: allValue, label: "All" }
|
|
353296
|
+
]);
|
|
353297
|
+
if (!picked.ok)
|
|
353298
|
+
return { kind: "cancelled" };
|
|
353299
|
+
if (picked.value === allValue) {
|
|
353300
|
+
return { kind: "proceed", files: [...args.files] };
|
|
353301
|
+
}
|
|
353302
|
+
return {
|
|
353303
|
+
kind: "proceed",
|
|
353304
|
+
files: [...byEnv.get("") ?? [], ...byEnv.get(picked.value) ?? []]
|
|
353305
|
+
};
|
|
353306
|
+
}
|
|
353307
|
+
|
|
352814
353308
|
// src/core/flowFailureHint.ts
|
|
352815
353309
|
function flowFailureHint(errText, projectDir) {
|
|
352816
353310
|
const missingPackage = extractMissingPackage(errText);
|
|
@@ -353354,15 +353848,15 @@ async function defaultRunWebFlowDeps(envDir = process.cwd(), signals) {
|
|
|
353354
353848
|
|
|
353355
353849
|
// src/domains/runtimeEnv/prepareRunDir.ts
|
|
353356
353850
|
import { createHash as createHash4 } from "node:crypto";
|
|
353357
|
-
import { join as
|
|
353851
|
+
import { join as join35, resolve as resolve9 } from "node:path";
|
|
353358
353852
|
|
|
353359
353853
|
// src/domains/runtimeEnv/execSubpathImports.ts
|
|
353360
|
-
import { join as
|
|
353854
|
+
import { join as join28 } from "node:path";
|
|
353361
353855
|
var flowSubpathImports = { "#playwright": "playwright" };
|
|
353362
353856
|
var packageJsonSchema = exports_external.looseObject({ imports: exports_external.record(exports_external.string(), exports_external.unknown()).catch({}) }).catch({ imports: {} });
|
|
353363
353857
|
async function writeExecSubpathImports(args) {
|
|
353364
353858
|
const { execDir, fs: fs4 } = args;
|
|
353365
|
-
const pkgPath =
|
|
353859
|
+
const pkgPath = join28(execDir, "package.json");
|
|
353366
353860
|
const pkg = packageJsonSchema.parse(await readPackageJson(pkgPath, fs4));
|
|
353367
353861
|
const merged = { ...pkg, imports: { ...pkg.imports, ...flowSubpathImports } };
|
|
353368
353862
|
await fs4.writeFile(pkgPath, JSON.stringify(merged, undefined, 2));
|
|
@@ -353384,10 +353878,10 @@ async function readPackageJson(pkgPath, fs4) {
|
|
|
353384
353878
|
}
|
|
353385
353879
|
|
|
353386
353880
|
// src/domains/runtimeEnv/innerHop.ts
|
|
353387
|
-
import { join as
|
|
353881
|
+
import { join as join30 } from "node:path";
|
|
353388
353882
|
|
|
353389
353883
|
// src/domains/runtimeEnv/linkPinnedPackages.ts
|
|
353390
|
-
import { dirname as
|
|
353884
|
+
import { dirname as dirname9, join as join29 } from "node:path";
|
|
353391
353885
|
|
|
353392
353886
|
// src/domains/runtimeEnv/symlinkDir.ts
|
|
353393
353887
|
import { symlink } from "node:fs/promises";
|
|
@@ -353399,16 +353893,16 @@ async function createDirSymlink(source, target) {
|
|
|
353399
353893
|
// src/domains/runtimeEnv/linkPinnedPackages.ts
|
|
353400
353894
|
async function linkPinnedPackages(args) {
|
|
353401
353895
|
const { depsRoot, nodeModulesDir, fs: fs4 } = args;
|
|
353402
|
-
const managedModules =
|
|
353896
|
+
const managedModules = join29(depsRoot, "node_modules");
|
|
353403
353897
|
await fs4.mkdir(nodeModulesDir, { recursive: true });
|
|
353404
353898
|
for (const { name } of pinnedPackages) {
|
|
353405
353899
|
const segments = name.split("/");
|
|
353406
|
-
const target =
|
|
353900
|
+
const target = join29(nodeModulesDir, ...segments);
|
|
353407
353901
|
if (segments.length > 1) {
|
|
353408
|
-
await fs4.mkdir(
|
|
353902
|
+
await fs4.mkdir(dirname9(target), { recursive: true });
|
|
353409
353903
|
}
|
|
353410
353904
|
await fs4.rm(target, { recursive: true, force: true });
|
|
353411
|
-
await createDirSymlink(
|
|
353905
|
+
await createDirSymlink(join29(managedModules, ...segments), target);
|
|
353412
353906
|
}
|
|
353413
353907
|
}
|
|
353414
353908
|
|
|
@@ -353417,18 +353911,18 @@ async function populateInnerHop(args) {
|
|
|
353417
353911
|
const { depsRoot, execDir, fs: fs4 } = args;
|
|
353418
353912
|
await linkPinnedPackages({
|
|
353419
353913
|
depsRoot,
|
|
353420
|
-
nodeModulesDir:
|
|
353914
|
+
nodeModulesDir: join30(execDir, "node_modules"),
|
|
353421
353915
|
fs: fs4
|
|
353422
353916
|
});
|
|
353423
353917
|
}
|
|
353424
353918
|
|
|
353425
353919
|
// src/domains/runtimeEnv/outerHop.ts
|
|
353426
353920
|
import { lstat as lstat2 } from "node:fs/promises";
|
|
353427
|
-
import { dirname as
|
|
353921
|
+
import { dirname as dirname11, join as join32 } from "node:path";
|
|
353428
353922
|
|
|
353429
353923
|
// src/domains/runtimeEnv/carryOverPackages.ts
|
|
353430
353924
|
import { lstat } from "node:fs/promises";
|
|
353431
|
-
import { dirname as
|
|
353925
|
+
import { dirname as dirname10, join as join31 } from "node:path";
|
|
353432
353926
|
|
|
353433
353927
|
// src/domains/runtimeEnv/carryOverPlan.ts
|
|
353434
353928
|
var executorPackageNames = new Set(pinnedPackages.map((p3) => p3.name));
|
|
@@ -353450,12 +353944,12 @@ async function carryOverPackages(args) {
|
|
|
353450
353944
|
const linked = [];
|
|
353451
353945
|
for (const name of names) {
|
|
353452
353946
|
const segments = name.split("/");
|
|
353453
|
-
const target =
|
|
353947
|
+
const target = join31(nodeModulesDir, ...segments);
|
|
353454
353948
|
if (await pathOccupied(target))
|
|
353455
353949
|
continue;
|
|
353456
353950
|
if (segments.length > 1)
|
|
353457
|
-
await fs4.mkdir(
|
|
353458
|
-
await createDirSymlink(
|
|
353951
|
+
await fs4.mkdir(dirname10(target), { recursive: true });
|
|
353952
|
+
await createDirSymlink(join31(projectModulesDir, ...segments), target);
|
|
353459
353953
|
linked.push(name);
|
|
353460
353954
|
}
|
|
353461
353955
|
return linked;
|
|
@@ -353478,18 +353972,18 @@ async function listPackageNames(dir, fs4) {
|
|
|
353478
353972
|
const names = [];
|
|
353479
353973
|
for (const entry of entries) {
|
|
353480
353974
|
if (!entry.startsWith("@")) {
|
|
353481
|
-
if (fs4.existsSync(
|
|
353975
|
+
if (fs4.existsSync(join31(dir, entry, "package.json")))
|
|
353482
353976
|
names.push(entry);
|
|
353483
353977
|
continue;
|
|
353484
353978
|
}
|
|
353485
353979
|
let scoped;
|
|
353486
353980
|
try {
|
|
353487
|
-
scoped = await fs4.readdir(
|
|
353981
|
+
scoped = await fs4.readdir(join31(dir, entry));
|
|
353488
353982
|
} catch {
|
|
353489
353983
|
continue;
|
|
353490
353984
|
}
|
|
353491
353985
|
for (const inner of scoped) {
|
|
353492
|
-
if (fs4.existsSync(
|
|
353986
|
+
if (fs4.existsSync(join31(dir, entry, inner, "package.json"))) {
|
|
353493
353987
|
names.push(`${entry}/${inner}`);
|
|
353494
353988
|
}
|
|
353495
353989
|
}
|
|
@@ -353507,7 +354001,7 @@ async function populateOuterHop(args) {
|
|
|
353507
354001
|
const depNames = Object.keys(installableDeps);
|
|
353508
354002
|
const { satisfying, rejected } = await findSatisfyingNodeModulesDir(projectDir, depNames, fs4);
|
|
353509
354003
|
if (satisfying !== undefined) {
|
|
353510
|
-
await createDirSymlink(satisfying,
|
|
354004
|
+
await createDirSymlink(satisfying, join32(runDir, "node_modules"));
|
|
353511
354005
|
return { mode: "symlink", nodeModulesDir: satisfying };
|
|
353512
354006
|
}
|
|
353513
354007
|
if (depNames.length === 0)
|
|
@@ -353516,12 +354010,12 @@ async function populateOuterHop(args) {
|
|
|
353516
354010
|
await installOuterDeps(runDir, installableDeps, fs4, args.install ?? spawnNpmInstall);
|
|
353517
354011
|
await linkPinnedPackages({
|
|
353518
354012
|
depsRoot: args.depsRoot,
|
|
353519
|
-
nodeModulesDir:
|
|
354013
|
+
nodeModulesDir: join32(runDir, "node_modules"),
|
|
353520
354014
|
fs: fs4
|
|
353521
354015
|
});
|
|
353522
354016
|
const carriedOver = await carryOverPackages({
|
|
353523
|
-
projectModulesDir:
|
|
353524
|
-
nodeModulesDir:
|
|
354017
|
+
projectModulesDir: join32(projectDir, "node_modules"),
|
|
354018
|
+
nodeModulesDir: join32(runDir, "node_modules"),
|
|
353525
354019
|
fs: fs4
|
|
353526
354020
|
});
|
|
353527
354021
|
return { mode: "install", depCount: depNames.length, rejected, carriedOver };
|
|
@@ -353530,15 +354024,15 @@ async function findSatisfyingNodeModulesDir(startDir, depNames, fs4) {
|
|
|
353530
354024
|
const rejected = [];
|
|
353531
354025
|
let dir = startDir;
|
|
353532
354026
|
while (true) {
|
|
353533
|
-
const candidate =
|
|
354027
|
+
const candidate = join32(dir, "node_modules");
|
|
353534
354028
|
const stats = await lstatSafe(candidate);
|
|
353535
354029
|
if (stats !== undefined && stats.isDirectory() && !stats.isSymbolicLink()) {
|
|
353536
|
-
const missing = depNames.filter((name) => !fs4.existsSync(
|
|
354030
|
+
const missing = depNames.filter((name) => !fs4.existsSync(join32(candidate, name, "package.json")));
|
|
353537
354031
|
if (missing.length === 0)
|
|
353538
354032
|
return { satisfying: candidate, rejected };
|
|
353539
354033
|
rejected.push({ dir: candidate, missing });
|
|
353540
354034
|
}
|
|
353541
|
-
const parent =
|
|
354035
|
+
const parent = dirname11(dir);
|
|
353542
354036
|
if (parent === dir)
|
|
353543
354037
|
return { satisfying: undefined, rejected };
|
|
353544
354038
|
dir = parent;
|
|
@@ -353554,7 +354048,7 @@ async function lstatSafe(path3) {
|
|
|
353554
354048
|
async function readInstallableDeps(projectDir, fs4) {
|
|
353555
354049
|
let content;
|
|
353556
354050
|
try {
|
|
353557
|
-
content = await fs4.readFile(
|
|
354051
|
+
content = await fs4.readFile(join32(projectDir, "package.json"));
|
|
353558
354052
|
} catch {
|
|
353559
354053
|
return {};
|
|
353560
354054
|
}
|
|
@@ -353572,8 +354066,8 @@ async function readInstallableDeps(projectDir, fs4) {
|
|
|
353572
354066
|
return Object.fromEntries(Object.entries(rawDeps).filter(([name]) => !executorPackageNames2.has(name)).filter((entry) => typeof entry[1] === "string"));
|
|
353573
354067
|
}
|
|
353574
354068
|
async function installOuterDeps(runDir, deps, fs4, install) {
|
|
353575
|
-
await fs4.writeFile(
|
|
353576
|
-
await fs4.writeFile(
|
|
354069
|
+
await fs4.writeFile(join32(runDir, "package.json"), JSON.stringify({ name: "qawolf-run", private: true, dependencies: deps }, undefined, 2));
|
|
354070
|
+
await fs4.writeFile(join32(runDir, ".npmrc"), `@qawolf:registry=https://registry.npmjs.org/
|
|
353577
354071
|
`);
|
|
353578
354072
|
const result = await install(runDir);
|
|
353579
354073
|
if (result.exitCode !== 0) {
|
|
@@ -353583,16 +354077,16 @@ async function installOuterDeps(runDir, deps, fs4, install) {
|
|
|
353583
354077
|
|
|
353584
354078
|
// src/domains/runtimeEnv/stageFlowFiles.ts
|
|
353585
354079
|
import { createHash as createHash3 } from "node:crypto";
|
|
353586
|
-
import { basename as
|
|
354080
|
+
import { basename as basename6, dirname as dirname12, join as join34, sep as sep4 } from "node:path";
|
|
353587
354081
|
|
|
353588
354082
|
// src/shell/copyDir.ts
|
|
353589
354083
|
import { cp, readdir as readdir2 } from "node:fs/promises";
|
|
353590
|
-
import { basename as
|
|
354084
|
+
import { basename as basename5, join as join33 } from "node:path";
|
|
353591
354085
|
async function copyDirExcluding(source, destination, excludedNames) {
|
|
353592
354086
|
const entries = await readdir2(source, { withFileTypes: true });
|
|
353593
|
-
await Promise.all(entries.filter((entry) => !excludedNames.has(entry.name)).map((entry) => cp(
|
|
354087
|
+
await Promise.all(entries.filter((entry) => !excludedNames.has(entry.name)).map((entry) => cp(join33(source, entry.name), join33(destination, entry.name), {
|
|
353594
354088
|
recursive: true,
|
|
353595
|
-
filter: (path3) => !excludedNames.has(
|
|
354089
|
+
filter: (path3) => !excludedNames.has(basename5(path3))
|
|
353596
354090
|
})));
|
|
353597
354091
|
}
|
|
353598
354092
|
|
|
@@ -353607,14 +354101,14 @@ async function stageFlowFiles(args) {
|
|
|
353607
354101
|
if (files.length > 1) {
|
|
353608
354102
|
return Promise.all(files.map((f3) => stageOneFile(f3, execDir, fs4)));
|
|
353609
354103
|
}
|
|
353610
|
-
await Promise.all(files.map((f3) => fs4.copyFile(f3,
|
|
353611
|
-
return files.map((f3) =>
|
|
354104
|
+
await Promise.all(files.map((f3) => fs4.copyFile(f3, join34(execDir, basename6(f3)))));
|
|
354105
|
+
return files.map((f3) => join34(execDir, basename6(f3)));
|
|
353612
354106
|
}
|
|
353613
354107
|
async function stageOneFile(file2, execDir, fs4) {
|
|
353614
|
-
const dirHash = createHash3("sha256").update(
|
|
353615
|
-
const subDir =
|
|
354108
|
+
const dirHash = createHash3("sha256").update(dirname12(file2)).digest("hex").slice(0, 8);
|
|
354109
|
+
const subDir = join34(execDir, dirHash);
|
|
353616
354110
|
await fs4.mkdir(subDir, { recursive: true });
|
|
353617
|
-
const dest =
|
|
354111
|
+
const dest = join34(subDir, basename6(file2));
|
|
353618
354112
|
await fs4.copyFile(file2, dest);
|
|
353619
354113
|
return dest;
|
|
353620
354114
|
}
|
|
@@ -353622,7 +354116,7 @@ function remapPath(file2, projectDir, execDir) {
|
|
|
353622
354116
|
if (file2 === projectDir)
|
|
353623
354117
|
return execDir;
|
|
353624
354118
|
if (file2.startsWith(projectDir + sep4)) {
|
|
353625
|
-
return
|
|
354119
|
+
return join34(execDir, file2.slice(projectDir.length + 1));
|
|
353626
354120
|
}
|
|
353627
354121
|
return;
|
|
353628
354122
|
}
|
|
@@ -353632,10 +354126,10 @@ async function prepareRunDir(args) {
|
|
|
353632
354126
|
const { files, projectDir, depsRoot, runRoot } = args;
|
|
353633
354127
|
const fs4 = args.fs ?? makeDefaultFs();
|
|
353634
354128
|
const runId = buildRunId(projectDir, files);
|
|
353635
|
-
const runDir =
|
|
354129
|
+
const runDir = join35(runRoot, runId);
|
|
353636
354130
|
await fs4.rm(runDir, { recursive: true, force: true });
|
|
353637
354131
|
await fs4.mkdir(runDir, { recursive: true });
|
|
353638
|
-
const execDir =
|
|
354132
|
+
const execDir = join35(runDir, "exec");
|
|
353639
354133
|
await fs4.mkdir(execDir, { recursive: true });
|
|
353640
354134
|
await populateInnerHop({ depsRoot, execDir, fs: fs4 });
|
|
353641
354135
|
const stagedFiles = await stageFlowFiles({ files, projectDir, execDir, fs: fs4 });
|
|
@@ -353666,17 +354160,17 @@ function buildRunId(projectDir, files) {
|
|
|
353666
354160
|
}
|
|
353667
354161
|
|
|
353668
354162
|
// src/shell/testkit.ts
|
|
353669
|
-
import { join as
|
|
354163
|
+
import { join as join36 } from "node:path";
|
|
353670
354164
|
function notAvailableLocally(name) {
|
|
353671
354165
|
throw new Error(runnerMessages.notAvailableLocally(name));
|
|
353672
354166
|
}
|
|
353673
354167
|
async function loadSdkDeps(cwd) {
|
|
353674
|
-
const testkitDir =
|
|
354168
|
+
const testkitDir = join36(cwd, "node_modules", "@qawolf", "testkit");
|
|
353675
354169
|
try {
|
|
353676
354170
|
const clientMod = await importFromPath(resolveFromEnvDir(cwd, "@qawolf/testkit/client"));
|
|
353677
354171
|
if (typeof clientMod.createTestkitClient !== "function")
|
|
353678
354172
|
throw new Error("createTestkitClient is not a function");
|
|
353679
|
-
const scopeMod = await importFromPath(
|
|
354173
|
+
const scopeMod = await importFromPath(join36(testkitDir, "dist", "clientScope.js"));
|
|
353680
354174
|
if (typeof scopeMod.configureTestkitClient !== "function")
|
|
353681
354175
|
throw new Error("configureTestkitClient is not a function");
|
|
353682
354176
|
return {
|
|
@@ -353734,9 +354228,9 @@ async function registerLazyEmailsClient(getInbox, cwd, deps) {
|
|
|
353734
354228
|
}
|
|
353735
354229
|
|
|
353736
354230
|
// src/commands/flows/envVarDeps.ts
|
|
353737
|
-
import { join as
|
|
354231
|
+
import { join as join37 } from "node:path";
|
|
353738
354232
|
function envFilePath(envDir) {
|
|
353739
|
-
return
|
|
354233
|
+
return join37(envDir, ".env");
|
|
353740
354234
|
}
|
|
353741
354235
|
async function readEnv(envDir, fs4) {
|
|
353742
354236
|
try {
|
|
@@ -353840,8 +354334,27 @@ async function createFlowRuntimeDeps({
|
|
|
353840
354334
|
};
|
|
353841
354335
|
}
|
|
353842
354336
|
|
|
354337
|
+
// src/domains/flows/selectRunByTag.ts
|
|
354338
|
+
async function selectRunByTag(args) {
|
|
354339
|
+
if (!hasSelectors(args.selectors))
|
|
354340
|
+
return { ok: true, files: args.files };
|
|
354341
|
+
const cachedTags = await args.readCachedTags(args.files);
|
|
354342
|
+
const notCached = tagsNotCachedResult(args.selectors, cachedTags);
|
|
354343
|
+
if (notCached !== undefined)
|
|
354344
|
+
return { ok: false, result: notCached };
|
|
354345
|
+
const matched = args.files.filter((file2) => matchesSelectors({ tags: cachedTags.get(file2) }, args.selectors));
|
|
354346
|
+
if (matched.length === 0) {
|
|
354347
|
+
return {
|
|
354348
|
+
ok: false,
|
|
354349
|
+
result: args.noMatch(explainEmptySelection(args.selectors))
|
|
354350
|
+
};
|
|
354351
|
+
}
|
|
354352
|
+
const choice = await args.chooseEnv(matched);
|
|
354353
|
+
return "proceed" in choice ? { ok: true, files: choice.proceed } : { ok: false, result: choice.stop };
|
|
354354
|
+
}
|
|
354355
|
+
|
|
353843
354356
|
// src/commands/flows/runStagedFlows.ts
|
|
353844
|
-
import { join as
|
|
354357
|
+
import { join as join41 } from "node:path";
|
|
353845
354358
|
|
|
353846
354359
|
// src/shell/appium/createAppiumServer.ts
|
|
353847
354360
|
import { existsSync as existsSync2 } from "node:fs";
|
|
@@ -354206,25 +354719,16 @@ Install Android Studio and open Tools > SDK Manager.`);
|
|
|
354206
354719
|
}
|
|
354207
354720
|
|
|
354208
354721
|
// src/shell/manifest/lookup.ts
|
|
354209
|
-
import {
|
|
354722
|
+
import { relative as relative8 } from "node:path";
|
|
354210
354723
|
async function findFlowStamp(flowAbsPath) {
|
|
354211
|
-
|
|
354212
|
-
let current = dirname12(flowAbsPath);
|
|
354213
|
-
while (current !== dirname12(current)) {
|
|
354214
|
-
const parent2 = dirname12(current);
|
|
354215
|
-
if (basename5(parent2) === ".qawolf") {
|
|
354216
|
-
envDir = current;
|
|
354217
|
-
break;
|
|
354218
|
-
}
|
|
354219
|
-
current = parent2;
|
|
354220
|
-
}
|
|
354724
|
+
const envDir = findPulledEnvDir(flowAbsPath);
|
|
354221
354725
|
if (!envDir)
|
|
354222
354726
|
return;
|
|
354223
354727
|
const manifest = await readManifest(envDir);
|
|
354224
354728
|
if (typeof manifest === "string")
|
|
354225
354729
|
return;
|
|
354226
|
-
const relPath =
|
|
354227
|
-
const entry = manifest.flows.find((f3) => f3.path === relPath);
|
|
354730
|
+
const relPath = toPosix(relative8(envDir, flowAbsPath));
|
|
354731
|
+
const entry = manifest.flows.find((f3) => toPosix(f3.path) === relPath);
|
|
354228
354732
|
if (!entry)
|
|
354229
354733
|
return;
|
|
354230
354734
|
return {
|
|
@@ -355143,14 +355647,14 @@ async function runWebFlow({
|
|
|
355143
355647
|
|
|
355144
355648
|
// src/shell/embeddedWorkerCli.ts
|
|
355145
355649
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
355146
|
-
import { basename as
|
|
355650
|
+
import { basename as basename7, join as join38 } from "node:path";
|
|
355147
355651
|
var embeddedCliPathEnv = "QAWOLF_EMBEDDED_CLI_PATH";
|
|
355148
355652
|
function extractEmbeddedWorkerCli() {
|
|
355149
355653
|
const assetPath = process.env[embeddedCliPathEnv];
|
|
355150
355654
|
if (assetPath === undefined || assetPath === "")
|
|
355151
355655
|
return;
|
|
355152
|
-
const dir =
|
|
355153
|
-
const dest =
|
|
355656
|
+
const dir = join38(getDataDir(), "worker");
|
|
355657
|
+
const dest = join38(dir, basename7(assetPath));
|
|
355154
355658
|
if (existsSync3(dest))
|
|
355155
355659
|
return dest;
|
|
355156
355660
|
mkdirSync3(dir, { recursive: true });
|
|
@@ -355388,7 +355892,7 @@ ${styleText3("dim", "─".repeat(width))}
|
|
|
355388
355892
|
};
|
|
355389
355893
|
}
|
|
355390
355894
|
// src/shell/reporter/createJUnitReporter.ts
|
|
355391
|
-
import { join as
|
|
355895
|
+
import { join as join39 } from "node:path";
|
|
355392
355896
|
|
|
355393
355897
|
// src/shell/reporter/junitXml.ts
|
|
355394
355898
|
function escapeXml(str) {
|
|
@@ -355427,7 +355931,7 @@ ${suites}`;
|
|
|
355427
355931
|
|
|
355428
355932
|
// src/shell/reporter/createJUnitReporter.ts
|
|
355429
355933
|
function resolveJUnitOutputPath(junit, outputDir) {
|
|
355430
|
-
return typeof junit === "string" && junit.trim() !== "" ? junit :
|
|
355934
|
+
return typeof junit === "string" && junit.trim() !== "" ? junit : join39(outputDir, "junit-report.xml");
|
|
355431
355935
|
}
|
|
355432
355936
|
function createJUnitReporter(deps) {
|
|
355433
355937
|
const flows = [];
|
|
@@ -355518,11 +356022,11 @@ function buildFlowsRunDeps(args) {
|
|
|
355518
356022
|
|
|
355519
356023
|
// src/commands/flows/loadEnvFile.ts
|
|
355520
356024
|
import { readFile } from "node:fs/promises";
|
|
355521
|
-
import { join as
|
|
356025
|
+
import { join as join40 } from "node:path";
|
|
355522
356026
|
async function loadEnvFile(envDir) {
|
|
355523
356027
|
let content;
|
|
355524
356028
|
try {
|
|
355525
|
-
content = await readFile(
|
|
356029
|
+
content = await readFile(join40(envDir, ".env"), "utf8");
|
|
355526
356030
|
} catch (err) {
|
|
355527
356031
|
if (isNoEntError(err))
|
|
355528
356032
|
return;
|
|
@@ -355567,7 +356071,7 @@ async function runStagedFlows(args) {
|
|
|
355567
356071
|
for (const candidate of staged.outerHop.rejected) {
|
|
355568
356072
|
log31.debug(runnerMessages.outerHopCandidateRejected(candidate.dir, candidate.missing));
|
|
355569
356073
|
}
|
|
355570
|
-
const ownModules = projectDir === undefined ? undefined :
|
|
356074
|
+
const ownModules = projectDir === undefined ? undefined : join41(projectDir, "node_modules");
|
|
355571
356075
|
const own = staged.outerHop.rejected.find((c3) => c3.dir === ownModules);
|
|
355572
356076
|
if (own !== undefined) {
|
|
355573
356077
|
ctx.ui.warn(runnerMessages.outerHopFallbackNotice(own.dir, own.missing));
|
|
@@ -355613,7 +356117,7 @@ function makeDefaultDeps2(fs9) {
|
|
|
355613
356117
|
flowsRun
|
|
355614
356118
|
};
|
|
355615
356119
|
}
|
|
355616
|
-
async function handleFlowsRun(ctx, pattern, flags, deps) {
|
|
356120
|
+
async function handleFlowsRun(ctx, pattern, flags, deps, selectors = { tags: [] }, allEnvs = false) {
|
|
355617
356121
|
const resolvedDeps = deps ?? makeDefaultDeps2(ctx.fs);
|
|
355618
356122
|
const cwd = process.cwd();
|
|
355619
356123
|
const expandedFiles = await resolvedDeps.expandPatterns(buildPatternArgs(pattern), cwd, ctx.log("flows"));
|
|
@@ -355625,20 +356129,133 @@ async function handleFlowsRun(ctx, pattern, flags, deps) {
|
|
|
355625
356129
|
notice: runnerMessages.noFlowsMatched
|
|
355626
356130
|
});
|
|
355627
356131
|
}
|
|
356132
|
+
const selected = await selectRunByTag({
|
|
356133
|
+
files: expandedFiles,
|
|
356134
|
+
selectors,
|
|
356135
|
+
readCachedTags: (files) => readCachedTags(files, ctx.fs),
|
|
356136
|
+
chooseEnv: (files) => chooseEnv(ctx, files, allEnvs),
|
|
356137
|
+
noMatch: (error51) => noMatchResult(ctx, {
|
|
356138
|
+
allowNoMatch: flags.allowNoMatch,
|
|
356139
|
+
error: error51,
|
|
356140
|
+
notice: runnerMessages.noFlowsMatched
|
|
356141
|
+
})
|
|
356142
|
+
});
|
|
356143
|
+
if (!selected.ok)
|
|
356144
|
+
return selected.result;
|
|
355628
356145
|
return runStagedFlows({
|
|
355629
356146
|
ctx,
|
|
355630
|
-
files:
|
|
356147
|
+
files: selected.files,
|
|
355631
356148
|
flags,
|
|
355632
356149
|
deps: resolvedDeps
|
|
355633
356150
|
});
|
|
355634
356151
|
}
|
|
356152
|
+
async function chooseEnv(ctx, files, allEnvs) {
|
|
356153
|
+
const choice = await resolveEnvChoice({
|
|
356154
|
+
files,
|
|
356155
|
+
allEnvs,
|
|
356156
|
+
mode: ctx.ui.mode,
|
|
356157
|
+
select: ctx.ui.select,
|
|
356158
|
+
readLabel: (dir) => readEnvLabel(dir, ctx.fs)
|
|
356159
|
+
});
|
|
356160
|
+
if (choice.kind === "proceed")
|
|
356161
|
+
return { proceed: choice.files };
|
|
356162
|
+
if (choice.kind === "cancelled") {
|
|
356163
|
+
ctx.ui.info(environmentsMessages.aborted);
|
|
356164
|
+
return { stop: undefined };
|
|
356165
|
+
}
|
|
356166
|
+
return { stop: { error: choice.error, exitCode: exitCodes.invalidArgs } };
|
|
356167
|
+
}
|
|
356168
|
+
|
|
356169
|
+
// src/commands/flows/hybridRunDefaults.ts
|
|
356170
|
+
import { join as join42, resolve as resolve10 } from "node:path";
|
|
356171
|
+
|
|
356172
|
+
// src/core/selectFlowFiles.ts
|
|
356173
|
+
function selectFlowFiles(args) {
|
|
356174
|
+
if (!hasSelectors(args.selectors)) {
|
|
356175
|
+
return { kind: "selected", files: [...args.files] };
|
|
356176
|
+
}
|
|
356177
|
+
const matched = args.files.filter((file2) => matchesSelectors({ tags: args.tagsByPath?.get(toRepoRelativePath(file2, args.cwd)) }, args.selectors));
|
|
356178
|
+
if (matched.length === 0)
|
|
356179
|
+
return { kind: "empty" };
|
|
356180
|
+
return { kind: "selected", files: matched };
|
|
356181
|
+
}
|
|
356182
|
+
|
|
356183
|
+
// src/domains/flows/applyFlowSelectors.ts
|
|
356184
|
+
async function applyFlowSelectors(args) {
|
|
356185
|
+
if (!hasSelectors(args.selectors)) {
|
|
356186
|
+
return { ok: true, files: [...args.files] };
|
|
356187
|
+
}
|
|
356188
|
+
const resolution = await args.resolveTags();
|
|
356189
|
+
if (resolution.kind === "unavailable") {
|
|
356190
|
+
return { ok: false, result: tagsUnavailableResult(args.envId) };
|
|
356191
|
+
}
|
|
356192
|
+
if (resolution.kind === "cached") {
|
|
356193
|
+
args.warn(flowsMessages.selectors.usingCachedTags(resolution.fetchedAt));
|
|
356194
|
+
}
|
|
356195
|
+
const selection = selectFlowFiles({
|
|
356196
|
+
files: args.files,
|
|
356197
|
+
cwd: args.cwd,
|
|
356198
|
+
selectors: args.selectors,
|
|
356199
|
+
tagsByPath: resolution.byPath
|
|
356200
|
+
});
|
|
356201
|
+
if (selection.kind === "selected") {
|
|
356202
|
+
return { ok: true, files: selection.files };
|
|
356203
|
+
}
|
|
356204
|
+
return {
|
|
356205
|
+
ok: false,
|
|
356206
|
+
result: args.onEmpty(explainEmptySelection(args.selectors, await args.fetchKnownTags()))
|
|
356207
|
+
};
|
|
356208
|
+
}
|
|
356209
|
+
|
|
356210
|
+
// src/domains/flows/resolveTags.ts
|
|
356211
|
+
async function fetchLive(ctx, envId) {
|
|
356212
|
+
try {
|
|
356213
|
+
const result = await ctx.platformClient.callPublicApi(publicContractsV1.flow.list, { environmentId: envId, includeDrafts: true });
|
|
356214
|
+
if (!result.ok)
|
|
356215
|
+
return;
|
|
356216
|
+
return new Map(result.value.flows.map((f3) => [f3.path, f3.tags]));
|
|
356217
|
+
} catch {
|
|
356218
|
+
return;
|
|
356219
|
+
}
|
|
356220
|
+
}
|
|
356221
|
+
async function readCache(envDir, fs9) {
|
|
356222
|
+
const manifest = await readManifest(envDir, fs9);
|
|
356223
|
+
if (typeof manifest === "string")
|
|
356224
|
+
return;
|
|
356225
|
+
if (manifest.tagsFetchedAt === undefined)
|
|
356226
|
+
return;
|
|
356227
|
+
const byPath = new Map;
|
|
356228
|
+
for (const flow of manifest.flows) {
|
|
356229
|
+
if (flow.tags !== undefined)
|
|
356230
|
+
byPath.set(toPosix(flow.path), flow.tags);
|
|
356231
|
+
}
|
|
356232
|
+
return { byPath, fetchedAt: manifest.tagsFetchedAt };
|
|
356233
|
+
}
|
|
356234
|
+
async function resolveTags(ctx, envId, envDir, fs9 = makeDefaultFs()) {
|
|
356235
|
+
const live = await fetchLive(ctx, envId);
|
|
356236
|
+
if (live)
|
|
356237
|
+
return { kind: "live", byPath: live };
|
|
356238
|
+
const cached2 = await readCache(envDir, fs9);
|
|
356239
|
+
if (cached2) {
|
|
356240
|
+
return {
|
|
356241
|
+
kind: "cached",
|
|
356242
|
+
byPath: cached2.byPath,
|
|
356243
|
+
fetchedAt: cached2.fetchedAt
|
|
356244
|
+
};
|
|
356245
|
+
}
|
|
356246
|
+
return { kind: "unavailable" };
|
|
356247
|
+
}
|
|
355635
356248
|
|
|
355636
356249
|
// src/commands/flows/hybridRunDefaults.ts
|
|
355637
|
-
import { join as join40, resolve as resolve10 } from "node:path";
|
|
355638
356250
|
function makeDefaultHybridDeps(fs9) {
|
|
355639
356251
|
return {
|
|
355640
356252
|
expandPatterns: (patterns, cwd, logger) => expandPatterns(patterns, cwd, logger, fs9),
|
|
355641
|
-
pullEnv: (ctx, envId) => handleFlowsPull(ctx, {
|
|
356253
|
+
pullEnv: (ctx, envId, identity) => handleFlowsPull(ctx, {
|
|
356254
|
+
env: envId,
|
|
356255
|
+
yes: true,
|
|
356256
|
+
envSlug: identity.slug,
|
|
356257
|
+
envName: identity.name
|
|
356258
|
+
}),
|
|
355642
356259
|
resolveDepsRoot: (args) => resolveDepsRoot({ ...args, fs: fs9 }),
|
|
355643
356260
|
prepareRunDir: (args) => prepareRunDir({ ...args, fs: fs9 }),
|
|
355644
356261
|
configureTestkit,
|
|
@@ -355647,18 +356264,20 @@ function makeDefaultHybridDeps(fs9) {
|
|
|
355647
356264
|
createFlowRuntimeDeps
|
|
355648
356265
|
};
|
|
355649
356266
|
}
|
|
355650
|
-
async function handleHybridFlowsRun(ctx, pattern, flags,
|
|
355651
|
-
const
|
|
356267
|
+
async function handleHybridFlowsRun(ctx, pattern, flags, options = {}) {
|
|
356268
|
+
const identity = options.identity ?? { slug: undefined, name: undefined };
|
|
356269
|
+
const selectors = options.selectors ?? { tags: [] };
|
|
356270
|
+
const resolvedDeps = options.deps ?? makeDefaultHybridDeps(ctx.fs);
|
|
355652
356271
|
const validation = validateEnvId(flags.env);
|
|
355653
356272
|
if (validation !== "ok") {
|
|
355654
356273
|
return { error: validation.error, exitCode: 2 };
|
|
355655
356274
|
}
|
|
355656
|
-
const envDir = resolve10(
|
|
356275
|
+
const envDir = resolve10(join42(".qawolf", flags.env));
|
|
355657
356276
|
const patternArgs = buildPatternArgs(pattern);
|
|
355658
356277
|
const globFlows = () => resolvedDeps.expandPatterns(patternArgs, envDir, ctx.log("flows"));
|
|
355659
356278
|
let files = await globFlows();
|
|
355660
356279
|
if (files.length === 0) {
|
|
355661
|
-
const pullResult = await resolvedDeps.pullEnv(ctx, flags.env);
|
|
356280
|
+
const pullResult = await resolvedDeps.pullEnv(ctx, flags.env, identity);
|
|
355662
356281
|
if (pullResult !== undefined)
|
|
355663
356282
|
return pullResult;
|
|
355664
356283
|
files = await globFlows();
|
|
@@ -355670,36 +356289,73 @@ async function handleHybridFlowsRun(ctx, pattern, flags, deps) {
|
|
|
355670
356289
|
});
|
|
355671
356290
|
}
|
|
355672
356291
|
}
|
|
355673
|
-
|
|
356292
|
+
const selection = await applyFlowSelectors({
|
|
356293
|
+
files,
|
|
356294
|
+
cwd: envDir,
|
|
356295
|
+
selectors,
|
|
356296
|
+
envId: flags.env,
|
|
356297
|
+
warn: (message) => ctx.ui.warn(message),
|
|
356298
|
+
resolveTags: () => resolveTags(ctx, flags.env, envDir, ctx.fs),
|
|
356299
|
+
fetchKnownTags: () => fetchKnownTags(ctx),
|
|
356300
|
+
onEmpty: (error51) => noMatchResult(ctx, {
|
|
356301
|
+
allowNoMatch: flags.allowNoMatch,
|
|
356302
|
+
error: error51,
|
|
356303
|
+
notice: runnerMessages.noFlowsMatched
|
|
356304
|
+
})
|
|
356305
|
+
});
|
|
356306
|
+
if (!selection.ok)
|
|
356307
|
+
return selection.result;
|
|
356308
|
+
return runStagedFlows({
|
|
356309
|
+
ctx,
|
|
356310
|
+
files: selection.files,
|
|
356311
|
+
flags,
|
|
356312
|
+
envDir,
|
|
356313
|
+
deps: resolvedDeps
|
|
356314
|
+
});
|
|
356315
|
+
}
|
|
356316
|
+
|
|
356317
|
+
// src/commands/flows/runAction.ts
|
|
356318
|
+
function makeFlowsRunAction(signals) {
|
|
356319
|
+
return (pattern, opts, command) => {
|
|
356320
|
+
const selectors = { tags: opts.tag };
|
|
356321
|
+
const allEnvsWarning = allEnvsNoEffectWarning({
|
|
356322
|
+
allEnvs: opts.allEnvs ?? false,
|
|
356323
|
+
env: opts.env,
|
|
356324
|
+
tags: opts.tag
|
|
356325
|
+
});
|
|
356326
|
+
if (opts.env !== undefined) {
|
|
356327
|
+
return withResolvedEnv(signals, {
|
|
356328
|
+
explicit: opts.env,
|
|
356329
|
+
requiredMessage: flowsMessages.run.requiresEnv,
|
|
356330
|
+
offlineFallback: async (explicit) => explicit === undefined ? undefined : (await findPulledEnv(explicit, process.cwd()))?.envId
|
|
356331
|
+
}, (ctx, env3, identity) => {
|
|
356332
|
+
if (allEnvsWarning !== undefined)
|
|
356333
|
+
ctx.ui.warn(allEnvsWarning);
|
|
356334
|
+
return handleHybridFlowsRun(ctx, pattern, { ...opts, env: env3 }, { identity, selectors });
|
|
356335
|
+
})(opts, command);
|
|
356336
|
+
}
|
|
356337
|
+
return withContext(signals, (ctx) => {
|
|
356338
|
+
if (allEnvsWarning !== undefined)
|
|
356339
|
+
ctx.ui.warn(allEnvsWarning);
|
|
356340
|
+
return handleFlowsRun(ctx, pattern, opts, undefined, selectors, opts.allEnvs);
|
|
356341
|
+
})(opts, command);
|
|
356342
|
+
};
|
|
355674
356343
|
}
|
|
355675
356344
|
|
|
355676
356345
|
// src/commands/flows/run.register.ts
|
|
355677
|
-
var videoModes = ["on", "off", "retain-on-failure"];
|
|
355678
|
-
var traceModes = ["on", "off", "retain-on-failure"];
|
|
355679
|
-
var harModes = ["on", "off", "retain-on-failure"];
|
|
355680
|
-
var harContentModes = ["full", "omit"];
|
|
355681
|
-
var videoDefault = "off";
|
|
355682
|
-
var traceDefault = "off";
|
|
355683
|
-
var harDefault = "off";
|
|
355684
|
-
var harContentDefault = "omit";
|
|
355685
356346
|
var runExamples = `
|
|
355686
356347
|
Examples:
|
|
355687
356348
|
$ qawolf flows run
|
|
355688
356349
|
$ qawolf flows run "flows/checkout/**"
|
|
355689
356350
|
$ qawolf flows run --retries 2 --video retain-on-failure
|
|
356351
|
+
$ qawolf flows run --tag auth
|
|
356352
|
+
$ qawolf flows run --tag auth --env staging
|
|
355690
356353
|
$ qawolf flows run checkout --env staging --headed`;
|
|
355691
356354
|
function registerFlowsRunCommand(flows, signals) {
|
|
355692
|
-
declareCommandKind(flows.command("run [pattern]"), "local", {
|
|
356355
|
+
const command = declareCommandKind(flows.command("run [pattern]"), "local", {
|
|
355693
356356
|
kindNote: "read with --env"
|
|
355694
|
-
}).description("Run flows matching [pattern], or every flow when omitted; with --env, pull missing flows from that QA Wolf environment").option("--retries <n>", "Retry each failing flow up to this many times", parseInteger("--retries", { min: 0 }), 0).option("--bail", "Stop the run after the first failure", false).option("--workers <n>", "Parallel worker count for web flows", parseInteger("--workers", { min: 1 }), 1).option("--timeout <ms>", "Default timeout for actions and assertions, in milliseconds", parseInteger("--timeout", { min: 0 }), 30000)
|
|
355695
|
-
|
|
355696
|
-
return withResolvedEnv(signals, {
|
|
355697
|
-
explicit: opts.env,
|
|
355698
|
-
requiredMessage: flowsMessages.run.requiresEnv
|
|
355699
|
-
}, (ctx, env3) => handleHybridFlowsRun(ctx, pattern, { ...opts, env: env3 }))(opts, command);
|
|
355700
|
-
}
|
|
355701
|
-
return withContext(signals, (ctx) => handleFlowsRun(ctx, pattern, opts))(opts, command);
|
|
355702
|
-
});
|
|
356357
|
+
}).description("Run flows matching [pattern], or every flow when omitted; with --env, pull missing flows from that QA Wolf environment").option("--retries <n>", "Retry each failing flow up to this many times", parseInteger("--retries", { min: 0 }), 0).option("--bail", "Stop the run after the first failure", false).option("--workers <n>", "Parallel worker count for web flows", parseInteger("--workers", { min: 1 }), 1).option("--timeout <ms>", "Default timeout for actions and assertions, in milliseconds", parseInteger("--timeout", { min: 0 }), 30000);
|
|
356358
|
+
addRunArtifactOptions(command).option("--headed", "Show the browser window instead of headless", false).option("--env <env>", "Pull and run a flow from this environment (UUID or slug) if not cached locally").option("--deps <dir>", "Use this prepared dependency directory instead of auto-installing the runtime; or set QAWOLF_RUNTIME_DIR to relocate the managed runtime").option("--allow-no-match", "Exit 0 instead of 2 when the pattern selects no runnable flow", false).option("--no-browser-deps", "Skip installing OS-level browser dependencies (Linux --with-deps, which needs root); requires the system libraries to already be present").option("--tag <name>", "Only run flows carrying this tag; repeat for several. Without --env, matches against tags cached by the last pull", collectValue, []).option("--all-envs", "When a tag matches flows in several pulled environments, run every match instead of choosing one", false).addHelpText("after", runExamples).action(makeFlowsRunAction(signals));
|
|
355703
356359
|
}
|
|
355704
356360
|
|
|
355705
356361
|
// src/domains/runner/executeWorkerFlow.ts
|
|
@@ -355772,6 +356428,9 @@ Examples:
|
|
|
355772
356428
|
$ qawolf flows list
|
|
355773
356429
|
$ qawolf flows list "flows/checkout/**"
|
|
355774
356430
|
$ qawolf flows list --remote --env staging
|
|
356431
|
+
$ qawolf flows list --tag auth
|
|
356432
|
+
$ qawolf flows list --env staging --tag auth
|
|
356433
|
+
$ qawolf flows list --remote --env staging --tag auth --tag smoke
|
|
355775
356434
|
$ qawolf flows list "**/checkout/**" --remote --env staging --include-drafts`;
|
|
355776
356435
|
function registerFlowsCommand(program2, signals) {
|
|
355777
356436
|
const flows = program2.command("flows").description("Manage and run QA Wolf flows");
|
|
@@ -355779,33 +356438,35 @@ function registerFlowsCommand(program2, signals) {
|
|
|
355779
356438
|
registerRunWorkerCommand(flows, signals);
|
|
355780
356439
|
declareCommandKind(flows.command("list [pattern]"), "local", {
|
|
355781
356440
|
kindNote: "read with --remote"
|
|
355782
|
-
}).description("List flows matching [pattern] from the local project, or from a QA Wolf environment with --remote").option("--remote", "List flows from the QA Wolf platform instead of the local project", false).option("--env <env>", "Environment to list flows from
|
|
356441
|
+
}).description("List flows matching [pattern] from the local project, or from a QA Wolf environment with --remote").option("--remote", "List flows from the QA Wolf platform instead of the local project", false).option("--env <env>", "Environment to list flows from: a QA Wolf environment with --remote, otherwise a pulled one by slug or id").option("--include-drafts", "Include draft flows in the listing (requires --remote)", false).option("--tag <name>", "Only list flows carrying this tag; repeat for several. Without --remote, matches against tags cached by the last pull", collectValue, []).addHelpText("after", listExamples).action((pattern, opts, command) => {
|
|
356442
|
+
const tags = opts.tag;
|
|
355783
356443
|
if (opts.remote) {
|
|
355784
356444
|
return withResolvedEnv(signals, {
|
|
355785
356445
|
explicit: opts.env,
|
|
355786
356446
|
requiredMessage: flowsMessages.list.remoteRequiresEnv
|
|
355787
356447
|
}, (ctx, env3) => flowsListRemote(ctx, pattern, {
|
|
355788
356448
|
env: env3,
|
|
355789
|
-
includeDrafts: opts.includeDrafts
|
|
356449
|
+
includeDrafts: opts.includeDrafts,
|
|
356450
|
+
tags
|
|
355790
356451
|
}))(opts, command);
|
|
355791
356452
|
}
|
|
355792
|
-
if (opts.
|
|
356453
|
+
if (opts.includeDrafts) {
|
|
355793
356454
|
return withContext(signals, async () => ({
|
|
355794
|
-
error: flowsMessages.list.
|
|
356455
|
+
error: flowsMessages.list.draftsRequireRemote
|
|
355795
356456
|
}))(opts, command);
|
|
355796
356457
|
}
|
|
355797
|
-
return withContext(signals, (ctx) => handleFlowsList(ctx, pattern))(opts, command);
|
|
356458
|
+
return withContext(signals, (ctx) => handleFlowsList(ctx, pattern, { tags, env: opts.env }))(opts, command);
|
|
355798
356459
|
});
|
|
355799
356460
|
registerFlowsPullCommand(flows, signals);
|
|
355800
356461
|
}
|
|
355801
356462
|
|
|
355802
356463
|
// src/domains/init/init.ts
|
|
355803
|
-
import { dirname as dirname14, join as
|
|
356464
|
+
import { dirname as dirname14, join as join44, relative as relative9 } from "node:path";
|
|
355804
356465
|
|
|
355805
356466
|
// src/domains/init/ensurePackageJson.ts
|
|
355806
|
-
import { join as
|
|
356467
|
+
import { join as join43 } from "node:path";
|
|
355807
356468
|
async function ensurePackageJson(ctx, yes, deps) {
|
|
355808
|
-
const pkgPath =
|
|
356469
|
+
const pkgPath = join43(deps.cwd, "package.json");
|
|
355809
356470
|
if (!await deps.fs.pathExists(pkgPath)) {
|
|
355810
356471
|
const confirmed2 = await ctx.ui.confirm(initMessages.createPackageJsonPrompt, { yes });
|
|
355811
356472
|
if (!confirmed2.ok || !confirmed2.value) {
|
|
@@ -355931,9 +356592,9 @@ function makeDefaultInitDeps() {
|
|
|
355931
356592
|
async function handleInit(ctx, opts, deps = makeDefaultInitDeps()) {
|
|
355932
356593
|
ctx.ui.gap();
|
|
355933
356594
|
ctx.ui.intro(initMessages.title);
|
|
355934
|
-
const configPath =
|
|
355935
|
-
const flowPath =
|
|
355936
|
-
const gitignorePath =
|
|
356595
|
+
const configPath = join44(deps.cwd, "qawolf.config.ts");
|
|
356596
|
+
const flowPath = join44(deps.cwd, "src", "flows", "example.flow.ts");
|
|
356597
|
+
const gitignorePath = join44(deps.cwd, ".qawolf", ".gitignore");
|
|
355937
356598
|
await writeWithPrompt(ctx, configPath, qawolfConfigTs, opts.yes, deps);
|
|
355938
356599
|
await writeWithPrompt(ctx, flowPath, exampleFlowTs, opts.yes, deps);
|
|
355939
356600
|
await writeWithPrompt(ctx, gitignorePath, qawolfGitignore, opts.yes, deps);
|
|
@@ -355941,7 +356602,7 @@ async function handleInit(ctx, opts, deps = makeDefaultInitDeps()) {
|
|
|
355941
356602
|
ctx.ui.outro(initMessages.outro);
|
|
355942
356603
|
}
|
|
355943
356604
|
async function writeWithPrompt(ctx, filePath, content, yes, deps) {
|
|
355944
|
-
const relPath =
|
|
356605
|
+
const relPath = relative9(deps.cwd, filePath);
|
|
355945
356606
|
if (await deps.fs.pathExists(filePath)) {
|
|
355946
356607
|
const confirmed = await ctx.ui.confirm(initMessages.overwritePrompt(relPath), {
|
|
355947
356608
|
yes,
|
|
@@ -355971,7 +356632,7 @@ Examples:
|
|
|
355971
356632
|
import { parseExecutionTarget as parseExecutionTarget4 } from "@qawolf/flow-targets";
|
|
355972
356633
|
|
|
355973
356634
|
// src/domains/install/android/avd.ts
|
|
355974
|
-
import { join as
|
|
356635
|
+
import { join as join45 } from "node:path";
|
|
355975
356636
|
async function installAvds(ctx, specs, deps) {
|
|
355976
356637
|
const sdkManagerPath = sdkManagerBin(deps.androidHome, deps.platform);
|
|
355977
356638
|
const avdManagerPath = avdManagerBin(deps.androidHome, deps.platform);
|
|
@@ -355981,7 +356642,7 @@ async function installAvds(ctx, specs, deps) {
|
|
|
355981
356642
|
if (versionResult.exitCode !== 0) {
|
|
355982
356643
|
throw new Error(installMessages.android.sdkmanagerNotFound(sdkManagerPath));
|
|
355983
356644
|
}
|
|
355984
|
-
const licenseFile =
|
|
356645
|
+
const licenseFile = join45(deps.androidHome, "licenses", "android-sdk-license");
|
|
355985
356646
|
if (deps.checkExists(licenseFile)) {
|
|
355986
356647
|
ctx.ui.info(installMessages.android.licensesAlreadyAccepted);
|
|
355987
356648
|
} else {
|
|
@@ -355996,7 +356657,7 @@ async function installAvds(ctx, specs, deps) {
|
|
|
355996
356657
|
for (const spec of specs) {
|
|
355997
356658
|
if (installedImages.has(spec.systemImage))
|
|
355998
356659
|
continue;
|
|
355999
|
-
const systemImg =
|
|
356660
|
+
const systemImg = join45(deps.androidHome, ...spec.systemImage.split(";"), "system.img");
|
|
356000
356661
|
if (deps.checkExists(systemImg)) {
|
|
356001
356662
|
ctx.ui.info(installMessages.android.systemImageAlreadyInstalled(spec.systemImage));
|
|
356002
356663
|
installedImages.add(spec.systemImage);
|
|
@@ -356882,7 +357543,7 @@ function describeFailure(failureReason) {
|
|
|
356882
357543
|
}
|
|
356883
357544
|
|
|
356884
357545
|
// src/shell/interactiveRunner/collectRunFiles.ts
|
|
356885
|
-
import { join as
|
|
357546
|
+
import { join as join47 } from "node:path";
|
|
356886
357547
|
|
|
356887
357548
|
// src/core/interactiveRunner/getImports.ts
|
|
356888
357549
|
function getImports(options) {
|
|
@@ -356921,7 +357582,7 @@ function isPathAlias(importPath, paths) {
|
|
|
356921
357582
|
}
|
|
356922
357583
|
|
|
356923
357584
|
// src/core/interactiveRunner/resolveImportPath.ts
|
|
356924
|
-
import { dirname as dirname15, join as
|
|
357585
|
+
import { dirname as dirname15, join as join46, normalize as normalize4 } from "node:path/posix";
|
|
356925
357586
|
|
|
356926
357587
|
// src/core/interactiveRunner/tsconfigPaths.ts
|
|
356927
357588
|
function isRecord5(value) {
|
|
@@ -356974,7 +357635,7 @@ function candidatesForExplicitExtension(options) {
|
|
|
356974
357635
|
}
|
|
356975
357636
|
function resolveImportPath(options) {
|
|
356976
357637
|
const aliasTarget = resolvePathAlias(options.importPath, options.tsconfigPaths);
|
|
356977
|
-
const resolvedPath = aliasTarget === undefined ?
|
|
357638
|
+
const resolvedPath = aliasTarget === undefined ? normalize4(join46(dirname15(options.importingFilePath), options.importPath)) : normalize4(aliasTarget);
|
|
356978
357639
|
const hasExplicitExtension = supportedExtensions.some((extension) => options.importPath.endsWith(extension));
|
|
356979
357640
|
const candidates = hasExplicitExtension ? candidatesForExplicitExtension({
|
|
356980
357641
|
importPath: options.importPath,
|
|
@@ -356998,7 +357659,7 @@ function resolveImportPath(options) {
|
|
|
356998
357659
|
var tsconfigPath = "tsconfig.json";
|
|
356999
357660
|
async function collectRunFiles(options) {
|
|
357000
357661
|
const held = await listShippablePaths(options);
|
|
357001
|
-
const readFile2 = (path9) => options.fs.readFile(
|
|
357662
|
+
const readFile2 = (path9) => options.fs.readFile(join47(options.cwd, path9));
|
|
357002
357663
|
const tsconfigContent = held.has(tsconfigPath) ? await readFile2(tsconfigPath).catch(() => {
|
|
357003
357664
|
return;
|
|
357004
357665
|
}) : undefined;
|
|
@@ -357081,7 +357742,7 @@ function makeRunnerId() {
|
|
|
357081
357742
|
}
|
|
357082
357743
|
|
|
357083
357744
|
// src/shell/interactiveRunner/runFilesManifest.ts
|
|
357084
|
-
import { join as
|
|
357745
|
+
import { join as join48 } from "node:path";
|
|
357085
357746
|
var manifestFileName = "runner-files.json";
|
|
357086
357747
|
var manifestSchema2 = exports_external.object({
|
|
357087
357748
|
files: exports_external.array(exports_external.object({ contentHash: exports_external.string(), path: exports_external.string() })),
|
|
@@ -357089,8 +357750,8 @@ var manifestSchema2 = exports_external.object({
|
|
|
357089
357750
|
version: exports_external.literal(1)
|
|
357090
357751
|
});
|
|
357091
357752
|
function makeRunFilesManifestStore(options) {
|
|
357092
|
-
const directory =
|
|
357093
|
-
const path9 =
|
|
357753
|
+
const directory = join48(options.cwd, qawolfDir);
|
|
357754
|
+
const path9 = join48(directory, manifestFileName);
|
|
357094
357755
|
let pendingWrites = 0;
|
|
357095
357756
|
return {
|
|
357096
357757
|
async read() {
|
|
@@ -357120,7 +357781,7 @@ function parseJson(text3) {
|
|
|
357120
357781
|
}
|
|
357121
357782
|
|
|
357122
357783
|
// src/shell/interactiveRunner/runnerStore.ts
|
|
357123
|
-
import { join as
|
|
357784
|
+
import { join as join49 } from "node:path";
|
|
357124
357785
|
var storeFileName = "runner.json";
|
|
357125
357786
|
var runnersDirName = "runners";
|
|
357126
357787
|
var storedRunnerSchema = exports_external.object({
|
|
@@ -357139,11 +357800,11 @@ function parseJson2(text3) {
|
|
|
357139
357800
|
}
|
|
357140
357801
|
var pendingWrites = 0;
|
|
357141
357802
|
function makeRunnerStore(options) {
|
|
357142
|
-
const directory =
|
|
357143
|
-
const path9 =
|
|
357144
|
-
const runnersDir =
|
|
357803
|
+
const directory = join49(options.cwd, qawolfDir);
|
|
357804
|
+
const path9 = join49(directory, storeFileName);
|
|
357805
|
+
const runnersDir = join49(directory, runnersDirName);
|
|
357145
357806
|
const nextPendingPath = (target) => `${target}.${process.pid}.${++pendingWrites}.tmp`;
|
|
357146
|
-
const runnerPath = (runnerId) =>
|
|
357807
|
+
const runnerPath = (runnerId) => join49(runnersDir, `${encodeURIComponent(runnerId)}.json`);
|
|
357147
357808
|
const writeAtomically = async (target, contents2) => {
|
|
357148
357809
|
const pendingPath = nextPendingPath(target);
|
|
357149
357810
|
await options.fs.writeFile(pendingPath, `${JSON.stringify(contents2, undefined, 2)}
|
|
@@ -357180,7 +357841,7 @@ function makeRunnerStore(options) {
|
|
|
357180
357841
|
readDefaultRunnerId,
|
|
357181
357842
|
async readRunners() {
|
|
357182
357843
|
const runners = await Promise.all((await readRunnerFileNames()).map(async (name) => {
|
|
357183
|
-
const contents2 = await options.fs.readFile(
|
|
357844
|
+
const contents2 = await options.fs.readFile(join49(runnersDir, name)).catch(() => {
|
|
357184
357845
|
return;
|
|
357185
357846
|
});
|
|
357186
357847
|
if (contents2 === undefined)
|
|
@@ -357199,7 +357860,7 @@ function makeRunnerStore(options) {
|
|
|
357199
357860
|
await Promise.all(runnerIds.map((runnerId) => options.fs.rm(runnerPath(runnerId), { force: true })));
|
|
357200
357861
|
const names = await readRunnerFileNames();
|
|
357201
357862
|
await Promise.all(names.map(async (name) => {
|
|
357202
|
-
const runnerFile =
|
|
357863
|
+
const runnerFile = join49(runnersDir, name);
|
|
357203
357864
|
const contents2 = await options.fs.readFile(runnerFile).catch(() => {
|
|
357204
357865
|
return;
|
|
357205
357866
|
});
|
|
@@ -357283,7 +357944,7 @@ function registerRunnerHighlightSelectorCommand(runner, signals) {
|
|
|
357283
357944
|
}
|
|
357284
357945
|
|
|
357285
357946
|
// src/domains/interactiveRunner/importPackage.ts
|
|
357286
|
-
import { join as
|
|
357947
|
+
import { join as join50 } from "node:path";
|
|
357287
357948
|
|
|
357288
357949
|
// src/core/interactiveRunner/npmDependencies.ts
|
|
357289
357950
|
var sectionsInPrecedenceOrder = ["dependencies", "devDependencies"];
|
|
@@ -357324,7 +357985,7 @@ function readNpmDependencies(packageJsonContent) {
|
|
|
357324
357985
|
// src/domains/interactiveRunner/importPackage.ts
|
|
357325
357986
|
var defaultPackageVersion = "latest";
|
|
357326
357987
|
async function handleRunnerImportPackage(ctx, options, deps) {
|
|
357327
|
-
const content = await deps.readFile(
|
|
357988
|
+
const content = await deps.readFile(join50(deps.cwd, runPackageJsonPath)).catch(() => {
|
|
357328
357989
|
return;
|
|
357329
357990
|
});
|
|
357330
357991
|
if (content === undefined) {
|
|
@@ -357662,10 +358323,10 @@ function registerRunnerInspectCommands(runner, signals) {
|
|
|
357662
358323
|
}
|
|
357663
358324
|
|
|
357664
358325
|
// src/core/interactiveRunner/runFiles.ts
|
|
357665
|
-
import { isAbsolute as isAbsolute5, relative as
|
|
358326
|
+
import { isAbsolute as isAbsolute5, relative as relative10, resolve as resolve11, sep as sep5 } from "node:path";
|
|
357666
358327
|
function toCollectedPath(cwd, path9) {
|
|
357667
358328
|
const absolute = isAbsolute5(path9) ? path9 : resolve11(cwd, path9);
|
|
357668
|
-
return
|
|
358329
|
+
return relative10(cwd, absolute).split(sep5).join("/");
|
|
357669
358330
|
}
|
|
357670
358331
|
var namedLargestFileCount = 3;
|
|
357671
358332
|
function largestFiles(files) {
|
|
@@ -358106,7 +358767,7 @@ async function handleRunnerLaunch(ctx, options, deps) {
|
|
|
358106
358767
|
}
|
|
358107
358768
|
|
|
358108
358769
|
// src/domains/interactiveRunner/list.ts
|
|
358109
|
-
var
|
|
358770
|
+
var columns = [
|
|
358110
358771
|
{ header: "id", value: (row) => row.id },
|
|
358111
358772
|
{ header: "family", value: (row) => row.runnerName ?? "" },
|
|
358112
358773
|
{ header: "default", value: (row) => row.isDefault ? "yes" : "" }
|
|
@@ -358164,12 +358825,12 @@ async function handleRunnerList(ctx, deps) {
|
|
|
358164
358825
|
return;
|
|
358165
358826
|
}
|
|
358166
358827
|
if (ctx.ui.mode === "agent") {
|
|
358167
|
-
ctx.ui.write(renderTable({ boldHeader: false, columns
|
|
358828
|
+
ctx.ui.write(renderTable({ boldHeader: false, columns, rows: items }));
|
|
358168
358829
|
return;
|
|
358169
358830
|
}
|
|
358170
358831
|
ctx.ui.gap();
|
|
358171
358832
|
ctx.ui.intro(interactiveRunnerMessages.title);
|
|
358172
|
-
ctx.ui.write(renderTable({ boldHeader: true, columns
|
|
358833
|
+
ctx.ui.write(renderTable({ boldHeader: true, columns, rows: items }));
|
|
358173
358834
|
ctx.ui.outro(interactiveRunnerMessages.runnerCount(items.length));
|
|
358174
358835
|
}
|
|
358175
358836
|
|
|
@@ -359030,4 +359691,4 @@ createProgram({ signals }).parseAsync().catch(() => {
|
|
|
359030
359691
|
process.exitCode = 1;
|
|
359031
359692
|
}).finally(() => flushAndExit(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
359032
359693
|
|
|
359033
|
-
//# debugId=
|
|
359694
|
+
//# debugId=50C554904C1768A664756E2164756E21
|