@qawolf/cli 1.29.0 → 1.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1996 -499
- package/dist/runner-sdk.js +60 -72
- package/dist/types/runnerSdk/types.d.ts +2 -0
- package/package.json +2 -2
- package/skills/qawolf-cli/SKILL.md +56 -2
- package/skills/qawolf-cli/references/runner.md +9 -1
package/dist/cli.js
CHANGED
|
@@ -8390,16 +8390,38 @@ function extractMissingPackage(text) {
|
|
|
8390
8390
|
return specifier;
|
|
8391
8391
|
}
|
|
8392
8392
|
|
|
8393
|
-
// src/core/pluralize.ts
|
|
8394
|
-
function pluralize(count, singular, plural = `${singular}s`) {
|
|
8395
|
-
return `${String(count)} ${count === 1 ? singular : plural}`;
|
|
8396
|
-
}
|
|
8397
|
-
|
|
8398
8393
|
// src/core/formatSeconds.ts
|
|
8399
8394
|
function formatSeconds(ms) {
|
|
8400
8395
|
return `${Math.round(ms / 1000)}s`;
|
|
8401
8396
|
}
|
|
8402
8397
|
|
|
8398
|
+
// src/core/messages/agent.ts
|
|
8399
|
+
var followAgain = (sessionId) => `qawolf agent get --follow --session ${sessionId}`;
|
|
8400
|
+
var sessionGivenTwice = (argument, flag) => `Two different sessions were named: "${argument}" as an argument and "${flag}" as --session. Pass one of them.`;
|
|
8401
|
+
var agentMessages = {
|
|
8402
|
+
answerCancelled: "No answer sent, so QA Wolf is still waiting on one. The session keeps its place: answer it whenever you like.",
|
|
8403
|
+
answerPrompt: "Your answer",
|
|
8404
|
+
answerSendFailed: (reason) => `The answer could not be sent: ${reason}. The session is still waiting, so try again.`,
|
|
8405
|
+
blocked: (sessionId) => `QA Wolf asked a question and cannot continue until it is answered. Answer it with qawolf agent send "<your answer>" --session ${sessionId}.`,
|
|
8406
|
+
detachHint: "Press Ctrl-C to stop following. The session keeps running in the background.",
|
|
8407
|
+
detached: (sessionId) => `Stopped following. The session is still running — pick it back up with ${followAgain(sessionId)}.`,
|
|
8408
|
+
followTimedOut: (sessionId, seconds) => `Stopped following after ${formatSeconds(seconds * 1000)}. The session may still be going: pick it back up with ${followAgain(sessionId)}, or pass --timeout to wait longer.`,
|
|
8409
|
+
noSession: "No session named. Pass --session, set QAWOLF_SESSION_ID, or start one with qawolf agent send.",
|
|
8410
|
+
sessionNotRemembered: (sessionId) => `The session id could not be saved to .qawolf/agent.json, so pass --session ${sessionId} to pick it up later.`,
|
|
8411
|
+
sessionCancelled: (url) => `The session was cancelled before it finished. Read how far it got at ${url}.`,
|
|
8412
|
+
sessionCompleted: "QA Wolf finished the work.",
|
|
8413
|
+
sessionFailed: (url) => `The session failed. Read what happened at ${url}.`,
|
|
8414
|
+
sessionAt: (url) => `Following ${url}`,
|
|
8415
|
+
standing: (status, url) => `${status} — ${url}`,
|
|
8416
|
+
started: (sessionId, url) => `Started session ${sessionId} — ${url}`,
|
|
8417
|
+
waiting: "Waiting for QA Wolf",
|
|
8418
|
+
working: "QA Wolf is working. It reports back here as it goes, which can take a few minutes."
|
|
8419
|
+
};
|
|
8420
|
+
// src/core/pluralize.ts
|
|
8421
|
+
function pluralize(count, singular, plural = `${singular}s`) {
|
|
8422
|
+
return `${String(count)} ${count === 1 ? singular : plural}`;
|
|
8423
|
+
}
|
|
8424
|
+
|
|
8403
8425
|
// src/core/messages/authErrors.ts
|
|
8404
8426
|
var authErrorMessages = {
|
|
8405
8427
|
identity: {
|
|
@@ -8669,7 +8691,7 @@ var flowsMessages = {
|
|
|
8669
8691
|
extractingBundle: "Extracting bundle",
|
|
8670
8692
|
downloadingTeamStorageAssets: "Downloading team-storage assets",
|
|
8671
8693
|
downloadingTeamStorageAssetsProgress: (current, total) => `Downloading team-storage assets (${String(current)}/${String(total)})`,
|
|
8672
|
-
|
|
8694
|
+
teamStorageRequiresTeam: "Team storage needs a team. Pull an environment to name its team, choose a workspace with 'qawolf auth switch', or use a team API key.",
|
|
8673
8695
|
summary: (result, assetsAbs) => {
|
|
8674
8696
|
const flows = pluralize(result.flowCount, "flow");
|
|
8675
8697
|
const envVars = result.envVarCount === 0 ? "" : ` and ${pluralize(result.envVarCount, "environment variable")}`;
|
|
@@ -8844,17 +8866,18 @@ var interactMessages = {
|
|
|
8844
8866
|
};
|
|
8845
8867
|
|
|
8846
8868
|
// src/core/messages/interactiveRunner/lifecycle.ts
|
|
8869
|
+
var pageAt = (url) => `Its runner page is at ${url}`;
|
|
8847
8870
|
var noRunnerId = "No runner id. Pass --runner, set QAWOLF_RUNNER_ID, or run qawolf runner launch first.";
|
|
8848
8871
|
var lifecycleMessages = {
|
|
8849
|
-
alreadyRunning: (id) => `Runner ${id} was already running
|
|
8872
|
+
alreadyRunning: (id, url) => `Runner ${id} was already running. ${pageAt(url)}`,
|
|
8850
8873
|
defaultNotRemembered: (id) => `Runner ${id} could not be written to .qawolf as this directory's default, so later commands will not find it on their own. Pass --runner ${id}, or set QAWOLF_RUNNER_ID=${id}.`,
|
|
8851
8874
|
defaultNotForgotten: (id) => `Runner ${id} was terminated, but it could not be removed from .qawolf as this directory's default, so later commands will still be sent to it. Pass --runner, or launch a new runner.`,
|
|
8852
8875
|
envRunnerIdShadowsLaunch: (launchedId, envId) => `QAWOLF_RUNNER_ID=${envId} is still set, so commands that omit --runner will keep targeting it instead of the runner just launched. Pass --runner ${launchedId} to address this one.`,
|
|
8853
8876
|
keptAlive: (id) => `Runner ${id} is alive, and its inactivity clock has been reset.`,
|
|
8854
8877
|
launchFailed: (id, error) => `Launching runner ${id} failed. ${error}`,
|
|
8855
8878
|
launchLost: (id, error) => `Launching runner ${id} failed. ${error}. The request may still have reached QA Wolf and started a runner, so relaunch the same id with qawolf runner launch --id ${id} to attach to it rather than start a second one, or terminate it with qawolf runner terminate --runner ${id}.`,
|
|
8856
|
-
launched: (id) => `Launched runner ${id}
|
|
8857
|
-
launchedForCommand: (id) => `No runner was given, so launched ${id} for this command. Its browser is fresh: nothing has been run on it and nothing is signed in. It bills until it is terminated or idles out, so terminate it with qawolf runner terminate --runner ${id} when you are done
|
|
8879
|
+
launched: (id, url) => `Launched runner ${id}. ${pageAt(url)}`,
|
|
8880
|
+
launchedForCommand: (id, url) => `No runner was given, so launched ${id} for this command. Its browser is fresh: nothing has been run on it and nothing is signed in. It bills until it is terminated or idles out, so terminate it with qawolf runner terminate --runner ${id} when you are done. ${pageAt(url)}`,
|
|
8858
8881
|
noRunnerIdForImport: `${noRunnerId} An install also needs a live run to go into, which a runner gets from qawolf runner run.`,
|
|
8859
8882
|
noRunnerIdForHighlight: `${noRunnerId} Highlighting also needs a live page to draw on, which a runner gets from its first run: run a flow on it with qawolf runner run.`,
|
|
8860
8883
|
noRunnerIdForInspect: `${noRunnerId} Inspecting also needs a page, which a runner gets from its first run: run a flow on it with qawolf runner run.`,
|
|
@@ -9237,8 +9260,10 @@ function resolveHostUrl(env) {
|
|
|
9237
9260
|
return configuredHostUrl.replace(/\/+$/, "");
|
|
9238
9261
|
}
|
|
9239
9262
|
|
|
9240
|
-
// src/
|
|
9241
|
-
|
|
9263
|
+
// src/shell/keyring.ts
|
|
9264
|
+
function loadEntryClass() {
|
|
9265
|
+
return import("@napi-rs/keyring").then((keyring) => keyring.Entry);
|
|
9266
|
+
}
|
|
9242
9267
|
|
|
9243
9268
|
// src/core/deviceAuth/tokenExpiry.ts
|
|
9244
9269
|
function readAccessTokenExpiry(accessToken) {
|
|
@@ -11881,6 +11906,56 @@ function handlePipeResult(left, next, ctx) {
|
|
|
11881
11906
|
}
|
|
11882
11907
|
return next._zod.run({ value: left.value, issues: left.issues, fallback: left.fallback }, ctx);
|
|
11883
11908
|
}
|
|
11909
|
+
var $ZodCodec = /* @__PURE__ */ $constructor("$ZodCodec", (inst, def) => {
|
|
11910
|
+
$ZodType.init(inst, def);
|
|
11911
|
+
defineLazy(inst._zod, "values", () => def.in._zod.values);
|
|
11912
|
+
defineLazy(inst._zod, "optin", () => def.in._zod.optin);
|
|
11913
|
+
defineLazy(inst._zod, "optout", () => def.out._zod.optout);
|
|
11914
|
+
defineLazy(inst._zod, "propValues", () => def.in._zod.propValues);
|
|
11915
|
+
inst._zod.parse = (payload, ctx) => {
|
|
11916
|
+
const direction = ctx.direction || "forward";
|
|
11917
|
+
if (direction === "forward") {
|
|
11918
|
+
const left = def.in._zod.run(payload, ctx);
|
|
11919
|
+
if (left instanceof Promise) {
|
|
11920
|
+
return left.then((left) => handleCodecAResult(left, def, ctx));
|
|
11921
|
+
}
|
|
11922
|
+
return handleCodecAResult(left, def, ctx);
|
|
11923
|
+
} else {
|
|
11924
|
+
const right = def.out._zod.run(payload, ctx);
|
|
11925
|
+
if (right instanceof Promise) {
|
|
11926
|
+
return right.then((right) => handleCodecAResult(right, def, ctx));
|
|
11927
|
+
}
|
|
11928
|
+
return handleCodecAResult(right, def, ctx);
|
|
11929
|
+
}
|
|
11930
|
+
};
|
|
11931
|
+
});
|
|
11932
|
+
function handleCodecAResult(result, def, ctx) {
|
|
11933
|
+
if (result.issues.length) {
|
|
11934
|
+
result.aborted = true;
|
|
11935
|
+
return result;
|
|
11936
|
+
}
|
|
11937
|
+
const direction = ctx.direction || "forward";
|
|
11938
|
+
if (direction === "forward") {
|
|
11939
|
+
const transformed = def.transform(result.value, result);
|
|
11940
|
+
if (transformed instanceof Promise) {
|
|
11941
|
+
return transformed.then((value) => handleCodecTxResult(result, value, def.out, ctx));
|
|
11942
|
+
}
|
|
11943
|
+
return handleCodecTxResult(result, transformed, def.out, ctx);
|
|
11944
|
+
} else {
|
|
11945
|
+
const transformed = def.reverseTransform(result.value, result);
|
|
11946
|
+
if (transformed instanceof Promise) {
|
|
11947
|
+
return transformed.then((value) => handleCodecTxResult(result, value, def.in, ctx));
|
|
11948
|
+
}
|
|
11949
|
+
return handleCodecTxResult(result, transformed, def.in, ctx);
|
|
11950
|
+
}
|
|
11951
|
+
}
|
|
11952
|
+
function handleCodecTxResult(left, value, nextSchema, ctx) {
|
|
11953
|
+
if (left.issues.length) {
|
|
11954
|
+
left.aborted = true;
|
|
11955
|
+
return left;
|
|
11956
|
+
}
|
|
11957
|
+
return nextSchema._zod.run({ value, issues: left.issues }, ctx);
|
|
11958
|
+
}
|
|
11884
11959
|
var $ZodReadonly = /* @__PURE__ */ $constructor("$ZodReadonly", (inst, def) => {
|
|
11885
11960
|
$ZodType.init(inst, def);
|
|
11886
11961
|
defineLazy(inst._zod, "propValues", () => def.innerType._zod.propValues);
|
|
@@ -14426,6 +14501,19 @@ function pipe(in_, out) {
|
|
|
14426
14501
|
out
|
|
14427
14502
|
});
|
|
14428
14503
|
}
|
|
14504
|
+
var ZodCodec = /* @__PURE__ */ $constructor("ZodCodec", (inst, def) => {
|
|
14505
|
+
ZodPipe.init(inst, def);
|
|
14506
|
+
$ZodCodec.init(inst, def);
|
|
14507
|
+
});
|
|
14508
|
+
function codec(in_, out, params) {
|
|
14509
|
+
return new ZodCodec({
|
|
14510
|
+
type: "pipe",
|
|
14511
|
+
in: in_,
|
|
14512
|
+
out,
|
|
14513
|
+
transform: params.decode,
|
|
14514
|
+
reverseTransform: params.encode
|
|
14515
|
+
});
|
|
14516
|
+
}
|
|
14429
14517
|
var ZodReadonly = /* @__PURE__ */ $constructor("ZodReadonly", (inst, def) => {
|
|
14430
14518
|
$ZodReadonly.init(inst, def);
|
|
14431
14519
|
ZodType.init(inst, def);
|
|
@@ -14635,7 +14723,6 @@ function resolveWorkosConfig(publishedClientId) {
|
|
|
14635
14723
|
|
|
14636
14724
|
// src/domains/auth/store/delete.ts
|
|
14637
14725
|
import { join as join2 } from "node:path";
|
|
14638
|
-
import { Entry } from "@napi-rs/keyring";
|
|
14639
14726
|
|
|
14640
14727
|
// src/domains/auth/store/constants.ts
|
|
14641
14728
|
var service = "qawolf-cli";
|
|
@@ -14645,8 +14732,9 @@ var tokensAccount = "oauth-tokens";
|
|
|
14645
14732
|
var tokensFile = "tokens.json";
|
|
14646
14733
|
|
|
14647
14734
|
// src/domains/auth/store/delete.ts
|
|
14648
|
-
function deleteFromKeychain() {
|
|
14735
|
+
async function deleteFromKeychain() {
|
|
14649
14736
|
try {
|
|
14737
|
+
const Entry = await loadEntryClass();
|
|
14650
14738
|
new Entry(service, account).deletePassword();
|
|
14651
14739
|
return "deleted";
|
|
14652
14740
|
} catch {
|
|
@@ -14665,14 +14753,13 @@ async function deleteFromFile(configDir, fs) {
|
|
|
14665
14753
|
}
|
|
14666
14754
|
async function deleteApiKey(configDir, fs) {
|
|
14667
14755
|
const [keychain, file] = await Promise.all([
|
|
14668
|
-
|
|
14756
|
+
deleteFromKeychain(),
|
|
14669
14757
|
deleteFromFile(configDir, fs)
|
|
14670
14758
|
]);
|
|
14671
14759
|
return { keychain, file };
|
|
14672
14760
|
}
|
|
14673
14761
|
// src/domains/auth/store/hasStoredCredentials.ts
|
|
14674
14762
|
import { join as join3 } from "node:path";
|
|
14675
|
-
import { Entry as Entry2 } from "@napi-rs/keyring";
|
|
14676
14763
|
async function fileExists(path, fs) {
|
|
14677
14764
|
try {
|
|
14678
14765
|
await fs.readFile(path);
|
|
@@ -14681,9 +14768,10 @@ async function fileExists(path, fs) {
|
|
|
14681
14768
|
return !isNoEntError(err);
|
|
14682
14769
|
}
|
|
14683
14770
|
}
|
|
14684
|
-
function keychainHolds(entryAccount) {
|
|
14771
|
+
async function keychainHolds(entryAccount) {
|
|
14685
14772
|
try {
|
|
14686
|
-
|
|
14773
|
+
const Entry = await loadEntryClass();
|
|
14774
|
+
return Boolean(new Entry(service, entryAccount).getPassword());
|
|
14687
14775
|
} catch {
|
|
14688
14776
|
return false;
|
|
14689
14777
|
}
|
|
@@ -14693,7 +14781,9 @@ async function hasStoredCredentials(configDir, fs) {
|
|
|
14693
14781
|
fileExists(join3(configDir, credentialsFile), fs),
|
|
14694
14782
|
fileExists(join3(configDir, tokensFile), fs)
|
|
14695
14783
|
]);
|
|
14696
|
-
|
|
14784
|
+
if (apiKeyFile || tokenFile)
|
|
14785
|
+
return true;
|
|
14786
|
+
return await keychainHolds(account) || await keychainHolds(tokensAccount);
|
|
14697
14787
|
}
|
|
14698
14788
|
// src/domains/auth/store/load.ts
|
|
14699
14789
|
import { join as join4 } from "node:path";
|
|
@@ -14716,7 +14806,8 @@ var oauthTokensSchema = object({
|
|
|
14716
14806
|
async function loadApiKey(configDir, deps) {
|
|
14717
14807
|
const errors = {};
|
|
14718
14808
|
try {
|
|
14719
|
-
const
|
|
14809
|
+
const Entry = await deps.loadEntryClass();
|
|
14810
|
+
const entry = new Entry(service, account);
|
|
14720
14811
|
const key = entry.getPassword();
|
|
14721
14812
|
if (key)
|
|
14722
14813
|
return { found: true, key, source: "keychain" };
|
|
@@ -14737,7 +14828,6 @@ async function loadApiKey(configDir, deps) {
|
|
|
14737
14828
|
}
|
|
14738
14829
|
// src/domains/auth/store/save.ts
|
|
14739
14830
|
import { join as join5 } from "node:path";
|
|
14740
|
-
import { Entry as Entry3 } from "@napi-rs/keyring";
|
|
14741
14831
|
async function saveToFile(configDir, key, fs) {
|
|
14742
14832
|
const payload = { apiKey: key };
|
|
14743
14833
|
await fs.mkdir(configDir, { recursive: true, mode: 448 });
|
|
@@ -14745,7 +14835,8 @@ async function saveToFile(configDir, key, fs) {
|
|
|
14745
14835
|
}
|
|
14746
14836
|
async function saveApiKey(configDir, key, fs) {
|
|
14747
14837
|
try {
|
|
14748
|
-
const
|
|
14838
|
+
const Entry = await loadEntryClass();
|
|
14839
|
+
const entry = new Entry(service, account);
|
|
14749
14840
|
entry.setPassword(key);
|
|
14750
14841
|
return { stored: "keychain" };
|
|
14751
14842
|
} catch (err) {
|
|
@@ -14773,7 +14864,8 @@ function parseTokens(raw) {
|
|
|
14773
14864
|
async function loadTokens(configDir, deps) {
|
|
14774
14865
|
const errors = {};
|
|
14775
14866
|
try {
|
|
14776
|
-
const
|
|
14867
|
+
const Entry = await deps.loadEntryClass();
|
|
14868
|
+
const raw = new Entry(service, tokensAccount).getPassword();
|
|
14777
14869
|
if (raw) {
|
|
14778
14870
|
const tokens = parseTokens(raw);
|
|
14779
14871
|
if (tokens)
|
|
@@ -14798,7 +14890,6 @@ async function loadTokens(configDir, deps) {
|
|
|
14798
14890
|
// src/domains/auth/store/saveTokens.ts
|
|
14799
14891
|
import { randomUUID } from "node:crypto";
|
|
14800
14892
|
import { join as join7 } from "node:path";
|
|
14801
|
-
import { Entry as Entry4 } from "@napi-rs/keyring";
|
|
14802
14893
|
async function saveToFile2(configDir, tokens, fs) {
|
|
14803
14894
|
await fs.mkdir(configDir, { recursive: true, mode: 448 });
|
|
14804
14895
|
const target = join7(configDir, tokensFile);
|
|
@@ -14815,11 +14906,13 @@ async function saveToFile2(configDir, tokens, fs) {
|
|
|
14815
14906
|
}
|
|
14816
14907
|
async function saveTokens(configDir, tokens, fs) {
|
|
14817
14908
|
try {
|
|
14818
|
-
|
|
14909
|
+
const Entry = await loadEntryClass();
|
|
14910
|
+
new Entry(service, tokensAccount).setPassword(JSON.stringify(tokens));
|
|
14819
14911
|
return { stored: "keychain" };
|
|
14820
14912
|
} catch (err) {
|
|
14821
14913
|
try {
|
|
14822
|
-
|
|
14914
|
+
const Entry = await loadEntryClass();
|
|
14915
|
+
new Entry(service, tokensAccount).deletePassword();
|
|
14823
14916
|
} catch {}
|
|
14824
14917
|
await saveToFile2(configDir, tokens, fs);
|
|
14825
14918
|
return { stored: "file", keychainError: errorMessage(err) };
|
|
@@ -14882,7 +14975,7 @@ async function resolveOauthToken(configDir, deps) {
|
|
|
14882
14975
|
// src/domains/auth/resolve.ts
|
|
14883
14976
|
function makeOauthDeps(fs) {
|
|
14884
14977
|
return {
|
|
14885
|
-
loadTokens: (configDir) => loadTokens(configDir, {
|
|
14978
|
+
loadTokens: (configDir) => loadTokens(configDir, { loadEntryClass, fs }),
|
|
14886
14979
|
refreshTokens: async ({ refreshToken, organizationId, clientId }) => {
|
|
14887
14980
|
const config = resolveWorkosConfig(clientId);
|
|
14888
14981
|
if (!config.configured) {
|
|
@@ -14904,7 +14997,7 @@ function makeOauthDeps(fs) {
|
|
|
14904
14997
|
}
|
|
14905
14998
|
function makeDefaultDeps(fs) {
|
|
14906
14999
|
return {
|
|
14907
|
-
loadApiKey: (configDir) => loadApiKey(configDir, {
|
|
15000
|
+
loadApiKey: (configDir) => loadApiKey(configDir, { loadEntryClass, fs }),
|
|
14908
15001
|
resolveOauth: (configDir) => resolveOauthToken(configDir, makeOauthDeps(fs)),
|
|
14909
15002
|
env: process.env
|
|
14910
15003
|
};
|
|
@@ -18988,7 +19081,8 @@ var environmentListItemSchema = object({
|
|
|
18988
19081
|
slug: string2()
|
|
18989
19082
|
});
|
|
18990
19083
|
var environmentWithVariablesResponseSchema = object({
|
|
18991
|
-
environmentVariables: record(string2(), string2())
|
|
19084
|
+
environmentVariables: record(string2(), string2()),
|
|
19085
|
+
teamId: string2()
|
|
18992
19086
|
});
|
|
18993
19087
|
var flowListItemSchema = object({
|
|
18994
19088
|
flowId: string2(),
|
|
@@ -19265,7 +19359,10 @@ async function writeTeamStorageAssets(args, deps) {
|
|
|
19265
19359
|
|
|
19266
19360
|
// src/shell/platform/teamStorageMethods.ts
|
|
19267
19361
|
function createTeamStorageMethods(trpc, deps, fs, getIdentity) {
|
|
19268
|
-
async function list() {
|
|
19362
|
+
async function list(opts) {
|
|
19363
|
+
if (opts?.teamId !== undefined) {
|
|
19364
|
+
return listTeamStorageFiles(trpc, { teamId: opts.teamId }, deps);
|
|
19365
|
+
}
|
|
19269
19366
|
if (deps.workspaceId !== undefined) {
|
|
19270
19367
|
return listTeamStorageFiles(trpc, { teamId: deps.workspaceId }, deps);
|
|
19271
19368
|
}
|
|
@@ -19275,7 +19372,7 @@ function createTeamStorageMethods(trpc, deps, fs, getIdentity) {
|
|
|
19275
19372
|
if (!("team" in identity.value)) {
|
|
19276
19373
|
return {
|
|
19277
19374
|
ok: false,
|
|
19278
|
-
error: flowsMessages.pull.
|
|
19375
|
+
error: flowsMessages.pull.teamStorageRequiresTeam
|
|
19279
19376
|
};
|
|
19280
19377
|
}
|
|
19281
19378
|
return listTeamStorageFiles(trpc, { teamId: identity.value.team.id }, deps);
|
|
@@ -19283,7 +19380,7 @@ function createTeamStorageMethods(trpc, deps, fs, getIdentity) {
|
|
|
19283
19380
|
return {
|
|
19284
19381
|
listTeamStorageFiles: list,
|
|
19285
19382
|
async syncTeamStorageAssets(assetsAbs, opts) {
|
|
19286
|
-
const files = await list();
|
|
19383
|
+
const files = await list({ teamId: opts?.teamId });
|
|
19287
19384
|
if (!files.ok)
|
|
19288
19385
|
return files;
|
|
19289
19386
|
return downloadTeamStorageAssets({ assetsAbs, files: files.value }, { fetch: deps.fetch, fs, onProgress: opts?.onProgress });
|
|
@@ -19313,16 +19410,14 @@ function createPlatformClient(apiKey, deps) {
|
|
|
19313
19410
|
...createTeamStorageMethods(trpc, deps, fs, identityMethods.getIdentity),
|
|
19314
19411
|
getFlowsBundleUrl: getFlowsBundleUrlImpl,
|
|
19315
19412
|
callPublicApi: makeCallPublicApiMethod(trpc, deps, requestBackoffMs2),
|
|
19316
|
-
async
|
|
19413
|
+
async getEnvironmentWithVariables(envId) {
|
|
19317
19414
|
const result = await requestWithRetry({
|
|
19318
19415
|
call: () => trpc.query("environment.getEnvironmentWithVariables", { id: envId }, environmentWithVariablesResponseSchema),
|
|
19319
19416
|
backoffMs: requestBackoffMs2,
|
|
19320
19417
|
describe: (err) => describeRequestError(err, deps.baseUrl, "env-vars"),
|
|
19321
19418
|
sleep: deps.sleep
|
|
19322
19419
|
});
|
|
19323
|
-
|
|
19324
|
-
return result;
|
|
19325
|
-
return { ok: true, value: result.value.environmentVariables };
|
|
19420
|
+
return result;
|
|
19326
19421
|
},
|
|
19327
19422
|
async downloadBundle(envId) {
|
|
19328
19423
|
const urlResult = await getFlowsBundleUrlImpl(envId);
|
|
@@ -20142,6 +20237,30 @@ class a extends V {
|
|
|
20142
20237
|
});
|
|
20143
20238
|
}
|
|
20144
20239
|
}
|
|
20240
|
+
class n extends V {
|
|
20241
|
+
get userInputWithCursor() {
|
|
20242
|
+
if (this.state === "submit")
|
|
20243
|
+
return this.userInput;
|
|
20244
|
+
const t = this.userInput;
|
|
20245
|
+
if (this.cursor >= t.length)
|
|
20246
|
+
return `${this.userInput}█`;
|
|
20247
|
+
const e = t.slice(0, this.cursor), [s, ...r] = t.slice(this.cursor);
|
|
20248
|
+
return `${e}${styleText("inverse", s)}${r.join("")}`;
|
|
20249
|
+
}
|
|
20250
|
+
get cursor() {
|
|
20251
|
+
return this._cursor;
|
|
20252
|
+
}
|
|
20253
|
+
constructor(t) {
|
|
20254
|
+
super({
|
|
20255
|
+
...t,
|
|
20256
|
+
initialUserInput: t.initialUserInput ?? t.initialValue
|
|
20257
|
+
}), this.on("userInput", (e) => {
|
|
20258
|
+
this._setValue(e);
|
|
20259
|
+
}), this.on("finalize", () => {
|
|
20260
|
+
this.value || (this.value = t.defaultValue), this.value === undefined && (this.value = "");
|
|
20261
|
+
});
|
|
20262
|
+
}
|
|
20263
|
+
}
|
|
20145
20264
|
|
|
20146
20265
|
// node_modules/@clack/prompts/dist/index.mjs
|
|
20147
20266
|
import { styleText as styleText2, stripVTControlCharacters } from "node:util";
|
|
@@ -20752,14 +20871,56 @@ ${e.value}` : e.value;
|
|
|
20752
20871
|
}
|
|
20753
20872
|
};
|
|
20754
20873
|
};
|
|
20874
|
+
var text = (t) => new n({
|
|
20875
|
+
validate: t.validate,
|
|
20876
|
+
placeholder: t.placeholder,
|
|
20877
|
+
defaultValue: t.defaultValue,
|
|
20878
|
+
initialValue: t.initialValue,
|
|
20879
|
+
output: t.output,
|
|
20880
|
+
signal: t.signal,
|
|
20881
|
+
input: t.input,
|
|
20882
|
+
render() {
|
|
20883
|
+
const i = t?.withGuide ?? settings.withGuide, s = `${`${i ? `${styleText2("gray", S_BAR)}
|
|
20884
|
+
` : ""}${symbol(this.state)} `}${t.message}
|
|
20885
|
+
`, c = t.placeholder ? styleText2("inverse", t.placeholder[0]) + styleText2("dim", t.placeholder.slice(1)) : styleText2(["inverse", "hidden"], "_"), o = this.userInput ? this.userInputWithCursor : c, a = this.value ?? "";
|
|
20886
|
+
switch (this.state) {
|
|
20887
|
+
case "error": {
|
|
20888
|
+
const n = this.error ? ` ${styleText2("yellow", this.error)}` : "", r = i ? `${styleText2("yellow", S_BAR)} ` : "", d = i ? styleText2("yellow", S_BAR_END) : "";
|
|
20889
|
+
return `${s.trim()}
|
|
20890
|
+
${r}${o}
|
|
20891
|
+
${d}${n}
|
|
20892
|
+
`;
|
|
20893
|
+
}
|
|
20894
|
+
case "submit": {
|
|
20895
|
+
const n = a ? ` ${styleText2("dim", a)}` : "", r = i ? styleText2("gray", S_BAR) : "";
|
|
20896
|
+
return `${s}${r}${n}`;
|
|
20897
|
+
}
|
|
20898
|
+
case "cancel": {
|
|
20899
|
+
const n = a ? ` ${styleText2(["strikethrough", "dim"], a)}` : "", r = i ? styleText2("gray", S_BAR) : "";
|
|
20900
|
+
return `${s}${r}${n}${a.trim() ? `
|
|
20901
|
+
${r}` : ""}`;
|
|
20902
|
+
}
|
|
20903
|
+
default: {
|
|
20904
|
+
const n = i ? `${styleText2("cyan", S_BAR)} ` : "", r = i ? styleText2("cyan", S_BAR_END) : "";
|
|
20905
|
+
return `${s}${n}${o}
|
|
20906
|
+
${r}
|
|
20907
|
+
`;
|
|
20908
|
+
}
|
|
20909
|
+
}
|
|
20910
|
+
}
|
|
20911
|
+
}).prompt();
|
|
20755
20912
|
|
|
20756
20913
|
// src/shell/ui/clack/theme.ts
|
|
20914
|
+
import { styleText as styleText3 } from "node:util";
|
|
20757
20915
|
var qaWolfBlueBg = "\x1B[48;2;59;59;239m";
|
|
20758
20916
|
var whiteBold = "\x1B[97;1m";
|
|
20759
20917
|
var reset = "\x1B[0m";
|
|
20760
20918
|
function styledTitle(title) {
|
|
20761
20919
|
return `${qaWolfBlueBg}${whiteBold} ${title} ${reset}`;
|
|
20762
20920
|
}
|
|
20921
|
+
function replySymbol() {
|
|
20922
|
+
return styleText3("cyan", "◇");
|
|
20923
|
+
}
|
|
20763
20924
|
|
|
20764
20925
|
// src/shell/ui/clack/styledClack.ts
|
|
20765
20926
|
function createStyledClack() {
|
|
@@ -20770,6 +20931,7 @@ function createStyledClack() {
|
|
|
20770
20931
|
cancel,
|
|
20771
20932
|
confirm,
|
|
20772
20933
|
password,
|
|
20934
|
+
text,
|
|
20773
20935
|
autocomplete,
|
|
20774
20936
|
select,
|
|
20775
20937
|
isCancel,
|
|
@@ -20873,6 +21035,12 @@ function createAgentRenderers() {
|
|
|
20873
21035
|
gap: () => writeStderrLine(""),
|
|
20874
21036
|
stream: (_data, line) => writeStdoutRaw(`${line}
|
|
20875
21037
|
`),
|
|
21038
|
+
transcript: ({ body, headline }) => writeStdoutRaw(`**${headline}**
|
|
21039
|
+
|
|
21040
|
+
${body}
|
|
21041
|
+
|
|
21042
|
+
`),
|
|
21043
|
+
wait: () => ({ stop: () => {} }),
|
|
20876
21044
|
write: (text) => writeStderrRaw(text),
|
|
20877
21045
|
withProgress: async (steps, done) => {
|
|
20878
21046
|
const results = [];
|
|
@@ -20889,7 +21057,69 @@ function createAgentRenderers() {
|
|
|
20889
21057
|
};
|
|
20890
21058
|
}
|
|
20891
21059
|
|
|
21060
|
+
// src/core/wrapText.ts
|
|
21061
|
+
function wrapLine(rawLine, width) {
|
|
21062
|
+
const line = rawLine.trimEnd();
|
|
21063
|
+
if (line.length <= width)
|
|
21064
|
+
return [line];
|
|
21065
|
+
const indent = /^\s*/.exec(line)?.[0] ?? "";
|
|
21066
|
+
const lines = [];
|
|
21067
|
+
let current = "";
|
|
21068
|
+
for (const word of line.trimStart().split(" ")) {
|
|
21069
|
+
if (current === "") {
|
|
21070
|
+
current = word;
|
|
21071
|
+
} else if (indent.length + current.length + 1 + word.length <= width) {
|
|
21072
|
+
current = `${current} ${word}`;
|
|
21073
|
+
} else {
|
|
21074
|
+
lines.push(indent + current);
|
|
21075
|
+
current = word;
|
|
21076
|
+
}
|
|
21077
|
+
}
|
|
21078
|
+
lines.push(indent + current);
|
|
21079
|
+
return lines;
|
|
21080
|
+
}
|
|
21081
|
+
function wrapText(text, width) {
|
|
21082
|
+
return text.split(`
|
|
21083
|
+
`).flatMap((line) => wrapLine(line, width)).join(`
|
|
21084
|
+
`);
|
|
21085
|
+
}
|
|
21086
|
+
|
|
21087
|
+
// src/shell/ui/renderers/waitLine.ts
|
|
21088
|
+
import { styleText as styleText4 } from "node:util";
|
|
21089
|
+
var frames = ["◒", "◐", "◓", "◑"];
|
|
21090
|
+
var frameMs = 120;
|
|
21091
|
+
function elapsed(sinceMs) {
|
|
21092
|
+
const seconds = Math.floor((Date.now() - sinceMs) / 1000);
|
|
21093
|
+
const minutes = Math.floor(seconds / 60);
|
|
21094
|
+
return minutes > 0 ? `[${minutes}m ${seconds % 60}s]` : `[${seconds}s]`;
|
|
21095
|
+
}
|
|
21096
|
+
function startWaitLine(message, output = process.stdout) {
|
|
21097
|
+
const startedAt = Date.now();
|
|
21098
|
+
let frame = 0;
|
|
21099
|
+
const draw = () => {
|
|
21100
|
+
const mark = styleText4("magenta", frames[frame] ?? "◒");
|
|
21101
|
+
output.write(`\r\x1B[2K${mark} ${message} ${elapsed(startedAt)}`);
|
|
21102
|
+
frame = (frame + 1) % frames.length;
|
|
21103
|
+
};
|
|
21104
|
+
draw();
|
|
21105
|
+
const timer = setInterval(draw, frameMs);
|
|
21106
|
+
let stopped = false;
|
|
21107
|
+
return {
|
|
21108
|
+
stop: () => {
|
|
21109
|
+
if (stopped)
|
|
21110
|
+
return;
|
|
21111
|
+
stopped = true;
|
|
21112
|
+
clearInterval(timer);
|
|
21113
|
+
output.write("\r\x1B[2K");
|
|
21114
|
+
}
|
|
21115
|
+
};
|
|
21116
|
+
}
|
|
21117
|
+
|
|
20892
21118
|
// src/shell/ui/renderers/modes/human.ts
|
|
21119
|
+
function transcriptWidth() {
|
|
21120
|
+
const columns = process.stdout.columns || 80;
|
|
21121
|
+
return Math.min(Math.max(columns - 4, 20), 100);
|
|
21122
|
+
}
|
|
20893
21123
|
function createHumanRenderers(clack, verboseTarget) {
|
|
20894
21124
|
return {
|
|
20895
21125
|
intro: (title) => clack.intro(title),
|
|
@@ -20911,6 +21141,12 @@ ${body}` : ""));
|
|
|
20911
21141
|
`),
|
|
20912
21142
|
stream: (_data, line) => writeStdoutRaw(`${line}
|
|
20913
21143
|
`),
|
|
21144
|
+
transcript: ({ body, headline }) => {
|
|
21145
|
+
const lines = wrapText(body, transcriptWidth()).split(`
|
|
21146
|
+
`);
|
|
21147
|
+
clack.log.message([headline, ...lines], { symbol: replySymbol() });
|
|
21148
|
+
},
|
|
21149
|
+
wait: (message) => startWaitLine(message),
|
|
20914
21150
|
write: (text) => writeStdoutRaw(text),
|
|
20915
21151
|
withProgress: async (steps, done) => {
|
|
20916
21152
|
const results = [];
|
|
@@ -20984,6 +21220,8 @@ function createJsonRenderers() {
|
|
|
20984
21220
|
output: (data, _humanMessage) => writeJsonLine(data),
|
|
20985
21221
|
gap: () => {},
|
|
20986
21222
|
stream: (data, _line) => writeJsonLine(data),
|
|
21223
|
+
transcript: ({ data }) => writeJsonLine(data),
|
|
21224
|
+
wait: () => ({ stop: () => {} }),
|
|
20987
21225
|
write: () => {},
|
|
20988
21226
|
withProgress: async (steps, done) => {
|
|
20989
21227
|
const results = [];
|
|
@@ -21080,6 +21318,20 @@ function createSelect({ mode, clack }) {
|
|
|
21080
21318
|
};
|
|
21081
21319
|
}
|
|
21082
21320
|
|
|
21321
|
+
// src/shell/ui/renderers/text.ts
|
|
21322
|
+
function createText({ mode, clack }) {
|
|
21323
|
+
return async (message) => {
|
|
21324
|
+
assertHumanMode(mode, "text");
|
|
21325
|
+
const value = await clack.text({ message });
|
|
21326
|
+
if (clack.isCancel(value))
|
|
21327
|
+
return { ok: false };
|
|
21328
|
+
const answer = value.trim();
|
|
21329
|
+
if (answer.length === 0)
|
|
21330
|
+
return { ok: false };
|
|
21331
|
+
return { ok: true, value: answer };
|
|
21332
|
+
};
|
|
21333
|
+
}
|
|
21334
|
+
|
|
21083
21335
|
// src/shell/ui/createUi.ts
|
|
21084
21336
|
function createUI(mode, opts = {}) {
|
|
21085
21337
|
const clack = opts.clack ?? createStyledClack();
|
|
@@ -21089,6 +21341,7 @@ function createUI(mode, opts = {}) {
|
|
|
21089
21341
|
confirm: createConfirm({ mode, clack }),
|
|
21090
21342
|
password: createPassword({ mode, clack }),
|
|
21091
21343
|
select: createSelect({ mode, clack }),
|
|
21344
|
+
text: createText({ mode, clack }),
|
|
21092
21345
|
json: createJson()
|
|
21093
21346
|
};
|
|
21094
21347
|
}
|
|
@@ -21213,7 +21466,7 @@ function startUpdateCheck(deps) {
|
|
|
21213
21466
|
// package.json
|
|
21214
21467
|
var package_default = {
|
|
21215
21468
|
name: "@qawolf/cli",
|
|
21216
|
-
version: "1.
|
|
21469
|
+
version: "1.30.0",
|
|
21217
21470
|
description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
21218
21471
|
keywords: [
|
|
21219
21472
|
"automation",
|
|
@@ -21288,7 +21541,7 @@ var package_default = {
|
|
|
21288
21541
|
"@qawolf/emails": "1.1.1",
|
|
21289
21542
|
"@qawolf/flow-targets": "1.0.0",
|
|
21290
21543
|
"@qawolf/flows": "0.1.4",
|
|
21291
|
-
"@qawolf/testkit": "1.
|
|
21544
|
+
"@qawolf/testkit": "1.2.1",
|
|
21292
21545
|
commander: "14.0.3",
|
|
21293
21546
|
"env-paths": "4.0.0",
|
|
21294
21547
|
picomatch: "4.0.4",
|
|
@@ -21429,111 +21682,576 @@ function withAuthContext(signals, fn, deps = {}) {
|
|
|
21429
21682
|
};
|
|
21430
21683
|
}
|
|
21431
21684
|
|
|
21432
|
-
// src/
|
|
21433
|
-
|
|
21434
|
-
|
|
21435
|
-
|
|
21436
|
-
|
|
21685
|
+
// src/core/agent/session.ts
|
|
21686
|
+
var defaultAgentFollowTimeoutSeconds = 1800;
|
|
21687
|
+
var settledStatuses = [
|
|
21688
|
+
"cancelled",
|
|
21689
|
+
"completed",
|
|
21690
|
+
"failed"
|
|
21691
|
+
];
|
|
21692
|
+
function isSettled(status) {
|
|
21693
|
+
return settledStatuses.includes(status);
|
|
21694
|
+
}
|
|
21695
|
+
function pendingQuestion(status, replies) {
|
|
21696
|
+
if (status !== "waiting-for-you")
|
|
21437
21697
|
return;
|
|
21438
|
-
|
|
21439
|
-
|
|
21440
|
-
|
|
21441
|
-
|
|
21698
|
+
return replies[replies.length - 1];
|
|
21699
|
+
}
|
|
21700
|
+
|
|
21701
|
+
// src/core/agent/formatReply.ts
|
|
21702
|
+
var speaker = "QA Wolf";
|
|
21703
|
+
function replyTime(askedAt) {
|
|
21704
|
+
const at = new Date(askedAt);
|
|
21705
|
+
if (Number.isNaN(at.getTime()))
|
|
21706
|
+
return;
|
|
21707
|
+
return at.toTimeString().slice(0, 8);
|
|
21708
|
+
}
|
|
21709
|
+
function replyParts(reply, options) {
|
|
21710
|
+
const time = replyTime(reply.askedAt);
|
|
21711
|
+
const choices = options.listChoices && reply.choices !== undefined ? ["", ...reply.choices.map((choice) => `- ${choice}`)] : [];
|
|
21712
|
+
return {
|
|
21713
|
+
body: [reply.text.trim(), ...choices].join(`
|
|
21714
|
+
`),
|
|
21715
|
+
headline: time === undefined ? speaker : `${speaker} ${time}`
|
|
21716
|
+
};
|
|
21717
|
+
}
|
|
21718
|
+
|
|
21719
|
+
// src/core/followTimeout.ts
|
|
21720
|
+
var followTimeoutSchema = exports_coerce.number().int().positive();
|
|
21721
|
+
function parseFollowTimeout(seconds, defaultSeconds) {
|
|
21722
|
+
if (seconds === undefined)
|
|
21723
|
+
return { ok: true, seconds: defaultSeconds };
|
|
21724
|
+
const parsed = followTimeoutSchema.safeParse(seconds);
|
|
21725
|
+
if (!parsed.success)
|
|
21726
|
+
return { error: prettifyError(parsed.error), ok: false };
|
|
21727
|
+
return { ok: true, seconds: parsed.data };
|
|
21728
|
+
}
|
|
21729
|
+
|
|
21730
|
+
// src/domains/agent/settlement.ts
|
|
21731
|
+
function endWithSession(ctx, session) {
|
|
21732
|
+
if (ctx.ui.mode !== "human")
|
|
21733
|
+
ctx.ui.json(session);
|
|
21734
|
+
}
|
|
21735
|
+
function reportSettlement(ctx, session) {
|
|
21736
|
+
endWithSession(ctx, session);
|
|
21737
|
+
if (session.status === "completed") {
|
|
21738
|
+
ctx.ui.success(agentMessages.sessionCompleted);
|
|
21442
21739
|
return;
|
|
21443
21740
|
}
|
|
21444
|
-
|
|
21445
|
-
|
|
21446
|
-
|
|
21447
|
-
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
|
|
21452
|
-
|
|
21741
|
+
return {
|
|
21742
|
+
error: session.status === "cancelled" ? agentMessages.sessionCancelled(session.url) : agentMessages.sessionFailed(session.url),
|
|
21743
|
+
exitCode: exitCodes.testFailure
|
|
21744
|
+
};
|
|
21745
|
+
}
|
|
21746
|
+
|
|
21747
|
+
// src/domains/agent/answerQuestion.ts
|
|
21748
|
+
async function ask(ctx, question) {
|
|
21749
|
+
const choices = question.choices ?? [];
|
|
21750
|
+
const answer = choices.length > 0 ? await ctx.ui.select(agentMessages.answerPrompt, choices.map((choice) => ({ label: choice, value: choice }))) : await ctx.ui.text(agentMessages.answerPrompt);
|
|
21751
|
+
return answer.ok ? answer.value : undefined;
|
|
21752
|
+
}
|
|
21753
|
+
async function answerQuestion(ctx, options) {
|
|
21754
|
+
const answer = await ask(ctx, options.question);
|
|
21755
|
+
if (answer === undefined) {
|
|
21756
|
+
ctx.ui.warn(agentMessages.answerCancelled);
|
|
21757
|
+
return { type: "declined" };
|
|
21758
|
+
}
|
|
21759
|
+
const sent = await ctx.platformClient.callPublicApi(publicContractsV1.agent.send, {
|
|
21760
|
+
message: answer,
|
|
21761
|
+
sessionId: options.sessionId,
|
|
21762
|
+
...options.workspaceId === undefined ? {} : { workspaceId: options.workspaceId }
|
|
21763
|
+
});
|
|
21764
|
+
if (!sent.ok) {
|
|
21765
|
+
const failure = failureFields(sent);
|
|
21766
|
+
return {
|
|
21767
|
+
result: {
|
|
21768
|
+
exitCode: exitCodes.network,
|
|
21769
|
+
...failure,
|
|
21770
|
+
error: agentMessages.answerSendFailed(failure.error)
|
|
21771
|
+
},
|
|
21772
|
+
type: "failed"
|
|
21773
|
+
};
|
|
21774
|
+
}
|
|
21775
|
+
return { repliesAtAnswer: options.repliesSoFar, type: "answered" };
|
|
21776
|
+
}
|
|
21777
|
+
async function handleQuestion(ctx, options) {
|
|
21778
|
+
const { session, sessionId } = options;
|
|
21779
|
+
if (!options.canPrompt) {
|
|
21780
|
+
ctx.ui.info(agentMessages.blocked(sessionId));
|
|
21781
|
+
endWithSession(ctx, session);
|
|
21782
|
+
return { result: undefined, type: "ended" };
|
|
21783
|
+
}
|
|
21784
|
+
const outcome = await answerQuestion(ctx, {
|
|
21785
|
+
question: options.question,
|
|
21786
|
+
repliesSoFar: session.replies.length,
|
|
21787
|
+
sessionId,
|
|
21788
|
+
workspaceId: options.workspaceId
|
|
21789
|
+
});
|
|
21790
|
+
if (outcome.type === "failed")
|
|
21791
|
+
return { result: outcome.result, type: "ended" };
|
|
21792
|
+
if (outcome.type === "declined")
|
|
21793
|
+
return { result: undefined, type: "ended" };
|
|
21794
|
+
return outcome;
|
|
21795
|
+
}
|
|
21796
|
+
|
|
21797
|
+
// src/domains/agent/followSession.ts
|
|
21798
|
+
var pollIntervalMs = 5000;
|
|
21799
|
+
async function followSession(ctx, options, deps) {
|
|
21800
|
+
const { sessionId, workspaceId } = options;
|
|
21801
|
+
const canPrompt = ctx.ui.mode === "human" && ctx.isInteractive;
|
|
21802
|
+
const startedAt = deps.now();
|
|
21803
|
+
let promptedMs = 0;
|
|
21804
|
+
const timedOut = () => deps.now() - startedAt - promptedMs >= options.timeoutSeconds * 1000;
|
|
21805
|
+
let pending = options.initial;
|
|
21806
|
+
let printed = 0;
|
|
21807
|
+
let { repliesAtAnswer } = options;
|
|
21808
|
+
let saidDetachHint = false;
|
|
21809
|
+
let waiting;
|
|
21810
|
+
const stopWaiting = () => {
|
|
21811
|
+
waiting?.stop();
|
|
21812
|
+
waiting = undefined;
|
|
21813
|
+
};
|
|
21814
|
+
const detach = ctx.signals.register(() => {
|
|
21815
|
+
stopWaiting();
|
|
21816
|
+
ctx.ui.info(agentMessages.detached(sessionId));
|
|
21817
|
+
});
|
|
21818
|
+
try {
|
|
21819
|
+
for (let poll = 1;; poll++) {
|
|
21820
|
+
let session;
|
|
21821
|
+
if (pending !== undefined) {
|
|
21822
|
+
session = pending;
|
|
21823
|
+
pending = undefined;
|
|
21824
|
+
} else {
|
|
21825
|
+
const read = await ctx.platformClient.callPublicApi(publicContractsV1.agent.get, { sessionId });
|
|
21826
|
+
if (!read.ok) {
|
|
21827
|
+
return { exitCode: exitCodes.network, ...failureFields(read) };
|
|
21828
|
+
}
|
|
21829
|
+
session = read.value;
|
|
21830
|
+
}
|
|
21831
|
+
const { replies, status } = session;
|
|
21832
|
+
const fresh = replies.slice(printed);
|
|
21833
|
+
printed = replies.length;
|
|
21834
|
+
if (fresh.length > 0)
|
|
21835
|
+
stopWaiting();
|
|
21836
|
+
for (const reply of fresh) {
|
|
21837
|
+
ctx.ui.transcript({
|
|
21838
|
+
...replyParts(reply, { listChoices: !canPrompt }),
|
|
21839
|
+
data: reply
|
|
21453
21840
|
});
|
|
21454
|
-
if (!v.valid)
|
|
21455
|
-
throw Error(v.error);
|
|
21456
21841
|
}
|
|
21457
|
-
|
|
21458
|
-
|
|
21459
|
-
|
|
21460
|
-
|
|
21842
|
+
if (poll === 1 && replies.length === 0 && !isSettled(status)) {
|
|
21843
|
+
ctx.ui.info(agentMessages.working);
|
|
21844
|
+
}
|
|
21845
|
+
if (isSettled(status)) {
|
|
21846
|
+
stopWaiting();
|
|
21847
|
+
return reportSettlement(ctx, session);
|
|
21848
|
+
}
|
|
21849
|
+
const question = pendingQuestion(status, replies);
|
|
21850
|
+
const awaitingOurAnswer = repliesAtAnswer !== undefined && replies.length <= repliesAtAnswer;
|
|
21851
|
+
if (question !== undefined && !awaitingOurAnswer) {
|
|
21852
|
+
stopWaiting();
|
|
21853
|
+
const promptStartedAt = deps.now();
|
|
21854
|
+
const step = await handleQuestion(ctx, {
|
|
21855
|
+
canPrompt,
|
|
21856
|
+
question,
|
|
21857
|
+
session,
|
|
21858
|
+
sessionId,
|
|
21859
|
+
workspaceId
|
|
21860
|
+
});
|
|
21861
|
+
promptedMs += deps.now() - promptStartedAt;
|
|
21862
|
+
if (step.type === "ended")
|
|
21863
|
+
return step.result;
|
|
21864
|
+
repliesAtAnswer = step.repliesAtAnswer;
|
|
21865
|
+
}
|
|
21866
|
+
if (!saidDetachHint && ctx.ui.mode === "human") {
|
|
21867
|
+
saidDetachHint = true;
|
|
21868
|
+
ctx.ui.info(agentMessages.detachHint);
|
|
21869
|
+
}
|
|
21870
|
+
waiting ??= ctx.ui.wait(agentMessages.waiting);
|
|
21871
|
+
await deps.sleep(pollIntervalMs);
|
|
21872
|
+
if (timedOut()) {
|
|
21873
|
+
return {
|
|
21874
|
+
error: agentMessages.followTimedOut(sessionId, options.timeoutSeconds),
|
|
21875
|
+
exitCode: exitCodes.timeout
|
|
21876
|
+
};
|
|
21877
|
+
}
|
|
21461
21878
|
}
|
|
21462
|
-
|
|
21463
|
-
|
|
21464
|
-
|
|
21465
|
-
|
|
21879
|
+
} finally {
|
|
21880
|
+
stopWaiting();
|
|
21881
|
+
detach();
|
|
21882
|
+
}
|
|
21466
21883
|
}
|
|
21467
21884
|
|
|
21468
|
-
// src/core/
|
|
21469
|
-
|
|
21470
|
-
|
|
21471
|
-
|
|
21472
|
-
|
|
21885
|
+
// src/core/resolveId.ts
|
|
21886
|
+
async function resolveIdFrom(options) {
|
|
21887
|
+
if (options.given !== undefined)
|
|
21888
|
+
return options.given;
|
|
21889
|
+
const fromEnvironment = options.env[options.environmentVariable]?.trim();
|
|
21890
|
+
if (fromEnvironment)
|
|
21891
|
+
return fromEnvironment;
|
|
21892
|
+
return options.readStored();
|
|
21473
21893
|
}
|
|
21474
|
-
|
|
21475
|
-
|
|
21476
|
-
|
|
21477
|
-
|
|
21478
|
-
|
|
21479
|
-
|
|
21894
|
+
|
|
21895
|
+
// src/domains/agent/resolveSessionId.ts
|
|
21896
|
+
var sessionIdEnvironmentVariable = "QAWOLF_SESSION_ID";
|
|
21897
|
+
function chooseGivenSessionId(given) {
|
|
21898
|
+
const { argument, flag } = given;
|
|
21899
|
+
if (argument !== undefined && flag !== undefined && argument !== flag) {
|
|
21900
|
+
return { error: sessionGivenTwice(argument, flag), ok: false };
|
|
21480
21901
|
}
|
|
21481
|
-
|
|
21482
|
-
|
|
21483
|
-
|
|
21484
|
-
|
|
21485
|
-
|
|
21486
|
-
|
|
21487
|
-
|
|
21488
|
-
|
|
21489
|
-
|
|
21490
|
-
|
|
21491
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
};
|
|
21498
|
-
}
|
|
21499
|
-
case "denied":
|
|
21500
|
-
return { action: "fail", reason: "access-denied", detail: undefined };
|
|
21501
|
-
case "expired":
|
|
21502
|
-
return { action: "fail", reason: "expired", detail: undefined };
|
|
21503
|
-
case "unreachable": {
|
|
21504
|
-
const backedOff = {
|
|
21505
|
-
intervalMs: state.intervalMs * unreachableBackoffFactor,
|
|
21506
|
-
deadlineMs: state.deadlineMs
|
|
21507
|
-
};
|
|
21508
|
-
return {
|
|
21509
|
-
action: "poll",
|
|
21510
|
-
delayMs: capToLifetime(backedOff.intervalMs, backedOff, nowMs),
|
|
21511
|
-
state: backedOff
|
|
21512
|
-
};
|
|
21902
|
+
return { ok: true, sessionId: argument ?? flag };
|
|
21903
|
+
}
|
|
21904
|
+
var resolveSessionId = (session, deps) => resolveIdFrom({
|
|
21905
|
+
env: deps.env,
|
|
21906
|
+
environmentVariable: sessionIdEnvironmentVariable,
|
|
21907
|
+
given: session,
|
|
21908
|
+
readStored: deps.store.readLastSessionId
|
|
21909
|
+
});
|
|
21910
|
+
|
|
21911
|
+
// src/domains/agent/get.ts
|
|
21912
|
+
function renderSession(ctx, session) {
|
|
21913
|
+
if (ctx.ui.mode !== "json") {
|
|
21914
|
+
for (const reply of session.replies) {
|
|
21915
|
+
ctx.ui.transcript({
|
|
21916
|
+
...replyParts(reply, { listChoices: true }),
|
|
21917
|
+
data: reply
|
|
21918
|
+
});
|
|
21513
21919
|
}
|
|
21514
|
-
case "error":
|
|
21515
|
-
return { action: "fail", reason: "network", detail: response.detail };
|
|
21516
21920
|
}
|
|
21921
|
+
ctx.ui.output(session, agentMessages.standing(session.status, session.url));
|
|
21517
21922
|
}
|
|
21518
|
-
|
|
21519
|
-
|
|
21520
|
-
|
|
21521
|
-
|
|
21522
|
-
reason: "cancelled",
|
|
21523
|
-
detail: undefined
|
|
21524
|
-
};
|
|
21525
|
-
async function deviceLogin(deps) {
|
|
21526
|
-
if (deps.isCancelled())
|
|
21527
|
-
return cancelled;
|
|
21528
|
-
const authorization = await deps.requestAuthorization();
|
|
21529
|
-
if (!authorization.ok) {
|
|
21530
|
-
return { ok: false, reason: "unavailable", detail: authorization.error };
|
|
21923
|
+
async function handleAgentGet(ctx, options, deps) {
|
|
21924
|
+
const timeout = parseFollowTimeout(options.timeout, defaultAgentFollowTimeoutSeconds);
|
|
21925
|
+
if (!timeout.ok) {
|
|
21926
|
+
return { error: timeout.error, exitCode: exitCodes.invalidArgs };
|
|
21531
21927
|
}
|
|
21532
|
-
|
|
21533
|
-
|
|
21534
|
-
|
|
21535
|
-
|
|
21536
|
-
|
|
21928
|
+
const given = chooseGivenSessionId({
|
|
21929
|
+
argument: options.sessionArgument,
|
|
21930
|
+
flag: options.session
|
|
21931
|
+
});
|
|
21932
|
+
if (!given.ok) {
|
|
21933
|
+
return { error: given.error, exitCode: exitCodes.invalidArgs };
|
|
21934
|
+
}
|
|
21935
|
+
const sessionId = await resolveSessionId(given.sessionId, deps);
|
|
21936
|
+
if (sessionId === undefined) {
|
|
21937
|
+
return { error: agentMessages.noSession, exitCode: exitCodes.invalidArgs };
|
|
21938
|
+
}
|
|
21939
|
+
const read = await ctx.platformClient.callPublicApi(publicContractsV1.agent.get, { sessionId });
|
|
21940
|
+
if (!read.ok)
|
|
21941
|
+
return { exitCode: exitCodes.network, ...failureFields(read) };
|
|
21942
|
+
if (!options.follow) {
|
|
21943
|
+
renderSession(ctx, read.value);
|
|
21944
|
+
return;
|
|
21945
|
+
}
|
|
21946
|
+
ctx.ui.info(agentMessages.sessionAt(read.value.url));
|
|
21947
|
+
return followSession(ctx, {
|
|
21948
|
+
initial: read.value,
|
|
21949
|
+
repliesAtAnswer: undefined,
|
|
21950
|
+
sessionId,
|
|
21951
|
+
timeoutSeconds: timeout.seconds,
|
|
21952
|
+
workspaceId: options.workspaceId
|
|
21953
|
+
}, deps);
|
|
21954
|
+
}
|
|
21955
|
+
|
|
21956
|
+
// src/shell/agent/sessionStore.ts
|
|
21957
|
+
import { join as join14 } from "node:path";
|
|
21958
|
+
|
|
21959
|
+
// src/core/parseJson.ts
|
|
21960
|
+
function parseJson(text) {
|
|
21961
|
+
try {
|
|
21962
|
+
return JSON.parse(text);
|
|
21963
|
+
} catch {
|
|
21964
|
+
return;
|
|
21965
|
+
}
|
|
21966
|
+
}
|
|
21967
|
+
|
|
21968
|
+
// src/shell/jsonFile.ts
|
|
21969
|
+
var pendingWrites = 0;
|
|
21970
|
+
async function readJsonFile(fs, path, schema) {
|
|
21971
|
+
const contents = await fs.readFile(path).catch(() => {
|
|
21972
|
+
return;
|
|
21973
|
+
});
|
|
21974
|
+
if (contents === undefined)
|
|
21975
|
+
return;
|
|
21976
|
+
const parsed = schema.safeParse(parseJson(contents));
|
|
21977
|
+
return parsed.success ? parsed.data : undefined;
|
|
21978
|
+
}
|
|
21979
|
+
async function writeJsonFileAtomically(fs, path, value) {
|
|
21980
|
+
const pendingPath = `${path}.${String(process.pid)}.${String(++pendingWrites)}.tmp`;
|
|
21981
|
+
try {
|
|
21982
|
+
await fs.writeFile(pendingPath, `${JSON.stringify(value, undefined, 2)}
|
|
21983
|
+
`);
|
|
21984
|
+
await fs.rename(pendingPath, path);
|
|
21985
|
+
} finally {
|
|
21986
|
+
await fs.rm(pendingPath, { force: true }).catch(() => {});
|
|
21987
|
+
}
|
|
21988
|
+
}
|
|
21989
|
+
|
|
21990
|
+
// src/shell/agent/sessionStore.ts
|
|
21991
|
+
var storeFileName = "agent.json";
|
|
21992
|
+
var storeSchema = object({ lastSessionId: string2().optional() });
|
|
21993
|
+
function makeAgentSessionStore(options) {
|
|
21994
|
+
const directory = join14(options.cwd, qawolfDir);
|
|
21995
|
+
const path = join14(directory, storeFileName);
|
|
21996
|
+
return {
|
|
21997
|
+
async readLastSessionId() {
|
|
21998
|
+
const stored = await readJsonFile(options.fs, path, storeSchema);
|
|
21999
|
+
return stored?.lastSessionId;
|
|
22000
|
+
},
|
|
22001
|
+
async rememberSession(sessionId) {
|
|
22002
|
+
await options.fs.mkdir(directory, { recursive: true });
|
|
22003
|
+
await writeJsonFileAtomically(options.fs, path, {
|
|
22004
|
+
lastSessionId: sessionId
|
|
22005
|
+
});
|
|
22006
|
+
}
|
|
22007
|
+
};
|
|
22008
|
+
}
|
|
22009
|
+
|
|
22010
|
+
// src/domains/agent/deps.ts
|
|
22011
|
+
function makeAgentDeps(options) {
|
|
22012
|
+
return {
|
|
22013
|
+
env: options.env,
|
|
22014
|
+
now: Date.now,
|
|
22015
|
+
sleep,
|
|
22016
|
+
store: makeAgentSessionStore({ cwd: options.cwd, fs: options.fs })
|
|
22017
|
+
};
|
|
22018
|
+
}
|
|
22019
|
+
|
|
22020
|
+
// src/commands/agent/context.ts
|
|
22021
|
+
var sessionFlagDescription = `Session to target. Defaults to ${sessionIdEnvironmentVariable}, then the session this directory last started`;
|
|
22022
|
+
var timeoutFlagDescription = "Give up following after this long. A session that never settles would otherwise hold a CI job open until the build is killed";
|
|
22023
|
+
function agentDeps(ctx) {
|
|
22024
|
+
return makeAgentDeps({
|
|
22025
|
+
cwd: process.cwd(),
|
|
22026
|
+
env: process.env,
|
|
22027
|
+
fs: ctx.fs
|
|
22028
|
+
});
|
|
22029
|
+
}
|
|
22030
|
+
|
|
22031
|
+
// src/commands/agent/get.register.ts
|
|
22032
|
+
var getExamples = `
|
|
22033
|
+
Examples:
|
|
22034
|
+
$ qawolf agent get
|
|
22035
|
+
$ qawolf agent get --follow
|
|
22036
|
+
$ qawolf agent get <sessionId> --follow
|
|
22037
|
+
$ qawolf agent get --session <sessionId>`;
|
|
22038
|
+
function registerAgentGetCommand(agent, signals) {
|
|
22039
|
+
declareCommandKind(agent.command("get [session]"), "read").description("Read what the QA Wolf AI has said and whether it is still working").option("--follow", "Stay and report what QA Wolf says until the session settles, answering its questions as they come", false).option("--session <id>", sessionFlagDescription).option("--workspace-id <id>", "The workspace an answer given during --follow is sent to. Required when authenticating with an organization or user API key").option("--timeout <seconds>", timeoutFlagDescription, String(defaultAgentFollowTimeoutSeconds)).addHelpText("after", getExamples).action((session, opts, command) => withAuthContext(signals, (ctx) => handleAgentGet(ctx, {
|
|
22040
|
+
follow: opts.follow,
|
|
22041
|
+
session: opts.session,
|
|
22042
|
+
sessionArgument: session,
|
|
22043
|
+
timeout: opts.timeout,
|
|
22044
|
+
workspaceId: opts.workspaceId
|
|
22045
|
+
}, agentDeps(ctx)))(opts, command));
|
|
22046
|
+
}
|
|
22047
|
+
|
|
22048
|
+
// src/commands/publicApi/environmentOptions.ts
|
|
22049
|
+
var environmentIdEnvironmentVariable = "QAWOLF_ENVIRONMENT";
|
|
22050
|
+
var optionEnvironmentVariables = new Map([
|
|
22051
|
+
["environmentId", environmentIdEnvironmentVariable],
|
|
22052
|
+
["public.run.create.aiTaskId", "QAWOLF_AI_TASK_ID"],
|
|
22053
|
+
["public.run.create.chatSessionId", "QAWOLF_CHAT_SESSION_ID"]
|
|
22054
|
+
]);
|
|
22055
|
+
function optionEnvironmentVariable(spec, path) {
|
|
22056
|
+
const dotted = path.join(".");
|
|
22057
|
+
return optionEnvironmentVariables.get(`${spec.trpcPath}.${dotted}`) ?? optionEnvironmentVariables.get(dotted);
|
|
22058
|
+
}
|
|
22059
|
+
var exclusiveOptions = new Map([
|
|
22060
|
+
["public.run.create", { keep: "aiTaskId", drop: "chatSessionId" }]
|
|
22061
|
+
]);
|
|
22062
|
+
function withoutExclusiveConflict(spec, command, options) {
|
|
22063
|
+
const pair = exclusiveOptions.get(spec.trpcPath);
|
|
22064
|
+
if (!pair)
|
|
22065
|
+
return options;
|
|
22066
|
+
if (options[pair.keep] === undefined || options[pair.drop] === undefined) {
|
|
22067
|
+
return options;
|
|
22068
|
+
}
|
|
22069
|
+
const fromEnvironment = (key) => command.getOptionValueSource(key) === "env";
|
|
22070
|
+
if (!fromEnvironment(pair.keep) && !fromEnvironment(pair.drop)) {
|
|
22071
|
+
return options;
|
|
22072
|
+
}
|
|
22073
|
+
const dropped = fromEnvironment(pair.drop) ? pair.drop : pair.keep;
|
|
22074
|
+
return Object.fromEntries(Object.entries(options).filter(([key]) => key !== dropped));
|
|
22075
|
+
}
|
|
22076
|
+
|
|
22077
|
+
// src/domains/agent/send.ts
|
|
22078
|
+
function parseInput(options) {
|
|
22079
|
+
return publicContractsV1.agent.send.input.safeParse({
|
|
22080
|
+
message: options.message,
|
|
22081
|
+
...options.environmentId === undefined ? {} : { environmentId: options.environmentId },
|
|
22082
|
+
...options.filePaths === undefined ? {} : { filePaths: options.filePaths },
|
|
22083
|
+
...options.session === undefined ? {} : { sessionId: options.session },
|
|
22084
|
+
...options.workspaceId === undefined ? {} : { workspaceId: options.workspaceId }
|
|
22085
|
+
});
|
|
22086
|
+
}
|
|
22087
|
+
async function handleAgentSend(ctx, options, deps) {
|
|
22088
|
+
const timeout = parseFollowTimeout(options.timeout, defaultAgentFollowTimeoutSeconds);
|
|
22089
|
+
if (!timeout.ok) {
|
|
22090
|
+
return { error: timeout.error, exitCode: exitCodes.invalidArgs };
|
|
22091
|
+
}
|
|
22092
|
+
const input = parseInput(options);
|
|
22093
|
+
if (!input.success) {
|
|
22094
|
+
return {
|
|
22095
|
+
error: prettifyError(input.error),
|
|
22096
|
+
exitCode: exitCodes.invalidArgs
|
|
22097
|
+
};
|
|
22098
|
+
}
|
|
22099
|
+
let repliesAtAnswer;
|
|
22100
|
+
if (options.follow && options.session !== undefined) {
|
|
22101
|
+
const before = await ctx.platformClient.callPublicApi(publicContractsV1.agent.get, { sessionId: options.session });
|
|
22102
|
+
if (before.ok)
|
|
22103
|
+
repliesAtAnswer = before.value.replies.length;
|
|
22104
|
+
}
|
|
22105
|
+
const sent = await ctx.platformClient.callPublicApi(publicContractsV1.agent.send, input.data);
|
|
22106
|
+
if (!sent.ok)
|
|
22107
|
+
return { exitCode: exitCodes.network, ...failureFields(sent) };
|
|
22108
|
+
ctx.ui.output(sent.value, agentMessages.started(sent.value.sessionId, sent.value.url));
|
|
22109
|
+
await deps.store.rememberSession(sent.value.sessionId).catch(() => {
|
|
22110
|
+
ctx.ui.warn(agentMessages.sessionNotRemembered(sent.value.sessionId));
|
|
22111
|
+
});
|
|
22112
|
+
if (!options.follow)
|
|
22113
|
+
return;
|
|
22114
|
+
return followSession(ctx, {
|
|
22115
|
+
initial: undefined,
|
|
22116
|
+
repliesAtAnswer,
|
|
22117
|
+
sessionId: sent.value.sessionId,
|
|
22118
|
+
timeoutSeconds: timeout.seconds,
|
|
22119
|
+
workspaceId: options.workspaceId
|
|
22120
|
+
}, deps);
|
|
22121
|
+
}
|
|
22122
|
+
|
|
22123
|
+
// src/commands/agent/send.register.ts
|
|
22124
|
+
var sendExamples = `
|
|
22125
|
+
Examples:
|
|
22126
|
+
$ qawolf agent send "cover the checkout journey"
|
|
22127
|
+
$ qawolf agent send "cover the checkout journey" --follow
|
|
22128
|
+
$ qawolf agent send "use the staging login test@example.com" --session <id>
|
|
22129
|
+
$ qawolf agent send "cover signup" --environment-id staging --follow
|
|
22130
|
+
$ qawolf agent send "cover every journey in the sheet" --file-paths uploads/journeys.csv --follow`;
|
|
22131
|
+
function registerAgentSendCommand(agent, signals) {
|
|
22132
|
+
declareCommandKind(agent.command("send <message>"), "write").description("Ask the QA Wolf AI to do a piece of work, such as covering a journey or fixing a broken flow").option("--follow", "Stay and report what QA Wolf says until the session settles, answering its questions as they come", false).option("--session <id>", "Continue this session instead of opening a new one. Send an answer, or add context to work already running").addOption(new Option2("--environment-id <env>", "QA Wolf environment to work in, by id or alias. Ignored with --session, because a session keeps the environment it opened in").env(environmentIdEnvironmentVariable)).option("--workspace-id <id>", "The workspace to work in. Required when authenticating with an organization or user API key").option("--file-paths <path...>", "Team-storage paths of files this request is about, from qawolf file requestUpload. The AI reads them from storage rather than the message, so a plan of hundreds of journeys costs nothing to send. Up to 20").option("--timeout <seconds>", timeoutFlagDescription, String(defaultAgentFollowTimeoutSeconds)).addHelpText("after", sendExamples).action((message, opts, command) => withAuthContext(signals, (ctx) => handleAgentSend(ctx, {
|
|
22133
|
+
environmentId: opts.environmentId,
|
|
22134
|
+
filePaths: opts.filePaths,
|
|
22135
|
+
follow: opts.follow,
|
|
22136
|
+
message,
|
|
22137
|
+
session: opts.session,
|
|
22138
|
+
timeout: opts.timeout,
|
|
22139
|
+
workspaceId: opts.workspaceId
|
|
22140
|
+
}, agentDeps(ctx)))(opts, command));
|
|
22141
|
+
}
|
|
22142
|
+
|
|
22143
|
+
// src/commands/agent/index.ts
|
|
22144
|
+
function registerAgentCommand(program, signals) {
|
|
22145
|
+
const agent = program.command("agent").description("Ask the QA Wolf AI for work and follow what it does");
|
|
22146
|
+
registerAgentSendCommand(agent, signals);
|
|
22147
|
+
registerAgentGetCommand(agent, signals);
|
|
22148
|
+
}
|
|
22149
|
+
|
|
22150
|
+
// src/commands/auth/loginApiKey.ts
|
|
22151
|
+
async function loginWithApiKey(ctx) {
|
|
22152
|
+
const result = await ctx.ui.password(authMessages.promptApiKey, "Set QAWOLF_API_KEY to authenticate in non-interactive environments.");
|
|
22153
|
+
if (!result.ok) {
|
|
22154
|
+
ctx.ui.cancel(authMessages.cancelled);
|
|
22155
|
+
return;
|
|
22156
|
+
}
|
|
22157
|
+
const apiKey = result.value.trim();
|
|
22158
|
+
if (!apiKey) {
|
|
22159
|
+
ctx.ui.cancel(authMessages.cancelled);
|
|
22160
|
+
return;
|
|
22161
|
+
}
|
|
22162
|
+
await ctx.ui.withProgress([
|
|
22163
|
+
{
|
|
22164
|
+
message: authMessages.verifying,
|
|
22165
|
+
task: async () => {
|
|
22166
|
+
const v = await validateApiKey({
|
|
22167
|
+
platformClient: createPlatformClient(apiKey, {
|
|
22168
|
+
baseUrl: ctx.apiBaseUrl,
|
|
22169
|
+
fetch: globalThis.fetch
|
|
22170
|
+
})
|
|
22171
|
+
});
|
|
22172
|
+
if (!v.valid)
|
|
22173
|
+
throw Error(v.error);
|
|
22174
|
+
}
|
|
22175
|
+
},
|
|
22176
|
+
{
|
|
22177
|
+
message: authMessages.storing,
|
|
22178
|
+
task: async () => saveApiKey(ctx.configDir, apiKey, ctx.fs)
|
|
22179
|
+
}
|
|
22180
|
+
], ([, saveResult]) => {
|
|
22181
|
+
return saveResult.stored === "file" ? authMessages.storedFile : authMessages.storedKeychain;
|
|
22182
|
+
});
|
|
22183
|
+
ctx.ui.outro(authMessages.outroSuccess);
|
|
22184
|
+
}
|
|
22185
|
+
|
|
22186
|
+
// src/core/deviceAuth/pollState.ts
|
|
22187
|
+
var slowDownIncrementMs = 5000;
|
|
22188
|
+
var unreachableBackoffFactor = 2;
|
|
22189
|
+
function capToLifetime(delayMs, state, nowMs) {
|
|
22190
|
+
return Math.min(delayMs, Math.max(1, state.deadlineMs - nowMs));
|
|
22191
|
+
}
|
|
22192
|
+
function nextPollStep(state, response, nowMs) {
|
|
22193
|
+
if (response.kind === "tokens") {
|
|
22194
|
+
return { action: "done", tokens: response.tokens };
|
|
22195
|
+
}
|
|
22196
|
+
if (nowMs > state.deadlineMs) {
|
|
22197
|
+
return { action: "fail", reason: "timeout", detail: undefined };
|
|
22198
|
+
}
|
|
22199
|
+
switch (response.kind) {
|
|
22200
|
+
case "pending":
|
|
22201
|
+
return {
|
|
22202
|
+
action: "poll",
|
|
22203
|
+
delayMs: capToLifetime(state.intervalMs, state, nowMs),
|
|
22204
|
+
state
|
|
22205
|
+
};
|
|
22206
|
+
case "slow-down": {
|
|
22207
|
+
const slowed = {
|
|
22208
|
+
intervalMs: state.intervalMs + slowDownIncrementMs,
|
|
22209
|
+
deadlineMs: state.deadlineMs
|
|
22210
|
+
};
|
|
22211
|
+
return {
|
|
22212
|
+
action: "poll",
|
|
22213
|
+
delayMs: capToLifetime(slowed.intervalMs, slowed, nowMs),
|
|
22214
|
+
state: slowed
|
|
22215
|
+
};
|
|
22216
|
+
}
|
|
22217
|
+
case "denied":
|
|
22218
|
+
return { action: "fail", reason: "access-denied", detail: undefined };
|
|
22219
|
+
case "expired":
|
|
22220
|
+
return { action: "fail", reason: "expired", detail: undefined };
|
|
22221
|
+
case "unreachable": {
|
|
22222
|
+
const backedOff = {
|
|
22223
|
+
intervalMs: state.intervalMs * unreachableBackoffFactor,
|
|
22224
|
+
deadlineMs: state.deadlineMs
|
|
22225
|
+
};
|
|
22226
|
+
return {
|
|
22227
|
+
action: "poll",
|
|
22228
|
+
delayMs: capToLifetime(backedOff.intervalMs, backedOff, nowMs),
|
|
22229
|
+
state: backedOff
|
|
22230
|
+
};
|
|
22231
|
+
}
|
|
22232
|
+
case "error":
|
|
22233
|
+
return { action: "fail", reason: "network", detail: response.detail };
|
|
22234
|
+
}
|
|
22235
|
+
}
|
|
22236
|
+
|
|
22237
|
+
// src/domains/auth/deviceLogin.ts
|
|
22238
|
+
var cancelled = {
|
|
22239
|
+
ok: false,
|
|
22240
|
+
reason: "cancelled",
|
|
22241
|
+
detail: undefined
|
|
22242
|
+
};
|
|
22243
|
+
async function deviceLogin(deps) {
|
|
22244
|
+
if (deps.isCancelled())
|
|
22245
|
+
return cancelled;
|
|
22246
|
+
const authorization = await deps.requestAuthorization();
|
|
22247
|
+
if (!authorization.ok) {
|
|
22248
|
+
return { ok: false, reason: "unavailable", detail: authorization.error };
|
|
22249
|
+
}
|
|
22250
|
+
await deps.onPrompt(authorization.value);
|
|
22251
|
+
let state = {
|
|
22252
|
+
intervalMs: authorization.value.intervalSec * 1000,
|
|
22253
|
+
deadlineMs: deps.now() + authorization.value.expiresInSec * 1000
|
|
22254
|
+
};
|
|
21537
22255
|
for (;; ) {
|
|
21538
22256
|
if (deps.isCancelled())
|
|
21539
22257
|
return cancelled;
|
|
@@ -21841,10 +22559,9 @@ async function selectWorkspace(deps) {
|
|
|
21841
22559
|
}
|
|
21842
22560
|
|
|
21843
22561
|
// src/domains/auth/store/saveWorkspaceId.ts
|
|
21844
|
-
import { Entry as Entry6 } from "@napi-rs/keyring";
|
|
21845
22562
|
function makeSaveWorkspaceIdDeps(configDir, fs) {
|
|
21846
22563
|
return {
|
|
21847
|
-
loadTokens: () => loadTokens(configDir, {
|
|
22564
|
+
loadTokens: () => loadTokens(configDir, { loadEntryClass, fs }),
|
|
21848
22565
|
saveTokens: (session) => saveTokens(configDir, session, fs)
|
|
21849
22566
|
};
|
|
21850
22567
|
}
|
|
@@ -22050,11 +22767,11 @@ async function handleLogin(ctx, deps = {}) {
|
|
|
22050
22767
|
}
|
|
22051
22768
|
|
|
22052
22769
|
// src/domains/auth/store/deleteTokens.ts
|
|
22053
|
-
import { join as
|
|
22054
|
-
|
|
22055
|
-
function deleteFromKeychain2() {
|
|
22770
|
+
import { join as join15 } from "node:path";
|
|
22771
|
+
async function deleteFromKeychain2() {
|
|
22056
22772
|
try {
|
|
22057
|
-
|
|
22773
|
+
const Entry = await loadEntryClass();
|
|
22774
|
+
new Entry(service, tokensAccount).deletePassword();
|
|
22058
22775
|
return "deleted";
|
|
22059
22776
|
} catch {
|
|
22060
22777
|
return "unavailable";
|
|
@@ -22062,7 +22779,7 @@ function deleteFromKeychain2() {
|
|
|
22062
22779
|
}
|
|
22063
22780
|
async function deleteFromFile2(configDir, fs) {
|
|
22064
22781
|
try {
|
|
22065
|
-
await fs.unlink(
|
|
22782
|
+
await fs.unlink(join15(configDir, tokensFile));
|
|
22066
22783
|
return "deleted";
|
|
22067
22784
|
} catch (err) {
|
|
22068
22785
|
if (isNoEntError(err))
|
|
@@ -22072,7 +22789,7 @@ async function deleteFromFile2(configDir, fs) {
|
|
|
22072
22789
|
}
|
|
22073
22790
|
async function deleteTokens(configDir, fs) {
|
|
22074
22791
|
const [keychain, file] = await Promise.all([
|
|
22075
|
-
|
|
22792
|
+
deleteFromKeychain2(),
|
|
22076
22793
|
deleteFromFile2(configDir, fs)
|
|
22077
22794
|
]);
|
|
22078
22795
|
return { keychain, file };
|
|
@@ -22121,10 +22838,9 @@ async function handleLogout(ctx, deps = {}) {
|
|
|
22121
22838
|
}
|
|
22122
22839
|
|
|
22123
22840
|
// src/domains/auth/refreshStoredSession.ts
|
|
22124
|
-
import { Entry as Entry8 } from "@napi-rs/keyring";
|
|
22125
22841
|
function makeDefaultDeps2(fs) {
|
|
22126
22842
|
return {
|
|
22127
|
-
loadTokens: (configDir) => loadTokens(configDir, {
|
|
22843
|
+
loadTokens: (configDir) => loadTokens(configDir, { loadEntryClass, fs }),
|
|
22128
22844
|
resolveOauth: (configDir) => resolveOauthToken(configDir, makeOauthDeps(fs))
|
|
22129
22845
|
};
|
|
22130
22846
|
}
|
|
@@ -22203,92 +22919,947 @@ async function handleWhoami(ctx, deps = {}) {
|
|
|
22203
22919
|
} else {
|
|
22204
22920
|
ctx.ui.output({ authenticated: false, source: undefined }, authMessages.notAuthenticated);
|
|
22205
22921
|
}
|
|
22206
|
-
return { error: "not authenticated", exitCode: exitCodes.auth };
|
|
22922
|
+
return { error: "not authenticated", exitCode: exitCodes.auth };
|
|
22923
|
+
}
|
|
22924
|
+
const platformClient = (deps.createPlatform ?? createPlatformClient)(resolved.key, {
|
|
22925
|
+
baseUrl: ctx.apiBaseUrl,
|
|
22926
|
+
fetch: globalThis.fetch,
|
|
22927
|
+
logger: ctx.log("trpc")
|
|
22928
|
+
});
|
|
22929
|
+
const identity = await platformClient.getIdentity();
|
|
22930
|
+
if (!identity.ok) {
|
|
22931
|
+
if (ctx.ui.mode === "human") {
|
|
22932
|
+
ctx.ui.note(authMessages.whoami.source(resolved.source), authMessages.whoamiFailed);
|
|
22933
|
+
ctx.ui.warn(identity.error);
|
|
22934
|
+
} else {
|
|
22935
|
+
ctx.ui.output({
|
|
22936
|
+
authenticated: false,
|
|
22937
|
+
error: identity.error,
|
|
22938
|
+
source: resolved.source,
|
|
22939
|
+
valid: false
|
|
22940
|
+
}, authMessages.whoami.authFailed(resolved.source, identity.error));
|
|
22941
|
+
}
|
|
22942
|
+
return {
|
|
22943
|
+
error: "invalid key",
|
|
22944
|
+
...identity.exitCode === undefined ? {} : { exitCode: identity.exitCode }
|
|
22945
|
+
};
|
|
22946
|
+
}
|
|
22947
|
+
const { value } = identity;
|
|
22948
|
+
if ("user" in value) {
|
|
22949
|
+
const { organization, user } = value;
|
|
22950
|
+
const found = value.organizations.flatMap((candidate) => candidate.workspaces.map((workspace) => ({
|
|
22951
|
+
organization: candidate.name,
|
|
22952
|
+
workspace: workspace.name,
|
|
22953
|
+
id: workspace.id
|
|
22954
|
+
}))).find((entry) => entry.id === resolved.workspaceId);
|
|
22955
|
+
const activeWorkspace = resolved.workspaceId ? authMessages.whoami.activeWorkspace(resolved.workspaceId, found) : undefined;
|
|
22956
|
+
if (ctx.ui.mode === "human") {
|
|
22957
|
+
ctx.ui.note(authMessages.whoami.userNote({
|
|
22958
|
+
organization,
|
|
22959
|
+
source: resolved.source,
|
|
22960
|
+
user,
|
|
22961
|
+
activeWorkspace,
|
|
22962
|
+
organizations: value.organizations
|
|
22963
|
+
}), authMessages.whoamiAuthenticated);
|
|
22964
|
+
ctx.ui.outro(authMessages.outroReady);
|
|
22965
|
+
} else {
|
|
22966
|
+
ctx.ui.output({
|
|
22967
|
+
authenticated: true,
|
|
22968
|
+
organization,
|
|
22969
|
+
source: resolved.source,
|
|
22970
|
+
user,
|
|
22971
|
+
workspaceId: resolved.workspaceId,
|
|
22972
|
+
organizations: value.organizations
|
|
22973
|
+
}, authMessages.whoami.authenticatedAs(user.email, resolved.source));
|
|
22974
|
+
}
|
|
22975
|
+
return;
|
|
22976
|
+
}
|
|
22977
|
+
if ("organization" in value) {
|
|
22978
|
+
const { organization } = value;
|
|
22979
|
+
if (ctx.ui.mode === "human") {
|
|
22980
|
+
ctx.ui.note(authMessages.whoami.organizationNote({
|
|
22981
|
+
organization,
|
|
22982
|
+
source: resolved.source
|
|
22983
|
+
}), authMessages.whoamiAuthenticated);
|
|
22984
|
+
ctx.ui.outro(authMessages.outroReady);
|
|
22985
|
+
} else {
|
|
22986
|
+
ctx.ui.output({
|
|
22987
|
+
authenticated: true,
|
|
22988
|
+
organization,
|
|
22989
|
+
source: resolved.source
|
|
22990
|
+
}, authMessages.whoami.authenticatedAs(organization.name, resolved.source));
|
|
22991
|
+
}
|
|
22992
|
+
return;
|
|
22993
|
+
}
|
|
22994
|
+
reportTeamIdentity(ctx, value, resolved.source);
|
|
22995
|
+
}
|
|
22996
|
+
|
|
22997
|
+
// src/commands/auth/index.ts
|
|
22998
|
+
function registerAuthCommand(program, signals) {
|
|
22999
|
+
const auth = program.command("auth").description("Manage authentication with QA Wolf");
|
|
23000
|
+
declareCommandKind(auth.command("login"), "local").description("Authenticate with QA Wolf in a browser or with an API key").action(withContext(signals, handleLogin));
|
|
23001
|
+
declareCommandKind(auth.command("logout"), "local").description("Remove stored credentials").action(withContext(signals, handleLogout));
|
|
23002
|
+
declareCommandKind(auth.command("switch"), "local").description("Choose which workspace to work in").action(withContext(signals, handleSwitchWorkspace));
|
|
23003
|
+
declareCommandKind(auth.command("whoami"), "read").description("Show authentication status").action(withContext(signals, handleWhoami));
|
|
23004
|
+
}
|
|
23005
|
+
|
|
23006
|
+
// node_modules/@qawolf/flow-targets/dist/presets/android/androidPixel2Android14.js
|
|
23007
|
+
var androidPixel2Android14Target = {
|
|
23008
|
+
meta: {
|
|
23009
|
+
androidVersion: "34",
|
|
23010
|
+
deviceModel: "Pixel 2"
|
|
23011
|
+
},
|
|
23012
|
+
platform: "android",
|
|
23013
|
+
schemaVersion: 1
|
|
23014
|
+
};
|
|
23015
|
+
|
|
23016
|
+
// node_modules/@qawolf/flow-targets/dist/presets/android/androidPixel9.js
|
|
23017
|
+
var androidPixel9Target = {
|
|
23018
|
+
meta: {
|
|
23019
|
+
androidVersion: "34",
|
|
23020
|
+
deviceModel: "Pixel 9"
|
|
23021
|
+
},
|
|
23022
|
+
platform: "android",
|
|
23023
|
+
schemaVersion: 1
|
|
23024
|
+
};
|
|
23025
|
+
|
|
23026
|
+
// node_modules/@qawolf/flow-targets/dist/presets/android/androidPixel9Android14.js
|
|
23027
|
+
var androidPixel9Android14Target = {
|
|
23028
|
+
meta: {
|
|
23029
|
+
androidVersion: "34",
|
|
23030
|
+
deviceModel: "Pixel 9"
|
|
23031
|
+
},
|
|
23032
|
+
platform: "android",
|
|
23033
|
+
schemaVersion: 1
|
|
23034
|
+
};
|
|
23035
|
+
|
|
23036
|
+
// node_modules/@qawolf/flow-targets/dist/presets/android/androidPixel9Android15.js
|
|
23037
|
+
var androidPixel9Android15Target = {
|
|
23038
|
+
meta: {
|
|
23039
|
+
androidVersion: "35",
|
|
23040
|
+
deviceModel: "Pixel 9"
|
|
23041
|
+
},
|
|
23042
|
+
platform: "android",
|
|
23043
|
+
schemaVersion: 1
|
|
23044
|
+
};
|
|
23045
|
+
|
|
23046
|
+
// node_modules/@qawolf/flow-targets/dist/presets/android/androidPixel9Android16.js
|
|
23047
|
+
var androidPixel9Android16Target = {
|
|
23048
|
+
meta: {
|
|
23049
|
+
androidVersion: "36",
|
|
23050
|
+
deviceModel: "Pixel 9"
|
|
23051
|
+
},
|
|
23052
|
+
platform: "android",
|
|
23053
|
+
schemaVersion: 1
|
|
23054
|
+
};
|
|
23055
|
+
|
|
23056
|
+
// node_modules/@qawolf/flow-targets/dist/presets/android/androidPixel.js
|
|
23057
|
+
var androidPixelTarget = {
|
|
23058
|
+
meta: {
|
|
23059
|
+
androidVersion: "34",
|
|
23060
|
+
deviceModel: "Pixel 2"
|
|
23061
|
+
},
|
|
23062
|
+
platform: "android",
|
|
23063
|
+
schemaVersion: 1
|
|
23064
|
+
};
|
|
23065
|
+
|
|
23066
|
+
// node_modules/@qawolf/flow-targets/dist/presets/android/androidPixelTabletAndroid14.js
|
|
23067
|
+
var androidPixelTabletAndroid14Target = {
|
|
23068
|
+
meta: {
|
|
23069
|
+
androidVersion: "34",
|
|
23070
|
+
deviceModel: "Pixel Tablet"
|
|
23071
|
+
},
|
|
23072
|
+
platform: "android",
|
|
23073
|
+
schemaVersion: 1
|
|
23074
|
+
};
|
|
23075
|
+
|
|
23076
|
+
// node_modules/@qawolf/flow-targets/dist/presets/android/androidTablet.js
|
|
23077
|
+
var androidTabletTarget = {
|
|
23078
|
+
meta: {
|
|
23079
|
+
androidVersion: "34",
|
|
23080
|
+
deviceModel: "Pixel Tablet"
|
|
23081
|
+
},
|
|
23082
|
+
platform: "android",
|
|
23083
|
+
schemaVersion: 1
|
|
23084
|
+
};
|
|
23085
|
+
|
|
23086
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/allowlistedIphone.js
|
|
23087
|
+
var allowlistedIphoneTarget = {
|
|
23088
|
+
meta: {
|
|
23089
|
+
deviceModel: "iPhone 15",
|
|
23090
|
+
iosVersion: "26",
|
|
23091
|
+
targetDevices: "Allowlisted Device"
|
|
23092
|
+
},
|
|
23093
|
+
platform: "ios",
|
|
23094
|
+
schemaVersion: 1
|
|
23095
|
+
};
|
|
23096
|
+
|
|
23097
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/appleIdEnabledIpad.js
|
|
23098
|
+
var appleIdEnabledIpadTarget = {
|
|
23099
|
+
meta: {
|
|
23100
|
+
appleId: true,
|
|
23101
|
+
deviceModel: "iPad 11",
|
|
23102
|
+
iosVersion: "18"
|
|
23103
|
+
},
|
|
23104
|
+
platform: "ios",
|
|
23105
|
+
schemaVersion: 1
|
|
23106
|
+
};
|
|
23107
|
+
|
|
23108
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/appleIdEnabledIphone.js
|
|
23109
|
+
var appleIdEnabledIphoneTarget = {
|
|
23110
|
+
meta: {
|
|
23111
|
+
appleId: true,
|
|
23112
|
+
deviceModel: "iPhone 15",
|
|
23113
|
+
iosVersion: "26"
|
|
23114
|
+
},
|
|
23115
|
+
platform: "ios",
|
|
23116
|
+
schemaVersion: 1
|
|
23117
|
+
};
|
|
23118
|
+
|
|
23119
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/ipad11ios18.js
|
|
23120
|
+
var ipad11ios18Target = {
|
|
23121
|
+
meta: {
|
|
23122
|
+
deviceModel: "iPad 11",
|
|
23123
|
+
iosVersion: "18"
|
|
23124
|
+
},
|
|
23125
|
+
platform: "ios",
|
|
23126
|
+
schemaVersion: 1
|
|
23127
|
+
};
|
|
23128
|
+
|
|
23129
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/ipad11ios18AppleId.js
|
|
23130
|
+
var ipad11ios18AppleIdTarget = {
|
|
23131
|
+
meta: {
|
|
23132
|
+
appleId: true,
|
|
23133
|
+
deviceModel: "iPad 11",
|
|
23134
|
+
iosVersion: "18"
|
|
23135
|
+
},
|
|
23136
|
+
platform: "ios",
|
|
23137
|
+
schemaVersion: 1
|
|
23138
|
+
};
|
|
23139
|
+
|
|
23140
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/ipad11ios26.js
|
|
23141
|
+
var ipad11ios26Target = {
|
|
23142
|
+
meta: {
|
|
23143
|
+
deviceModel: "iPad 11",
|
|
23144
|
+
iosVersion: "26"
|
|
23145
|
+
},
|
|
23146
|
+
platform: "ios",
|
|
23147
|
+
schemaVersion: 1
|
|
23148
|
+
};
|
|
23149
|
+
|
|
23150
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/ipad.js
|
|
23151
|
+
var ipadTarget = {
|
|
23152
|
+
meta: {
|
|
23153
|
+
deviceModel: "iPad 11",
|
|
23154
|
+
iosVersion: "18"
|
|
23155
|
+
},
|
|
23156
|
+
platform: "ios",
|
|
23157
|
+
schemaVersion: 1
|
|
23158
|
+
};
|
|
23159
|
+
|
|
23160
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/iphone15ios17.js
|
|
23161
|
+
var iphone15ios17Target = {
|
|
23162
|
+
meta: {
|
|
23163
|
+
deviceModel: "iPhone 15",
|
|
23164
|
+
iosVersion: "17"
|
|
23165
|
+
},
|
|
23166
|
+
platform: "ios",
|
|
23167
|
+
schemaVersion: 1
|
|
23168
|
+
};
|
|
23169
|
+
|
|
23170
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/iphone15ios18.js
|
|
23171
|
+
var iphone15ios18Target = {
|
|
23172
|
+
meta: {
|
|
23173
|
+
deviceModel: "iPhone 15",
|
|
23174
|
+
iosVersion: "18"
|
|
23175
|
+
},
|
|
23176
|
+
platform: "ios",
|
|
23177
|
+
schemaVersion: 1
|
|
23178
|
+
};
|
|
23179
|
+
|
|
23180
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/iphone15ios26.js
|
|
23181
|
+
var iphone15ios26Target = {
|
|
23182
|
+
meta: {
|
|
23183
|
+
deviceModel: "iPhone 15",
|
|
23184
|
+
iosVersion: "26"
|
|
23185
|
+
},
|
|
23186
|
+
platform: "ios",
|
|
23187
|
+
schemaVersion: 1
|
|
23188
|
+
};
|
|
23189
|
+
|
|
23190
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/iphone15ios26Allowlisted.js
|
|
23191
|
+
var iphone15ios26AllowlistedTarget = {
|
|
23192
|
+
meta: {
|
|
23193
|
+
deviceModel: "iPhone 15",
|
|
23194
|
+
iosVersion: "26",
|
|
23195
|
+
targetDevices: "Allowlisted Device"
|
|
23196
|
+
},
|
|
23197
|
+
platform: "ios",
|
|
23198
|
+
schemaVersion: 1
|
|
23199
|
+
};
|
|
23200
|
+
|
|
23201
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/iphone15ios26AppleId.js
|
|
23202
|
+
var iphone15ios26AppleIdTarget = {
|
|
23203
|
+
meta: {
|
|
23204
|
+
appleId: true,
|
|
23205
|
+
deviceModel: "iPhone 15",
|
|
23206
|
+
iosVersion: "26"
|
|
23207
|
+
},
|
|
23208
|
+
platform: "ios",
|
|
23209
|
+
schemaVersion: 1
|
|
23210
|
+
};
|
|
23211
|
+
|
|
23212
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/iphone15ios26Private.js
|
|
23213
|
+
var iphone15ios26PrivateTarget = {
|
|
23214
|
+
meta: {
|
|
23215
|
+
deviceModel: "iPhone 15",
|
|
23216
|
+
iosVersion: "26",
|
|
23217
|
+
targetDevices: "Team Dedicated Device"
|
|
23218
|
+
},
|
|
23219
|
+
platform: "ios",
|
|
23220
|
+
schemaVersion: 1
|
|
23221
|
+
};
|
|
23222
|
+
|
|
23223
|
+
// node_modules/@qawolf/flow-targets/dist/presets/ios/iphone17ios26.js
|
|
23224
|
+
var iphone17ios26Target = {
|
|
23225
|
+
meta: {
|
|
23226
|
+
deviceModel: "iPhone 17",
|
|
23227
|
+
iosVersion: "26"
|
|
23228
|
+
},
|
|
23229
|
+
platform: "ios",
|
|
23230
|
+
schemaVersion: 1
|
|
23231
|
+
};
|
|
23232
|
+
|
|
23233
|
+
// node_modules/@qawolf/flow-targets/dist/presets/web/basic.js
|
|
23234
|
+
var webBasicTarget = {
|
|
23235
|
+
meta: "legacy",
|
|
23236
|
+
platform: "web",
|
|
23237
|
+
schemaVersion: 1
|
|
23238
|
+
};
|
|
23239
|
+
|
|
23240
|
+
// node_modules/@qawolf/flow-targets/dist/presets/web/chrome.js
|
|
23241
|
+
var webChromeTarget = {
|
|
23242
|
+
meta: {
|
|
23243
|
+
defaultBrowser: {
|
|
23244
|
+
name: "chrome"
|
|
23245
|
+
},
|
|
23246
|
+
gpuEnabled: false
|
|
23247
|
+
},
|
|
23248
|
+
platform: "web",
|
|
23249
|
+
schemaVersion: 1
|
|
23250
|
+
};
|
|
23251
|
+
|
|
23252
|
+
// node_modules/@qawolf/flow-targets/dist/presets/web/chromeWithGpu.js
|
|
23253
|
+
var webChromeWithGpuTarget = {
|
|
23254
|
+
meta: {
|
|
23255
|
+
defaultBrowser: {
|
|
23256
|
+
name: "chrome"
|
|
23257
|
+
},
|
|
23258
|
+
gpuEnabled: true
|
|
23259
|
+
},
|
|
23260
|
+
platform: "web",
|
|
23261
|
+
schemaVersion: 1
|
|
23262
|
+
};
|
|
23263
|
+
|
|
23264
|
+
// node_modules/@qawolf/flow-targets/dist/presets/web/electron.js
|
|
23265
|
+
var webElectronTarget = {
|
|
23266
|
+
meta: {
|
|
23267
|
+
gpuEnabled: false,
|
|
23268
|
+
kind: "electron"
|
|
23269
|
+
},
|
|
23270
|
+
platform: "web",
|
|
23271
|
+
schemaVersion: 1
|
|
23272
|
+
};
|
|
23273
|
+
|
|
23274
|
+
// node_modules/@qawolf/flow-targets/dist/presets/web/firefox.js
|
|
23275
|
+
var webFirefoxTarget = {
|
|
23276
|
+
meta: {
|
|
23277
|
+
defaultBrowser: {
|
|
23278
|
+
name: "firefox"
|
|
23279
|
+
},
|
|
23280
|
+
gpuEnabled: false
|
|
23281
|
+
},
|
|
23282
|
+
platform: "web",
|
|
23283
|
+
schemaVersion: 1
|
|
23284
|
+
};
|
|
23285
|
+
|
|
23286
|
+
// node_modules/@qawolf/flow-targets/dist/presets/web/firefoxWithGpu.js
|
|
23287
|
+
var webFirefoxWithGpuTarget = {
|
|
23288
|
+
meta: {
|
|
23289
|
+
defaultBrowser: {
|
|
23290
|
+
name: "firefox"
|
|
23291
|
+
},
|
|
23292
|
+
gpuEnabled: true
|
|
23293
|
+
},
|
|
23294
|
+
platform: "web",
|
|
23295
|
+
schemaVersion: 1
|
|
23296
|
+
};
|
|
23297
|
+
|
|
23298
|
+
// node_modules/@qawolf/flow-targets/dist/presets/web/safari.js
|
|
23299
|
+
var webSafariTarget = {
|
|
23300
|
+
meta: {
|
|
23301
|
+
defaultBrowser: {
|
|
23302
|
+
name: "safari"
|
|
23303
|
+
},
|
|
23304
|
+
gpuEnabled: false
|
|
23305
|
+
},
|
|
23306
|
+
platform: "web",
|
|
23307
|
+
schemaVersion: 1
|
|
23308
|
+
};
|
|
23309
|
+
|
|
23310
|
+
// node_modules/@qawolf/flow-targets/dist/presets/web/safariWithGpu.js
|
|
23311
|
+
var webSafariWithGpuTarget = {
|
|
23312
|
+
meta: {
|
|
23313
|
+
defaultBrowser: {
|
|
23314
|
+
name: "safari"
|
|
23315
|
+
},
|
|
23316
|
+
gpuEnabled: true
|
|
23317
|
+
},
|
|
23318
|
+
platform: "web",
|
|
23319
|
+
schemaVersion: 1
|
|
23320
|
+
};
|
|
23321
|
+
|
|
23322
|
+
// node_modules/@qawolf/flow-targets/dist/presets/index.js
|
|
23323
|
+
var androidPresetLiteralRaw = [
|
|
23324
|
+
"Android - Pixel",
|
|
23325
|
+
"Android - Pixel 2 (Android 14)",
|
|
23326
|
+
"Android - Pixel 9",
|
|
23327
|
+
"Android - Pixel 9 (Android 14)",
|
|
23328
|
+
"Android - Pixel 9 (Android 15)",
|
|
23329
|
+
"Android - Pixel 9 (Android 16)",
|
|
23330
|
+
"Android - Pixel Tablet (Android 14)",
|
|
23331
|
+
"Android - Tablet"
|
|
23332
|
+
];
|
|
23333
|
+
var androidPresetLiteralSchema = _enum(androidPresetLiteralRaw);
|
|
23334
|
+
var iosPresetLiteralRaw = [
|
|
23335
|
+
"iOS - Allowlisted iPhone",
|
|
23336
|
+
"iOS - Apple ID Enabled iPad",
|
|
23337
|
+
"iOS - Apple ID Enabled iPhone",
|
|
23338
|
+
"iOS - iPad",
|
|
23339
|
+
"iOS - iPad 11 (iOS 18)",
|
|
23340
|
+
"iOS - iPad 11 (iOS 18) (Apple ID)",
|
|
23341
|
+
"iOS - iPad 11 (iOS 26)",
|
|
23342
|
+
"iOS - iPhone 15 (iOS 17)",
|
|
23343
|
+
"iOS - iPhone 15 (iOS 18)",
|
|
23344
|
+
"iOS - iPhone 15 (iOS 26)",
|
|
23345
|
+
"iOS - iPhone 15 (iOS 26) (Apple ID)",
|
|
23346
|
+
"iOS - iPhone 15 (iOS 26) (allowlisted)",
|
|
23347
|
+
"iOS - iPhone 15 (iOS 26) (private)",
|
|
23348
|
+
"iOS - iPhone 17 (iOS 26)"
|
|
23349
|
+
];
|
|
23350
|
+
var iosPresetLiteralSchema = _enum(iosPresetLiteralRaw);
|
|
23351
|
+
var webPresetLiteralRaw = [
|
|
23352
|
+
"Basic",
|
|
23353
|
+
"Electron",
|
|
23354
|
+
"Web - Chrome",
|
|
23355
|
+
"Web - Chrome (GPU)",
|
|
23356
|
+
"Web - Firefox",
|
|
23357
|
+
"Web - Firefox (GPU)",
|
|
23358
|
+
"Web - Safari",
|
|
23359
|
+
"Web - Safari (GPU)"
|
|
23360
|
+
];
|
|
23361
|
+
var webPresetLiteralSchema = _enum(webPresetLiteralRaw);
|
|
23362
|
+
var presetLiteralsSchema = union([
|
|
23363
|
+
androidPresetLiteralSchema,
|
|
23364
|
+
iosPresetLiteralSchema,
|
|
23365
|
+
webPresetLiteralSchema
|
|
23366
|
+
]);
|
|
23367
|
+
var presetTargetMap = {
|
|
23368
|
+
"Android - Pixel": androidPixelTarget,
|
|
23369
|
+
"Android - Pixel 2 (Android 14)": androidPixel2Android14Target,
|
|
23370
|
+
"Android - Pixel 9": androidPixel9Target,
|
|
23371
|
+
"Android - Pixel 9 (Android 14)": androidPixel9Android14Target,
|
|
23372
|
+
"Android - Pixel 9 (Android 15)": androidPixel9Android15Target,
|
|
23373
|
+
"Android - Pixel 9 (Android 16)": androidPixel9Android16Target,
|
|
23374
|
+
"Android - Pixel Tablet (Android 14)": androidPixelTabletAndroid14Target,
|
|
23375
|
+
"Android - Tablet": androidTabletTarget,
|
|
23376
|
+
Basic: webBasicTarget,
|
|
23377
|
+
Electron: webElectronTarget,
|
|
23378
|
+
"iOS - Allowlisted iPhone": allowlistedIphoneTarget,
|
|
23379
|
+
"iOS - Apple ID Enabled iPad": appleIdEnabledIpadTarget,
|
|
23380
|
+
"iOS - Apple ID Enabled iPhone": appleIdEnabledIphoneTarget,
|
|
23381
|
+
"iOS - iPad": ipadTarget,
|
|
23382
|
+
"iOS - iPad 11 (iOS 18)": ipad11ios18Target,
|
|
23383
|
+
"iOS - iPad 11 (iOS 18) (Apple ID)": ipad11ios18AppleIdTarget,
|
|
23384
|
+
"iOS - iPad 11 (iOS 26)": ipad11ios26Target,
|
|
23385
|
+
"iOS - iPhone 15 (iOS 17)": iphone15ios17Target,
|
|
23386
|
+
"iOS - iPhone 15 (iOS 18)": iphone15ios18Target,
|
|
23387
|
+
"iOS - iPhone 15 (iOS 26)": iphone15ios26Target,
|
|
23388
|
+
"iOS - iPhone 15 (iOS 26) (allowlisted)": iphone15ios26AllowlistedTarget,
|
|
23389
|
+
"iOS - iPhone 15 (iOS 26) (Apple ID)": iphone15ios26AppleIdTarget,
|
|
23390
|
+
"iOS - iPhone 15 (iOS 26) (private)": iphone15ios26PrivateTarget,
|
|
23391
|
+
"iOS - iPhone 17 (iOS 26)": iphone17ios26Target,
|
|
23392
|
+
"Web - Chrome": webChromeTarget,
|
|
23393
|
+
"Web - Chrome (GPU)": webChromeWithGpuTarget,
|
|
23394
|
+
"Web - Firefox": webFirefoxTarget,
|
|
23395
|
+
"Web - Firefox (GPU)": webFirefoxWithGpuTarget,
|
|
23396
|
+
"Web - Safari": webSafariTarget,
|
|
23397
|
+
"Web - Safari (GPU)": webSafariWithGpuTarget
|
|
23398
|
+
};
|
|
23399
|
+
|
|
23400
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/shared/screenDimensions.js
|
|
23401
|
+
var screenDimensions = {
|
|
23402
|
+
"iPad 11": { screenHeight: 2360, screenWidth: 1640 },
|
|
23403
|
+
"iPhone 15": { screenHeight: 2556, screenWidth: 1179 },
|
|
23404
|
+
"iPhone 15 Plus": { screenHeight: 2796, screenWidth: 1290 },
|
|
23405
|
+
"iPhone 15 Pro Max": { screenHeight: 2868, screenWidth: 1320 },
|
|
23406
|
+
"iPhone 16 Plus": { screenHeight: 2796, screenWidth: 1290 },
|
|
23407
|
+
"iPhone 17": { screenHeight: 2622, screenWidth: 1206 },
|
|
23408
|
+
"Pixel 2": { screenHeight: 1920, screenWidth: 1080 },
|
|
23409
|
+
"Pixel 9": { screenHeight: 2424, screenWidth: 1080 },
|
|
23410
|
+
"Pixel Tablet": { screenHeight: 1600, screenWidth: 2560 },
|
|
23411
|
+
playwright_default: { screenHeight: 804, screenWidth: 1288 }
|
|
23412
|
+
};
|
|
23413
|
+
|
|
23414
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/shared/platforms.js
|
|
23415
|
+
var platformsSchema = _enum(["web", "android", "ios"]);
|
|
23416
|
+
|
|
23417
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/shared/runnerNames.js
|
|
23418
|
+
var runnerNamesSchema = _enum([
|
|
23419
|
+
"node20Basic",
|
|
23420
|
+
"classic",
|
|
23421
|
+
"node20GpuWithPlaywright",
|
|
23422
|
+
"node20WithPlaywright",
|
|
23423
|
+
"node20WithAndroid",
|
|
23424
|
+
"node20WithIos"
|
|
23425
|
+
]);
|
|
23426
|
+
|
|
23427
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/shared/baseSchemas.js
|
|
23428
|
+
var baseInputSchema = object({
|
|
23429
|
+
platform: platformsSchema,
|
|
23430
|
+
schemaVersion: int().positive()
|
|
23431
|
+
});
|
|
23432
|
+
var baseOutputSchema = baseInputSchema.extend({
|
|
23433
|
+
runnerName: runnerNamesSchema
|
|
23434
|
+
});
|
|
23435
|
+
|
|
23436
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/android/v1/supportedModelsSchema.js
|
|
23437
|
+
var supportedModelsInputSchema = _enum([
|
|
23438
|
+
"Pixel 2",
|
|
23439
|
+
"Pixel Tablet",
|
|
23440
|
+
"Pixel 9"
|
|
23441
|
+
]);
|
|
23442
|
+
var supportedModelsOutputSchema = _enum([
|
|
23443
|
+
"pixel_2",
|
|
23444
|
+
"pixel_tablet",
|
|
23445
|
+
"pixel_9"
|
|
23446
|
+
]);
|
|
23447
|
+
var supportedModelsSchema = codec(supportedModelsInputSchema, supportedModelsOutputSchema, {
|
|
23448
|
+
decode(deviceModel) {
|
|
23449
|
+
switch (deviceModel) {
|
|
23450
|
+
case "Pixel 2":
|
|
23451
|
+
return "pixel_2";
|
|
23452
|
+
case "Pixel 9":
|
|
23453
|
+
return "pixel_9";
|
|
23454
|
+
case "Pixel Tablet":
|
|
23455
|
+
return "pixel_tablet";
|
|
23456
|
+
default:
|
|
23457
|
+
throw Error(`Unsupported device model: ${deviceModel}`);
|
|
23458
|
+
}
|
|
23459
|
+
},
|
|
23460
|
+
encode(deviceModel) {
|
|
23461
|
+
switch (deviceModel) {
|
|
23462
|
+
case "pixel_2":
|
|
23463
|
+
return "Pixel 2";
|
|
23464
|
+
case "pixel_9":
|
|
23465
|
+
return "Pixel 9";
|
|
23466
|
+
case "pixel_tablet":
|
|
23467
|
+
return "Pixel Tablet";
|
|
23468
|
+
default:
|
|
23469
|
+
throw Error(`Unsupported device model: ${deviceModel}`);
|
|
23470
|
+
}
|
|
23471
|
+
}
|
|
23472
|
+
});
|
|
23473
|
+
|
|
23474
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/android/v1/input.js
|
|
23475
|
+
var supportedVersionsSchema = _enum(["34", "35", "36"]);
|
|
23476
|
+
var androidMetaInputSchema = discriminatedUnion("deviceModel", [
|
|
23477
|
+
object({
|
|
23478
|
+
androidVersion: supportedVersionsSchema.extract(["34"]),
|
|
23479
|
+
deviceModel: supportedModelsInputSchema.extract(["Pixel 2"])
|
|
23480
|
+
}),
|
|
23481
|
+
object({
|
|
23482
|
+
androidVersion: supportedVersionsSchema.extract(["34"]),
|
|
23483
|
+
deviceModel: supportedModelsInputSchema.extract(["Pixel Tablet"])
|
|
23484
|
+
}),
|
|
23485
|
+
object({
|
|
23486
|
+
androidVersion: supportedVersionsSchema.extract(["34", "35", "36"]),
|
|
23487
|
+
deviceModel: supportedModelsInputSchema.extract(["Pixel 9"])
|
|
23488
|
+
})
|
|
23489
|
+
]);
|
|
23490
|
+
var androidTargetInputSchema = baseInputSchema.extend({
|
|
23491
|
+
meta: androidMetaInputSchema,
|
|
23492
|
+
platform: platformsSchema.extract(["android"]),
|
|
23493
|
+
schemaVersion: literal(1)
|
|
23494
|
+
});
|
|
23495
|
+
|
|
23496
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/android/v1/output.js
|
|
23497
|
+
var androidTargetOutputSchema = baseOutputSchema.extend({
|
|
23498
|
+
...androidTargetInputSchema.shape,
|
|
23499
|
+
meta: object({
|
|
23500
|
+
androidVersion: supportedVersionsSchema,
|
|
23501
|
+
deviceModel: supportedModelsOutputSchema,
|
|
23502
|
+
screenHeight: number2(),
|
|
23503
|
+
screenWidth: number2()
|
|
23504
|
+
}),
|
|
23505
|
+
runnerName: runnerNamesSchema.extract(["node20WithAndroid"])
|
|
23506
|
+
});
|
|
23507
|
+
|
|
23508
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/android/v1/index.js
|
|
23509
|
+
var androidExecutionTargetSchema = codec(androidTargetInputSchema, androidTargetOutputSchema, {
|
|
23510
|
+
decode(value) {
|
|
23511
|
+
return {
|
|
23512
|
+
...value,
|
|
23513
|
+
meta: {
|
|
23514
|
+
...value.meta,
|
|
23515
|
+
deviceModel: supportedModelsSchema.decode(value.meta.deviceModel),
|
|
23516
|
+
...screenDimensions[value.meta.deviceModel]
|
|
23517
|
+
},
|
|
23518
|
+
runnerName: "node20WithAndroid"
|
|
23519
|
+
};
|
|
23520
|
+
},
|
|
23521
|
+
encode(value) {
|
|
23522
|
+
return androidTargetInputSchema.parse({
|
|
23523
|
+
...value,
|
|
23524
|
+
meta: {
|
|
23525
|
+
...value.meta,
|
|
23526
|
+
deviceModel: supportedModelsSchema.encode(value.meta.deviceModel)
|
|
23527
|
+
}
|
|
23528
|
+
});
|
|
23529
|
+
}
|
|
23530
|
+
});
|
|
23531
|
+
|
|
23532
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/android/index.js
|
|
23533
|
+
var androidExecutionTargetInputSchema = discriminatedUnion("schemaVersion", [androidTargetInputSchema]);
|
|
23534
|
+
var androidExecutionTargetOutputSchema = discriminatedUnion("schemaVersion", [androidTargetOutputSchema]);
|
|
23535
|
+
var androidExecutionTargetSchema2 = discriminatedUnion("schemaVersion", [androidExecutionTargetSchema]);
|
|
23536
|
+
|
|
23537
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/ios/v1/supportedModelsSchema.js
|
|
23538
|
+
var supportedModelsInputSchema2 = _enum([
|
|
23539
|
+
"iPhone 15",
|
|
23540
|
+
"iPhone 15 Plus",
|
|
23541
|
+
"iPhone 15 Pro Max",
|
|
23542
|
+
"iPhone 16 Plus",
|
|
23543
|
+
"iPhone 17",
|
|
23544
|
+
"iPad 11"
|
|
23545
|
+
]);
|
|
23546
|
+
var supportedModelsOutputSchema2 = _enum([
|
|
23547
|
+
"iphone15_4",
|
|
23548
|
+
"iphone15_5",
|
|
23549
|
+
"iphone16_2",
|
|
23550
|
+
"iphone17_4",
|
|
23551
|
+
"iphone18_3",
|
|
23552
|
+
"ipad15_7"
|
|
23553
|
+
]);
|
|
23554
|
+
var supportedModelsSchema2 = codec(supportedModelsInputSchema2, supportedModelsOutputSchema2, {
|
|
23555
|
+
decode(deviceModel) {
|
|
23556
|
+
switch (deviceModel) {
|
|
23557
|
+
case "iPad 11":
|
|
23558
|
+
return "ipad15_7";
|
|
23559
|
+
case "iPhone 15":
|
|
23560
|
+
return "iphone15_4";
|
|
23561
|
+
case "iPhone 15 Plus":
|
|
23562
|
+
return "iphone15_5";
|
|
23563
|
+
case "iPhone 15 Pro Max":
|
|
23564
|
+
return "iphone16_2";
|
|
23565
|
+
case "iPhone 16 Plus":
|
|
23566
|
+
return "iphone17_4";
|
|
23567
|
+
case "iPhone 17":
|
|
23568
|
+
return "iphone18_3";
|
|
23569
|
+
default:
|
|
23570
|
+
throw Error(`Unsupported device model: ${deviceModel}`);
|
|
23571
|
+
}
|
|
23572
|
+
},
|
|
23573
|
+
encode(value) {
|
|
23574
|
+
switch (value) {
|
|
23575
|
+
case "ipad15_7":
|
|
23576
|
+
return "iPad 11";
|
|
23577
|
+
case "iphone15_4":
|
|
23578
|
+
return "iPhone 15";
|
|
23579
|
+
case "iphone15_5":
|
|
23580
|
+
return "iPhone 15 Plus";
|
|
23581
|
+
case "iphone16_2":
|
|
23582
|
+
return "iPhone 15 Pro Max";
|
|
23583
|
+
case "iphone17_4":
|
|
23584
|
+
return "iPhone 16 Plus";
|
|
23585
|
+
case "iphone18_3":
|
|
23586
|
+
return "iPhone 17";
|
|
23587
|
+
default:
|
|
23588
|
+
throw Error(`Unsupported device model: ${value}`);
|
|
23589
|
+
}
|
|
22207
23590
|
}
|
|
22208
|
-
|
|
22209
|
-
|
|
22210
|
-
|
|
22211
|
-
|
|
22212
|
-
|
|
22213
|
-
|
|
22214
|
-
|
|
22215
|
-
|
|
22216
|
-
|
|
22217
|
-
|
|
22218
|
-
|
|
22219
|
-
|
|
22220
|
-
|
|
22221
|
-
|
|
22222
|
-
|
|
22223
|
-
|
|
22224
|
-
|
|
23591
|
+
});
|
|
23592
|
+
|
|
23593
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/ios/v1/supportedTargetDevicesSchema.js
|
|
23594
|
+
var supportedTargetDevicesInputSchema = _enum([
|
|
23595
|
+
"Any Device",
|
|
23596
|
+
"Allowlisted Device",
|
|
23597
|
+
"Team Dedicated Device"
|
|
23598
|
+
]);
|
|
23599
|
+
var supportedTargetDevicesOutputSchema = _enum([
|
|
23600
|
+
"anyDevice",
|
|
23601
|
+
"allowlistedDevice",
|
|
23602
|
+
"teamDedicatedDevice"
|
|
23603
|
+
]);
|
|
23604
|
+
var supportedTargetDevicesSchema = codec(supportedTargetDevicesInputSchema, supportedTargetDevicesOutputSchema, {
|
|
23605
|
+
decode(targetDevices) {
|
|
23606
|
+
switch (targetDevices) {
|
|
23607
|
+
case "Allowlisted Device":
|
|
23608
|
+
return "allowlistedDevice";
|
|
23609
|
+
case "Any Device":
|
|
23610
|
+
return "anyDevice";
|
|
23611
|
+
case "Team Dedicated Device":
|
|
23612
|
+
return "teamDedicatedDevice";
|
|
23613
|
+
default:
|
|
23614
|
+
throw Error(`Unsupported target devices: ${targetDevices}`);
|
|
23615
|
+
}
|
|
23616
|
+
},
|
|
23617
|
+
encode(targetDevices) {
|
|
23618
|
+
switch (targetDevices) {
|
|
23619
|
+
case "allowlistedDevice":
|
|
23620
|
+
return "Allowlisted Device";
|
|
23621
|
+
case "anyDevice":
|
|
23622
|
+
return "Any Device";
|
|
23623
|
+
case "teamDedicatedDevice":
|
|
23624
|
+
return "Team Dedicated Device";
|
|
23625
|
+
default:
|
|
23626
|
+
throw Error(`Unsupported target devices: ${targetDevices}`);
|
|
22225
23627
|
}
|
|
23628
|
+
}
|
|
23629
|
+
});
|
|
23630
|
+
|
|
23631
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/ios/v1/input.js
|
|
23632
|
+
var supportedVersionsInputSchema = _enum(["17", "18", "26"]);
|
|
23633
|
+
var baseMetaInputSchema = object({
|
|
23634
|
+
appleId: union([email2(), boolean2()]).optional(),
|
|
23635
|
+
deviceUdid: string2().optional(),
|
|
23636
|
+
targetDevices: supportedTargetDevicesInputSchema.default("Any Device")
|
|
23637
|
+
});
|
|
23638
|
+
var iosMetaInputSchema = discriminatedUnion("deviceModel", [
|
|
23639
|
+
baseMetaInputSchema.extend({
|
|
23640
|
+
deviceModel: supportedModelsInputSchema2.extract(["iPhone 15"]),
|
|
23641
|
+
iosVersion: supportedVersionsInputSchema.extract(["17", "18", "26"])
|
|
23642
|
+
}),
|
|
23643
|
+
baseMetaInputSchema.extend({
|
|
23644
|
+
deviceModel: supportedModelsInputSchema2.extract(["iPhone 15 Plus"]),
|
|
23645
|
+
iosVersion: supportedVersionsInputSchema.extract(["17"])
|
|
23646
|
+
}),
|
|
23647
|
+
baseMetaInputSchema.extend({
|
|
23648
|
+
deviceModel: supportedModelsInputSchema2.extract(["iPhone 15 Pro Max"]),
|
|
23649
|
+
iosVersion: supportedVersionsInputSchema.extract(["17"])
|
|
23650
|
+
}),
|
|
23651
|
+
baseMetaInputSchema.extend({
|
|
23652
|
+
deviceModel: supportedModelsInputSchema2.extract(["iPhone 16 Plus"]),
|
|
23653
|
+
iosVersion: supportedVersionsInputSchema.extract(["26"])
|
|
23654
|
+
}),
|
|
23655
|
+
baseMetaInputSchema.extend({
|
|
23656
|
+
deviceModel: supportedModelsInputSchema2.extract(["iPhone 17"]),
|
|
23657
|
+
iosVersion: supportedVersionsInputSchema.extract(["26"])
|
|
23658
|
+
}),
|
|
23659
|
+
baseMetaInputSchema.extend({
|
|
23660
|
+
deviceModel: supportedModelsInputSchema2.extract(["iPad 11"]),
|
|
23661
|
+
iosVersion: supportedVersionsInputSchema.extract(["18", "26"])
|
|
23662
|
+
})
|
|
23663
|
+
]);
|
|
23664
|
+
var iosTargetInputSchema = baseInputSchema.extend({
|
|
23665
|
+
meta: iosMetaInputSchema,
|
|
23666
|
+
platform: platformsSchema.extract(["ios"]),
|
|
23667
|
+
schemaVersion: literal(1)
|
|
23668
|
+
});
|
|
23669
|
+
|
|
23670
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/ios/v1/output.js
|
|
23671
|
+
var iosTargetOutputSchema = baseOutputSchema.extend({
|
|
23672
|
+
...iosTargetInputSchema.shape,
|
|
23673
|
+
meta: object({
|
|
23674
|
+
appleId: union([email2(), boolean2()]).optional(),
|
|
23675
|
+
deviceModel: supportedModelsOutputSchema2,
|
|
23676
|
+
deviceUdid: string2().optional(),
|
|
23677
|
+
iosVersion: supportedVersionsInputSchema,
|
|
23678
|
+
screenHeight: number2(),
|
|
23679
|
+
screenWidth: number2(),
|
|
23680
|
+
targetDevices: supportedTargetDevicesOutputSchema
|
|
23681
|
+
}),
|
|
23682
|
+
runnerName: runnerNamesSchema.extract(["node20WithIos"])
|
|
23683
|
+
});
|
|
23684
|
+
|
|
23685
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/ios/v1/index.js
|
|
23686
|
+
var iosExecutionTargetSchema = codec(iosTargetInputSchema, iosTargetOutputSchema, {
|
|
23687
|
+
decode(value) {
|
|
22226
23688
|
return {
|
|
22227
|
-
|
|
22228
|
-
|
|
23689
|
+
...value,
|
|
23690
|
+
meta: {
|
|
23691
|
+
...value.meta,
|
|
23692
|
+
appleId: value.meta.appleId || undefined,
|
|
23693
|
+
deviceModel: supportedModelsSchema2.decode(value.meta.deviceModel),
|
|
23694
|
+
...screenDimensions[value.meta.deviceModel],
|
|
23695
|
+
targetDevices: supportedTargetDevicesSchema.decode(value.meta.targetDevices)
|
|
23696
|
+
},
|
|
23697
|
+
runnerName: "node20WithIos"
|
|
22229
23698
|
};
|
|
23699
|
+
},
|
|
23700
|
+
encode(value) {
|
|
23701
|
+
return iosTargetInputSchema.parse({
|
|
23702
|
+
...value,
|
|
23703
|
+
meta: {
|
|
23704
|
+
...value.meta,
|
|
23705
|
+
deviceModel: supportedModelsSchema2.encode(value.meta.deviceModel),
|
|
23706
|
+
targetDevices: supportedTargetDevicesSchema.encode(value.meta.targetDevices)
|
|
23707
|
+
}
|
|
23708
|
+
});
|
|
22230
23709
|
}
|
|
22231
|
-
|
|
22232
|
-
|
|
22233
|
-
|
|
22234
|
-
|
|
22235
|
-
|
|
22236
|
-
|
|
22237
|
-
|
|
22238
|
-
|
|
22239
|
-
|
|
22240
|
-
|
|
22241
|
-
|
|
22242
|
-
|
|
22243
|
-
|
|
22244
|
-
|
|
22245
|
-
|
|
22246
|
-
|
|
22247
|
-
|
|
22248
|
-
|
|
22249
|
-
|
|
22250
|
-
|
|
22251
|
-
|
|
22252
|
-
|
|
22253
|
-
|
|
22254
|
-
|
|
22255
|
-
|
|
22256
|
-
|
|
22257
|
-
|
|
22258
|
-
|
|
22259
|
-
|
|
22260
|
-
|
|
22261
|
-
|
|
22262
|
-
|
|
22263
|
-
|
|
22264
|
-
|
|
22265
|
-
|
|
22266
|
-
|
|
22267
|
-
|
|
22268
|
-
|
|
23710
|
+
});
|
|
23711
|
+
|
|
23712
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/ios/index.js
|
|
23713
|
+
var iosExecutionTargetInputSchema = discriminatedUnion("schemaVersion", [iosTargetInputSchema]);
|
|
23714
|
+
var iosExecutionTargetOutputSchema = discriminatedUnion("schemaVersion", [iosTargetOutputSchema]);
|
|
23715
|
+
var iosExecutionTargetSchema2 = discriminatedUnion("schemaVersion", [
|
|
23716
|
+
iosExecutionTargetSchema
|
|
23717
|
+
]);
|
|
23718
|
+
|
|
23719
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/web/v1/input.js
|
|
23720
|
+
var supportedBrowserNamesSchema = _enum(["chrome", "firefox", "safari"]);
|
|
23721
|
+
var defaultScreenDimensions = {
|
|
23722
|
+
height: 804,
|
|
23723
|
+
width: 1288
|
|
23724
|
+
};
|
|
23725
|
+
var webBrowserInputSchema = object({
|
|
23726
|
+
name: supportedBrowserNamesSchema,
|
|
23727
|
+
screenHeight: int().positive().default(defaultScreenDimensions.height),
|
|
23728
|
+
screenWidth: int().positive().default(defaultScreenDimensions.width)
|
|
23729
|
+
});
|
|
23730
|
+
var defaultBrowserInfoSchema = object({
|
|
23731
|
+
browser: optional(never()),
|
|
23732
|
+
defaultBrowser: webBrowserInputSchema,
|
|
23733
|
+
gpuEnabled: boolean2(),
|
|
23734
|
+
kind: literal("browser").default("browser")
|
|
23735
|
+
});
|
|
23736
|
+
var legacyBrowserInfoSchema = object({
|
|
23737
|
+
browser: webBrowserInputSchema,
|
|
23738
|
+
defaultBrowser: optional(never()),
|
|
23739
|
+
gpuEnabled: boolean2(),
|
|
23740
|
+
kind: literal("browser").default("browser")
|
|
23741
|
+
});
|
|
23742
|
+
var electronInfoSchema = object({
|
|
23743
|
+
browser: optional(never()),
|
|
23744
|
+
defaultBrowser: optional(never()),
|
|
23745
|
+
gpuEnabled: literal(false).default(false),
|
|
23746
|
+
kind: literal("electron")
|
|
23747
|
+
});
|
|
23748
|
+
var browserInfoSchema = union([
|
|
23749
|
+
defaultBrowserInfoSchema,
|
|
23750
|
+
legacyBrowserInfoSchema
|
|
23751
|
+
]);
|
|
23752
|
+
var webMetaSchema = union([browserInfoSchema, electronInfoSchema]);
|
|
23753
|
+
var webTargetInputSchema = baseInputSchema.extend({
|
|
23754
|
+
meta: union([webMetaSchema, literal("legacy")]),
|
|
23755
|
+
platform: platformsSchema.extract(["web"]),
|
|
23756
|
+
schemaVersion: literal(1)
|
|
23757
|
+
});
|
|
23758
|
+
function getWebBrowserInfo(meta) {
|
|
23759
|
+
if ("defaultBrowser" in meta && meta.defaultBrowser)
|
|
23760
|
+
return webBrowserInputSchema.parse(meta.defaultBrowser);
|
|
23761
|
+
if ("browser" in meta && meta.browser)
|
|
23762
|
+
return webBrowserInputSchema.parse(meta.browser);
|
|
23763
|
+
throw Error("Expected either defaultBrowser or browser in web meta");
|
|
23764
|
+
}
|
|
23765
|
+
|
|
23766
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/web/v1/webRunnerNames.js
|
|
23767
|
+
var webRunnerNamesSchema = runnerNamesSchema.extract([
|
|
23768
|
+
"node20Basic",
|
|
23769
|
+
"node20WithPlaywright",
|
|
23770
|
+
"node20GpuWithPlaywright"
|
|
23771
|
+
]);
|
|
23772
|
+
|
|
23773
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/web/v1/output.js
|
|
23774
|
+
var webOutputMetaSchema = union([
|
|
23775
|
+
object({
|
|
23776
|
+
defaultBrowser: webBrowserInputSchema,
|
|
23777
|
+
gpuEnabled: boolean2(),
|
|
23778
|
+
kind: literal("browser").default("browser")
|
|
23779
|
+
}),
|
|
23780
|
+
object({
|
|
23781
|
+
browser: webBrowserInputSchema,
|
|
23782
|
+
gpuEnabled: boolean2(),
|
|
23783
|
+
kind: literal("browser").default("browser")
|
|
23784
|
+
}),
|
|
23785
|
+
object({
|
|
23786
|
+
gpuEnabled: literal(false),
|
|
23787
|
+
kind: literal("electron")
|
|
23788
|
+
}),
|
|
23789
|
+
literal("legacy")
|
|
23790
|
+
]);
|
|
23791
|
+
var webTargetOutputSchema = baseOutputSchema.extend({
|
|
23792
|
+
meta: webOutputMetaSchema,
|
|
23793
|
+
platform: literal("web"),
|
|
23794
|
+
runnerName: webRunnerNamesSchema,
|
|
23795
|
+
schemaVersion: literal(1)
|
|
23796
|
+
});
|
|
23797
|
+
|
|
23798
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/web/v1/index.js
|
|
23799
|
+
var webExecutionTargetSchema = codec(webTargetInputSchema, webTargetOutputSchema, {
|
|
23800
|
+
decode(value) {
|
|
23801
|
+
const runnerName = value.meta === "legacy" ? "node20Basic" : value.meta.gpuEnabled ? "node20GpuWithPlaywright" : "node20WithPlaywright";
|
|
23802
|
+
let meta;
|
|
23803
|
+
if (value.meta === "legacy")
|
|
23804
|
+
meta = value.meta;
|
|
23805
|
+
else if (value.meta.kind === "electron") {
|
|
23806
|
+
meta = {
|
|
23807
|
+
gpuEnabled: false,
|
|
23808
|
+
kind: "electron"
|
|
23809
|
+
};
|
|
22269
23810
|
} else {
|
|
22270
|
-
|
|
22271
|
-
|
|
22272
|
-
|
|
22273
|
-
|
|
22274
|
-
|
|
23811
|
+
const browserInfo = getWebBrowserInfo(value.meta);
|
|
23812
|
+
meta = {
|
|
23813
|
+
defaultBrowser: browserInfo,
|
|
23814
|
+
gpuEnabled: value.meta.gpuEnabled,
|
|
23815
|
+
kind: "browser"
|
|
23816
|
+
};
|
|
22275
23817
|
}
|
|
22276
|
-
return
|
|
23818
|
+
return {
|
|
23819
|
+
...value,
|
|
23820
|
+
meta,
|
|
23821
|
+
runnerName
|
|
23822
|
+
};
|
|
23823
|
+
},
|
|
23824
|
+
encode(value) {
|
|
23825
|
+
return webTargetInputSchema.parse(value);
|
|
22277
23826
|
}
|
|
22278
|
-
|
|
22279
|
-
}
|
|
23827
|
+
});
|
|
22280
23828
|
|
|
22281
|
-
//
|
|
22282
|
-
|
|
22283
|
-
|
|
22284
|
-
|
|
22285
|
-
|
|
22286
|
-
|
|
22287
|
-
|
|
22288
|
-
|
|
23829
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/web/index.js
|
|
23830
|
+
var webExecutionTargetInputSchema = discriminatedUnion("schemaVersion", [webTargetInputSchema]);
|
|
23831
|
+
var webExecutionTargetOutputSchema = discriminatedUnion("schemaVersion", [webTargetOutputSchema]);
|
|
23832
|
+
var webExecutionTargetSchema2 = discriminatedUnion("schemaVersion", [
|
|
23833
|
+
webExecutionTargetSchema
|
|
23834
|
+
]);
|
|
23835
|
+
|
|
23836
|
+
// node_modules/@qawolf/flow-targets/dist/schemas/index.js
|
|
23837
|
+
var executionTargetInputSchema = discriminatedUnion("platform", [
|
|
23838
|
+
androidExecutionTargetInputSchema,
|
|
23839
|
+
iosExecutionTargetInputSchema,
|
|
23840
|
+
webExecutionTargetInputSchema
|
|
23841
|
+
]);
|
|
23842
|
+
var executionTargetOutputSchema = discriminatedUnion("platform", [
|
|
23843
|
+
androidExecutionTargetOutputSchema,
|
|
23844
|
+
iosExecutionTargetOutputSchema,
|
|
23845
|
+
webExecutionTargetOutputSchema
|
|
23846
|
+
]);
|
|
23847
|
+
var executionTargetSchema = discriminatedUnion("platform", [
|
|
23848
|
+
androidExecutionTargetSchema2,
|
|
23849
|
+
iosExecutionTargetSchema2,
|
|
23850
|
+
webExecutionTargetSchema2
|
|
23851
|
+
]);
|
|
23852
|
+
|
|
23853
|
+
// node_modules/@qawolf/flow-targets/dist/parseExecutionTarget.js
|
|
23854
|
+
var isPresetLiteral = (input) => presetLiteralsSchema.safeParse(input).success;
|
|
23855
|
+
var parseExecutionTarget = (input) => executionTargetSchema.decode(isPresetLiteral(input) ? presetTargetMap[input] : input);
|
|
23856
|
+
// node_modules/@qawolf/flow-targets/dist/index.js
|
|
23857
|
+
var presetLiteralOrAdHocTargetSchema = union([
|
|
23858
|
+
presetLiteralsSchema,
|
|
23859
|
+
executionTargetInputSchema
|
|
23860
|
+
]);
|
|
22289
23861
|
|
|
22290
23862
|
// src/core/androidTargets.ts
|
|
22291
|
-
import { parseExecutionTarget } from "@qawolf/flow-targets";
|
|
22292
23863
|
function makeAvdName(deviceModel, androidVersion) {
|
|
22293
23864
|
return `qawolf_${deviceModel.toLowerCase().replace(/ /g, "_")}_api${androidVersion}`;
|
|
22294
23865
|
}
|
|
@@ -22333,11 +23904,11 @@ async function* batchMap(items, fn, size) {
|
|
|
22333
23904
|
}
|
|
22334
23905
|
|
|
22335
23906
|
// src/core/nodeModulesBins.ts
|
|
22336
|
-
import { join as
|
|
23907
|
+
import { join as join16 } from "node:path";
|
|
22337
23908
|
function nodeModulesBinCandidates(envDir, name, platform) {
|
|
22338
|
-
const binDir =
|
|
23909
|
+
const binDir = join16(envDir, "node_modules", ".bin");
|
|
22339
23910
|
const names = platform === "win32" ? [`${name}.cmd`, `${name}.exe`] : [name];
|
|
22340
|
-
return names.map((shim) =>
|
|
23911
|
+
return names.map((shim) => join16(binDir, shim));
|
|
22341
23912
|
}
|
|
22342
23913
|
function appiumCliCandidates(envDir, platform) {
|
|
22343
23914
|
return nodeModulesBinCandidates(envDir, "appium", platform);
|
|
@@ -22394,21 +23965,21 @@ async function checkUiautomator2(spawn, appiumBin, platform) {
|
|
|
22394
23965
|
}
|
|
22395
23966
|
|
|
22396
23967
|
// src/core/androidBins.ts
|
|
22397
|
-
import { join as
|
|
23968
|
+
import { join as join17 } from "node:path";
|
|
22398
23969
|
function withExeSuffix(name, platform) {
|
|
22399
23970
|
return platform === "win32" ? `${name}.exe` : name;
|
|
22400
23971
|
}
|
|
22401
23972
|
function emulatorBin(home, platform) {
|
|
22402
23973
|
const name = withExeSuffix("emulator", platform);
|
|
22403
|
-
return home ?
|
|
23974
|
+
return home ? join17(home, "emulator", name) : name;
|
|
22404
23975
|
}
|
|
22405
23976
|
function adbBin(home, platform) {
|
|
22406
23977
|
const name = withExeSuffix("adb", platform);
|
|
22407
|
-
return home ?
|
|
23978
|
+
return home ? join17(home, "platform-tools", name) : name;
|
|
22408
23979
|
}
|
|
22409
23980
|
function cmdlineToolsBin(home, name, platform) {
|
|
22410
23981
|
const file = platform === "win32" ? `${name}.bat` : name;
|
|
22411
|
-
return
|
|
23982
|
+
return join17(home, "cmdline-tools", "latest", "bin", file);
|
|
22412
23983
|
}
|
|
22413
23984
|
function sdkManagerBin(home, platform) {
|
|
22414
23985
|
return cmdlineToolsBin(home, "sdkmanager", platform);
|
|
@@ -22705,9 +24276,9 @@ async function checkNpmRegistry(deps) {
|
|
|
22705
24276
|
}
|
|
22706
24277
|
|
|
22707
24278
|
// src/core/playwrightCli.ts
|
|
22708
|
-
import { join as
|
|
24279
|
+
import { join as join18 } from "node:path";
|
|
22709
24280
|
function playwrightCliJsPath(envDir) {
|
|
22710
|
-
return
|
|
24281
|
+
return join18(envDir, "node_modules", "playwright", "cli.js");
|
|
22711
24282
|
}
|
|
22712
24283
|
function playwrightCliInvocation(args) {
|
|
22713
24284
|
return {
|
|
@@ -22721,7 +24292,7 @@ function playwrightCliInvocation(args) {
|
|
|
22721
24292
|
var flowsVersion = "0.1.4";
|
|
22722
24293
|
var playwrightVersion = "1.62.0";
|
|
22723
24294
|
var emailsVersion = "1.1.1";
|
|
22724
|
-
var testkitVersion = "1.
|
|
24295
|
+
var testkitVersion = "1.2.1";
|
|
22725
24296
|
var appiumVersion = "3.6.0";
|
|
22726
24297
|
var appiumUiautomator2DriverVersion = "8.4.0";
|
|
22727
24298
|
var expectWebdriverioVersion = "5.6.5";
|
|
@@ -22857,11 +24428,11 @@ function renderResults(ui, results) {
|
|
|
22857
24428
|
}
|
|
22858
24429
|
|
|
22859
24430
|
// src/domains/flows/ensureDeps.ts
|
|
22860
|
-
import { dirname as dirname4, join as
|
|
24431
|
+
import { dirname as dirname4, join as join19 } from "node:path";
|
|
22861
24432
|
function findEnvDir(flowPath, fs) {
|
|
22862
24433
|
let dir = dirname4(flowPath);
|
|
22863
24434
|
while (true) {
|
|
22864
|
-
if (fs.existsSync(
|
|
24435
|
+
if (fs.existsSync(join19(dir, "package.json")))
|
|
22865
24436
|
return dir;
|
|
22866
24437
|
const parent = dirname4(dir);
|
|
22867
24438
|
if (parent === dir)
|
|
@@ -22887,7 +24458,7 @@ function resolveProjectDirSafe(files, fs) {
|
|
|
22887
24458
|
}
|
|
22888
24459
|
|
|
22889
24460
|
// src/domains/flows/expand.ts
|
|
22890
|
-
import { join as
|
|
24461
|
+
import { join as join20, resolve as resolve3 } from "node:path";
|
|
22891
24462
|
|
|
22892
24463
|
// node_modules/tinyglobby/dist/index.mjs
|
|
22893
24464
|
import { readdir, readdirSync, realpath, realpathSync, stat, statSync } from "fs";
|
|
@@ -23716,7 +25287,6 @@ async function glob(globInput, options) {
|
|
|
23716
25287
|
}
|
|
23717
25288
|
|
|
23718
25289
|
// src/core/flowMeta.ts
|
|
23719
|
-
import { getWebBrowserInfo, parseExecutionTarget as parseExecutionTarget2 } from "@qawolf/flow-targets";
|
|
23720
25290
|
import { basename as basename2 } from "node:path";
|
|
23721
25291
|
|
|
23722
25292
|
// src/core/stringLiteral.ts
|
|
@@ -23832,7 +25402,7 @@ var browserNameToPlaywright = {
|
|
|
23832
25402
|
function classifyTarget(target) {
|
|
23833
25403
|
let parsed;
|
|
23834
25404
|
try {
|
|
23835
|
-
parsed =
|
|
25405
|
+
parsed = parseExecutionTarget(target);
|
|
23836
25406
|
} catch {
|
|
23837
25407
|
return { kind: "unrecognized" };
|
|
23838
25408
|
}
|
|
@@ -23876,11 +25446,11 @@ function makePeekFlowMeta(fs) {
|
|
|
23876
25446
|
};
|
|
23877
25447
|
}
|
|
23878
25448
|
async function resolveGlobRoots(cwd, fs) {
|
|
23879
|
-
const qawolfPath =
|
|
25449
|
+
const qawolfPath = join20(cwd, ".qawolf");
|
|
23880
25450
|
let envDirs = [];
|
|
23881
25451
|
try {
|
|
23882
25452
|
const entries = await fs.readdirWithTypes(qawolfPath);
|
|
23883
|
-
envDirs = entries.filter((e) => e.isDirectory()).map((e) =>
|
|
25453
|
+
envDirs = entries.filter((e) => e.isDirectory()).map((e) => join20(qawolfPath, e.name));
|
|
23884
25454
|
} catch {}
|
|
23885
25455
|
return [cwd, ...envDirs];
|
|
23886
25456
|
}
|
|
@@ -23906,11 +25476,11 @@ async function expandPatterns(patterns, cwd, logger, fs) {
|
|
|
23906
25476
|
}
|
|
23907
25477
|
|
|
23908
25478
|
// src/domains/runtimeEnv/clearRuntimeEnv.ts
|
|
23909
|
-
import { join as
|
|
25479
|
+
import { join as join22 } from "node:path";
|
|
23910
25480
|
|
|
23911
25481
|
// src/domains/runtimeEnv/managedEnvDir.ts
|
|
23912
25482
|
import { createHash } from "node:crypto";
|
|
23913
|
-
import { join as
|
|
25483
|
+
import { join as join21, resolve as resolve4 } from "node:path";
|
|
23914
25484
|
|
|
23915
25485
|
// src/domains/runtimeEnv/pinnedPackages.ts
|
|
23916
25486
|
var pinnedPackages = [
|
|
@@ -23941,19 +25511,19 @@ function managedEnvBaseDir() {
|
|
|
23941
25511
|
const override = process.env["QAWOLF_RUNTIME_DIR"]?.trim();
|
|
23942
25512
|
if (override)
|
|
23943
25513
|
return resolve4(override);
|
|
23944
|
-
return
|
|
25514
|
+
return join21(getDataDir(), "runtime");
|
|
23945
25515
|
}
|
|
23946
25516
|
function runStagingRoot() {
|
|
23947
25517
|
return `${managedEnvBaseDir()}-runs`;
|
|
23948
25518
|
}
|
|
23949
25519
|
function managedEnvDir() {
|
|
23950
|
-
return
|
|
25520
|
+
return join21(managedEnvBaseDir(), managedEnvHash());
|
|
23951
25521
|
}
|
|
23952
25522
|
async function scaffoldManagedEnv(dir, fs) {
|
|
23953
25523
|
await fs.mkdir(dir, { recursive: true });
|
|
23954
25524
|
const dependencies = Object.fromEntries(pinnedPackages.map(({ name, version }) => [name, version]));
|
|
23955
|
-
await fs.writeFile(
|
|
23956
|
-
await fs.writeFile(
|
|
25525
|
+
await fs.writeFile(join21(dir, "package.json"), JSON.stringify({ name: "qawolf-runtime", private: true, dependencies }, undefined, 2));
|
|
25526
|
+
await fs.writeFile(join21(dir, ".npmrc"), `@qawolf:registry=https://registry.npmjs.org/
|
|
23957
25527
|
`);
|
|
23958
25528
|
}
|
|
23959
25529
|
|
|
@@ -23975,14 +25545,14 @@ async function isManagedRuntimeBase(dir, fs) {
|
|
|
23975
25545
|
for (const entry of entries) {
|
|
23976
25546
|
if (!entry.isDirectory())
|
|
23977
25547
|
return false;
|
|
23978
|
-
if (!await hasRuntimeSentinel(
|
|
25548
|
+
if (!await hasRuntimeSentinel(join22(dir, entry.name), fs))
|
|
23979
25549
|
return false;
|
|
23980
25550
|
}
|
|
23981
25551
|
return true;
|
|
23982
25552
|
}
|
|
23983
25553
|
async function hasRuntimeSentinel(hashDir, fs) {
|
|
23984
25554
|
try {
|
|
23985
|
-
const pkg = JSON.parse(await fs.readFile(
|
|
25555
|
+
const pkg = JSON.parse(await fs.readFile(join22(hashDir, "package.json")));
|
|
23986
25556
|
return pkg.name === runtimeSentinel;
|
|
23987
25557
|
} catch {
|
|
23988
25558
|
return false;
|
|
@@ -24008,10 +25578,10 @@ function spawnNpmInstall(cwd, spawn2 = spawn) {
|
|
|
24008
25578
|
}
|
|
24009
25579
|
|
|
24010
25580
|
// src/domains/runtimeEnv/resolvePinned.ts
|
|
24011
|
-
import { join as
|
|
25581
|
+
import { join as join23 } from "node:path";
|
|
24012
25582
|
function readInstalledVersion(dir, pkgName, fs) {
|
|
24013
25583
|
try {
|
|
24014
|
-
const pkgPath =
|
|
25584
|
+
const pkgPath = join23(dir, "node_modules", ...pkgName.split("/"), "package.json");
|
|
24015
25585
|
const raw = JSON.parse(fs.readFileSync(pkgPath));
|
|
24016
25586
|
const { version } = raw;
|
|
24017
25587
|
return typeof version === "string" ? version : undefined;
|
|
@@ -24059,10 +25629,10 @@ function allPinnedResolved(dir, fs, platform) {
|
|
|
24059
25629
|
}
|
|
24060
25630
|
|
|
24061
25631
|
// src/domains/runtimeEnv/shimDeps.ts
|
|
24062
|
-
import { join as
|
|
25632
|
+
import { join as join25 } from "node:path";
|
|
24063
25633
|
|
|
24064
25634
|
// src/shell/resolveExport.ts
|
|
24065
|
-
import { join as
|
|
25635
|
+
import { join as join24 } from "node:path";
|
|
24066
25636
|
function pickPath(entry, preference) {
|
|
24067
25637
|
if (typeof entry === "string")
|
|
24068
25638
|
return entry;
|
|
@@ -24094,28 +25664,28 @@ function resolveFromEnvDir(envDir, specifier, preference = "esm", fs = makeDefau
|
|
|
24094
25664
|
const pkgName = parts.slice(0, pkgPartCount).join("/");
|
|
24095
25665
|
const rest = parts.slice(pkgPartCount);
|
|
24096
25666
|
const subpath = rest.length > 0 ? "./" + rest.join("/") : ".";
|
|
24097
|
-
const pkgDir =
|
|
25667
|
+
const pkgDir = join24(envDir, "node_modules", ...pkgName.split("/"));
|
|
24098
25668
|
let pkg;
|
|
24099
25669
|
try {
|
|
24100
|
-
pkg = JSON.parse(fs.readFileSync(
|
|
25670
|
+
pkg = JSON.parse(fs.readFileSync(join24(pkgDir, "package.json")));
|
|
24101
25671
|
} catch (err) {
|
|
24102
25672
|
if (isNoEntError(err))
|
|
24103
|
-
throw new Error(`Package '${pkgName}' not found in ${
|
|
25673
|
+
throw new Error(`Package '${pkgName}' not found in ${join24(envDir, "node_modules")}`, { cause: err });
|
|
24104
25674
|
throw err;
|
|
24105
25675
|
}
|
|
24106
25676
|
const exportsMap = normalizeExports(pkg.exports);
|
|
24107
25677
|
const entry = exportsMap?.[subpath];
|
|
24108
25678
|
const relative = pickPath(entry, preference) ?? (subpath === "." ? pkg.module ?? pkg.main : undefined);
|
|
24109
25679
|
if (!relative) {
|
|
24110
|
-
throw new Error(`No entry for "${subpath}" in exports of ${
|
|
25680
|
+
throw new Error(`No entry for "${subpath}" in exports of ${join24(pkgDir, "package.json")}`);
|
|
24111
25681
|
}
|
|
24112
|
-
return
|
|
25682
|
+
return join24(pkgDir, relative);
|
|
24113
25683
|
}
|
|
24114
25684
|
|
|
24115
25685
|
// src/domains/runtimeEnv/shimDeps.ts
|
|
24116
25686
|
function readShimMarker(shimDir, fs) {
|
|
24117
25687
|
try {
|
|
24118
|
-
const pkg = JSON.parse(fs.readFileSync(
|
|
25688
|
+
const pkg = JSON.parse(fs.readFileSync(join25(shimDir, "package.json")));
|
|
24119
25689
|
if (pkg._qawolf_format) {
|
|
24120
25690
|
return {
|
|
24121
25691
|
_qawolf_version: pkg._qawolf_version ?? "",
|
|
@@ -24131,11 +25701,11 @@ function resolveBunBuild(bunBuild) {
|
|
|
24131
25701
|
return bunBuild === false ? undefined : { build: bunBuild };
|
|
24132
25702
|
}
|
|
24133
25703
|
async function removeStaleShims(flowsDir, flowsDeps, fs) {
|
|
24134
|
-
const shimsDir =
|
|
25704
|
+
const shimsDir = join25(flowsDir, "node_modules");
|
|
24135
25705
|
if (!fs.existsSync(shimsDir))
|
|
24136
25706
|
return;
|
|
24137
25707
|
for (const dep of flowsDeps) {
|
|
24138
|
-
const shimDepDir =
|
|
25708
|
+
const shimDepDir = join25(shimsDir, ...dep.split("/"));
|
|
24139
25709
|
if (readShimMarker(shimDepDir, fs)) {
|
|
24140
25710
|
await fs.rm(shimDepDir, { recursive: true, force: true });
|
|
24141
25711
|
}
|
|
@@ -24144,17 +25714,17 @@ async function removeStaleShims(flowsDir, flowsDeps, fs) {
|
|
|
24144
25714
|
async function buildDepShim(args) {
|
|
24145
25715
|
const { envDir, flowsDir, dep, fs, build } = args;
|
|
24146
25716
|
const depParts = dep.split("/");
|
|
24147
|
-
const depDir =
|
|
25717
|
+
const depDir = join25(envDir, "node_modules", ...depParts);
|
|
24148
25718
|
if (!fs.existsSync(depDir))
|
|
24149
25719
|
return;
|
|
24150
25720
|
let depVersion;
|
|
24151
25721
|
try {
|
|
24152
|
-
const pkg = JSON.parse(fs.readFileSync(
|
|
25722
|
+
const pkg = JSON.parse(fs.readFileSync(join25(depDir, "package.json")));
|
|
24153
25723
|
depVersion = pkg.version ?? "unknown";
|
|
24154
25724
|
} catch {
|
|
24155
25725
|
depVersion = "unknown";
|
|
24156
25726
|
}
|
|
24157
|
-
const shimDir =
|
|
25727
|
+
const shimDir = join25(flowsDir, "node_modules", ...depParts);
|
|
24158
25728
|
if (fs.existsSync(shimDir)) {
|
|
24159
25729
|
const marker = readShimMarker(shimDir, fs);
|
|
24160
25730
|
if (!marker)
|
|
@@ -24181,20 +25751,20 @@ async function buildDepShim(args) {
|
|
|
24181
25751
|
}
|
|
24182
25752
|
const shimCode = await output.text();
|
|
24183
25753
|
await fs.mkdir(shimDir, { recursive: true });
|
|
24184
|
-
await fs.writeFile(
|
|
25754
|
+
await fs.writeFile(join25(shimDir, "package.json"), JSON.stringify({
|
|
24185
25755
|
name: dep,
|
|
24186
25756
|
_qawolf_version: depVersion,
|
|
24187
25757
|
_qawolf_format: "bun-build-v1"
|
|
24188
25758
|
}));
|
|
24189
|
-
await fs.writeFile(
|
|
25759
|
+
await fs.writeFile(join25(shimDir, "index.js"), shimCode);
|
|
24190
25760
|
}
|
|
24191
25761
|
async function shimFlowsDeps(envDir, fs = makeDefaultFs(), bunBuild) {
|
|
24192
|
-
const flowsDir =
|
|
25762
|
+
const flowsDir = join25(envDir, "node_modules", "@qawolf", "flows");
|
|
24193
25763
|
if (!fs.existsSync(flowsDir))
|
|
24194
25764
|
return;
|
|
24195
25765
|
let flowsDeps;
|
|
24196
25766
|
try {
|
|
24197
|
-
const flowsPkg = JSON.parse(fs.readFileSync(
|
|
25767
|
+
const flowsPkg = JSON.parse(fs.readFileSync(join25(flowsDir, "package.json")));
|
|
24198
25768
|
flowsDeps = Object.keys(flowsPkg.dependencies ?? {});
|
|
24199
25769
|
} catch {
|
|
24200
25770
|
return;
|
|
@@ -24375,11 +25945,11 @@ function collectValue(value, previous) {
|
|
|
24375
25945
|
}
|
|
24376
25946
|
|
|
24377
25947
|
// src/shell/manifest/pulledEnv.ts
|
|
24378
|
-
import { join as
|
|
25948
|
+
import { join as join27 } from "node:path";
|
|
24379
25949
|
|
|
24380
25950
|
// src/shell/manifest/io.ts
|
|
24381
25951
|
import { createHash as createHash2 } from "node:crypto";
|
|
24382
|
-
import { join as
|
|
25952
|
+
import { join as join26 } from "node:path";
|
|
24383
25953
|
var manifestFilename = ".manifest.json";
|
|
24384
25954
|
var flowEntrySchema = object({
|
|
24385
25955
|
path: string2(),
|
|
@@ -24401,7 +25971,7 @@ var manifestSchema = object({
|
|
|
24401
25971
|
async function readManifest(envDir, fs = makeDefaultFs()) {
|
|
24402
25972
|
let raw;
|
|
24403
25973
|
try {
|
|
24404
|
-
raw = await fs.readFile(
|
|
25974
|
+
raw = await fs.readFile(join26(envDir, manifestFilename));
|
|
24405
25975
|
} catch (err) {
|
|
24406
25976
|
if (isNoEntError(err))
|
|
24407
25977
|
return "missing";
|
|
@@ -24435,7 +26005,7 @@ async function readManifest(envDir, fs = makeDefaultFs()) {
|
|
|
24435
26005
|
}
|
|
24436
26006
|
async function writeManifest(envDir, manifest, fs = makeDefaultFs()) {
|
|
24437
26007
|
const body = JSON.stringify(manifest, undefined, 2);
|
|
24438
|
-
await fs.writeFile(
|
|
26008
|
+
await fs.writeFile(join26(envDir, manifestFilename), `${body}
|
|
24439
26009
|
`);
|
|
24440
26010
|
}
|
|
24441
26011
|
function hashFile(absPath, fs = makeDefaultFs()) {
|
|
@@ -24461,7 +26031,7 @@ async function findPulledEnv(ref, cwd, fs = makeDefaultFs()) {
|
|
|
24461
26031
|
return;
|
|
24462
26032
|
}
|
|
24463
26033
|
async function listPulledEnvDirs(cwd, fs = makeDefaultFs()) {
|
|
24464
|
-
const root =
|
|
26034
|
+
const root = join27(cwd, ".qawolf");
|
|
24465
26035
|
let entries;
|
|
24466
26036
|
try {
|
|
24467
26037
|
entries = await fs.readdirWithTypes(root);
|
|
@@ -24474,7 +26044,7 @@ async function listPulledEnvDirs(cwd, fs = makeDefaultFs()) {
|
|
|
24474
26044
|
for (const entry of entries) {
|
|
24475
26045
|
if (!entry.isDirectory())
|
|
24476
26046
|
continue;
|
|
24477
|
-
const envDir =
|
|
26047
|
+
const envDir = join27(root, entry.name);
|
|
24478
26048
|
const manifest = await readManifest(envDir, fs);
|
|
24479
26049
|
if (typeof manifest === "string")
|
|
24480
26050
|
continue;
|
|
@@ -24866,7 +26436,7 @@ async function flowsListRemote(ctx, pattern, options) {
|
|
|
24866
26436
|
}
|
|
24867
26437
|
|
|
24868
26438
|
// src/domains/flows/pull/handler.ts
|
|
24869
|
-
import { dirname as dirname8, join as
|
|
26439
|
+
import { dirname as dirname8, join as join32, resolve as resolve8 } from "node:path";
|
|
24870
26440
|
|
|
24871
26441
|
// src/domains/flows/pull/fetchPhase.ts
|
|
24872
26442
|
async function fetchTags(ctx, envId) {
|
|
@@ -24888,6 +26458,7 @@ async function fetchBundleAndEnvVars(ctx, envId) {
|
|
|
24888
26458
|
let bundleFetchedAt;
|
|
24889
26459
|
let envVars;
|
|
24890
26460
|
let envVarsFetchedAt;
|
|
26461
|
+
let teamId;
|
|
24891
26462
|
let tags;
|
|
24892
26463
|
await ctx.ui.withProgress([
|
|
24893
26464
|
{
|
|
@@ -24903,10 +26474,11 @@ async function fetchBundleAndEnvVars(ctx, envId) {
|
|
|
24903
26474
|
{
|
|
24904
26475
|
message: flowsMessages.pull.fetchingEnvVars,
|
|
24905
26476
|
task: async () => {
|
|
24906
|
-
const result = await platformClient.
|
|
26477
|
+
const result = await platformClient.getEnvironmentWithVariables(envId);
|
|
24907
26478
|
if (!result.ok)
|
|
24908
26479
|
throw new Error(result.error);
|
|
24909
|
-
envVars = result.value;
|
|
26480
|
+
envVars = result.value.environmentVariables;
|
|
26481
|
+
teamId = result.value.teamId;
|
|
24910
26482
|
envVarsFetchedAt = new Date;
|
|
24911
26483
|
}
|
|
24912
26484
|
},
|
|
@@ -24917,10 +26489,17 @@ async function fetchBundleAndEnvVars(ctx, envId) {
|
|
|
24917
26489
|
}
|
|
24918
26490
|
}
|
|
24919
26491
|
], flowsMessages.pull.downloadComplete);
|
|
24920
|
-
if (tmpArchive === undefined || bundleFetchedAt === undefined || envVars === undefined || envVarsFetchedAt === undefined) {
|
|
26492
|
+
if (tmpArchive === undefined || bundleFetchedAt === undefined || envVars === undefined || envVarsFetchedAt === undefined || teamId === undefined) {
|
|
24921
26493
|
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");
|
|
24922
26494
|
}
|
|
24923
|
-
return {
|
|
26495
|
+
return {
|
|
26496
|
+
tmpArchive,
|
|
26497
|
+
bundleFetchedAt,
|
|
26498
|
+
envVars,
|
|
26499
|
+
envVarsFetchedAt,
|
|
26500
|
+
teamId,
|
|
26501
|
+
tags
|
|
26502
|
+
};
|
|
24924
26503
|
}
|
|
24925
26504
|
|
|
24926
26505
|
// src/domains/flows/pull/safety.ts
|
|
@@ -25010,7 +26589,7 @@ async function checkSafety(args) {
|
|
|
25010
26589
|
}
|
|
25011
26590
|
|
|
25012
26591
|
// src/domains/flows/pull/reportPull.ts
|
|
25013
|
-
import { join as
|
|
26592
|
+
import { join as join28 } from "node:path";
|
|
25014
26593
|
function reportPullResult(ui, args) {
|
|
25015
26594
|
if (ui.mode !== "json")
|
|
25016
26595
|
return;
|
|
@@ -25025,12 +26604,12 @@ function reportPullResult(ui, args) {
|
|
|
25025
26604
|
assetDownloadedCount: args.assets.downloadedCount,
|
|
25026
26605
|
assetReusedCount: args.assets.reusedCount,
|
|
25027
26606
|
assetSkippedCount: args.assets.skippedCount,
|
|
25028
|
-
manifestPath:
|
|
26607
|
+
manifestPath: join28(args.stage.envDir, manifestFilename)
|
|
25029
26608
|
}, "");
|
|
25030
26609
|
}
|
|
25031
26610
|
|
|
25032
26611
|
// src/domains/flows/pull/bundle.ts
|
|
25033
|
-
import { join as
|
|
26612
|
+
import { join as join29, relative as relative6 } from "node:path";
|
|
25034
26613
|
async function flattenSingleWrapper(dir, fs = makeDefaultFs()) {
|
|
25035
26614
|
const entries = await fs.readdir(dir);
|
|
25036
26615
|
if (entries.length !== 1)
|
|
@@ -25038,12 +26617,12 @@ async function flattenSingleWrapper(dir, fs = makeDefaultFs()) {
|
|
|
25038
26617
|
const innerName = entries[0];
|
|
25039
26618
|
if (!innerName)
|
|
25040
26619
|
return;
|
|
25041
|
-
const inner =
|
|
26620
|
+
const inner = join29(dir, innerName);
|
|
25042
26621
|
const innerStat = await fs.stat(inner);
|
|
25043
26622
|
if (!innerStat.isDirectory())
|
|
25044
26623
|
return;
|
|
25045
26624
|
for (const e of await fs.readdir(inner)) {
|
|
25046
|
-
await fs.rename(
|
|
26625
|
+
await fs.rename(join29(inner, e), join29(dir, e));
|
|
25047
26626
|
}
|
|
25048
26627
|
const leftovers = await fs.readdir(inner);
|
|
25049
26628
|
if (leftovers.length > 0) {
|
|
@@ -25062,7 +26641,7 @@ async function buildManifest(args, fs = makeDefaultFs()) {
|
|
|
25062
26641
|
const flowPaths = await walkForFlows(args.bundleDir, fs);
|
|
25063
26642
|
const flows = await Promise.all(flowPaths.map(async (rel) => ({
|
|
25064
26643
|
path: toPosix(rel),
|
|
25065
|
-
contentHash: await hashFile(
|
|
26644
|
+
contentHash: await hashFile(join29(args.bundleDir, rel), fs),
|
|
25066
26645
|
tags: args.tags?.byPath.get(toPosix(rel))
|
|
25067
26646
|
})));
|
|
25068
26647
|
return {
|
|
@@ -25086,7 +26665,7 @@ async function walkForFlows(root, fs) {
|
|
|
25086
26665
|
async function walk(current, root, out, fs) {
|
|
25087
26666
|
const entries = await fs.readdirWithTypes(current);
|
|
25088
26667
|
for (const e of entries) {
|
|
25089
|
-
const abs =
|
|
26668
|
+
const abs = join29(current, e.name);
|
|
25090
26669
|
if (e.isDirectory()) {
|
|
25091
26670
|
await walk(abs, root, out, fs);
|
|
25092
26671
|
} else if (e.isFile() && flowExtensions.some((ext) => e.name.endsWith(ext))) {
|
|
@@ -25099,11 +26678,11 @@ async function sampleQawolfCommittedAt(bundleDir, fs = makeDefaultFs()) {
|
|
|
25099
26678
|
const sample = flowPaths[0];
|
|
25100
26679
|
if (!sample)
|
|
25101
26680
|
return;
|
|
25102
|
-
return (await fs.stat(
|
|
26681
|
+
return (await fs.stat(join29(bundleDir, sample))).mtime.toISOString();
|
|
25103
26682
|
}
|
|
25104
26683
|
|
|
25105
26684
|
// src/domains/flows/pull/applyTeamStorageRewrite.ts
|
|
25106
|
-
import { join as
|
|
26685
|
+
import { join as join30, relative as relative7 } from "node:path";
|
|
25107
26686
|
|
|
25108
26687
|
// src/domains/flows/pull/rewriteTeamStorage.ts
|
|
25109
26688
|
var runnerMountPrefix = "/home/wolf/team-storage/";
|
|
@@ -25139,7 +26718,7 @@ function isFlowFile(name) {
|
|
|
25139
26718
|
async function walk2(dir, out, fs) {
|
|
25140
26719
|
const entries = await fs.readdirWithTypes(dir);
|
|
25141
26720
|
for (const e of entries) {
|
|
25142
|
-
const abs =
|
|
26721
|
+
const abs = join30(dir, e.name);
|
|
25143
26722
|
if (e.isDirectory()) {
|
|
25144
26723
|
await walk2(abs, out, fs);
|
|
25145
26724
|
} else if (e.isFile() && isSourceFile(e.name)) {
|
|
@@ -25167,7 +26746,7 @@ async function applyTeamStorageRewrite(rootDir, fs = makeDefaultFs()) {
|
|
|
25167
26746
|
}
|
|
25168
26747
|
|
|
25169
26748
|
// src/domains/flows/pull/envVars.ts
|
|
25170
|
-
import { join as
|
|
26749
|
+
import { join as join31 } from "node:path";
|
|
25171
26750
|
|
|
25172
26751
|
// src/core/dotenv.ts
|
|
25173
26752
|
var bareKeyPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -25232,7 +26811,7 @@ function unquote(escaped) {
|
|
|
25232
26811
|
async function writeEnvFile(envDir, vars, fs = makeDefaultFs()) {
|
|
25233
26812
|
if (Object.keys(vars).length === 0)
|
|
25234
26813
|
return;
|
|
25235
|
-
await fs.writeFile(
|
|
26814
|
+
await fs.writeFile(join31(envDir, ".env"), serializeDotenv(vars), {
|
|
25236
26815
|
mode: 384
|
|
25237
26816
|
});
|
|
25238
26817
|
}
|
|
@@ -28674,8 +30253,8 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
28674
30253
|
ctx.ui.error(validation.error);
|
|
28675
30254
|
return { error: validation.error };
|
|
28676
30255
|
}
|
|
28677
|
-
const destAbs = resolve8(opts.out ??
|
|
28678
|
-
const assetsAbs =
|
|
30256
|
+
const destAbs = resolve8(opts.out ?? join32(".qawolf", opts.env));
|
|
30257
|
+
const assetsAbs = join32(dirname8(destAbs), "assets");
|
|
28679
30258
|
await resolvedDeps.fs.mkdir(assetsAbs, { recursive: true });
|
|
28680
30259
|
const yes = opts.yes ?? false;
|
|
28681
30260
|
let archive;
|
|
@@ -28721,6 +30300,7 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
28721
30300
|
message: flowsMessages.pull.downloadingTeamStorageAssets,
|
|
28722
30301
|
task: async (update) => {
|
|
28723
30302
|
const result = await ctx.platformClient.syncTeamStorageAssets(assetsAbs, {
|
|
30303
|
+
teamId: fetched.teamId,
|
|
28724
30304
|
onProgress: ({ current, total }) => update(flowsMessages.pull.downloadingTeamStorageAssetsProgress(current, total))
|
|
28725
30305
|
});
|
|
28726
30306
|
if (!result.ok)
|
|
@@ -29101,9 +30681,6 @@ ${hint}`);
|
|
|
29101
30681
|
};
|
|
29102
30682
|
}
|
|
29103
30683
|
|
|
29104
|
-
// src/domains/runner/runAndroidFlowUtils.ts
|
|
29105
|
-
import { parseExecutionTarget as parseExecutionTarget3 } from "@qawolf/flow-targets";
|
|
29106
|
-
|
|
29107
30684
|
// src/domains/runner/unsupportedDepNames.ts
|
|
29108
30685
|
var unsupportedSharedDepNames = [
|
|
29109
30686
|
"fetchLatestEnvironmentVariables",
|
|
@@ -29129,7 +30706,7 @@ function resolveAvdName(targetInput) {
|
|
|
29129
30706
|
const { deviceModel, androidVersion } = raw.meta;
|
|
29130
30707
|
return makeAvdName(deviceModel, androidVersion);
|
|
29131
30708
|
}
|
|
29132
|
-
const parsed =
|
|
30709
|
+
const parsed = parseExecutionTarget(raw);
|
|
29133
30710
|
if (parsed.platform !== "android") {
|
|
29134
30711
|
throw new Error(`runAndroidFlow: expected an Android target, got platform "${parsed.platform}"`);
|
|
29135
30712
|
}
|
|
@@ -29550,15 +31127,15 @@ async function defaultRunWebFlowDeps(envDir = process.cwd(), signals) {
|
|
|
29550
31127
|
|
|
29551
31128
|
// src/domains/runtimeEnv/prepareRunDir.ts
|
|
29552
31129
|
import { createHash as createHash4 } from "node:crypto";
|
|
29553
|
-
import { join as
|
|
31130
|
+
import { join as join40, resolve as resolve9 } from "node:path";
|
|
29554
31131
|
|
|
29555
31132
|
// src/domains/runtimeEnv/execSubpathImports.ts
|
|
29556
|
-
import { join as
|
|
31133
|
+
import { join as join33 } from "node:path";
|
|
29557
31134
|
var flowSubpathImports = { "#playwright": "playwright" };
|
|
29558
31135
|
var packageJsonSchema = looseObject({ imports: record(string2(), unknown()).catch({}) }).catch({ imports: {} });
|
|
29559
31136
|
async function writeExecSubpathImports(args) {
|
|
29560
31137
|
const { execDir, fs } = args;
|
|
29561
|
-
const pkgPath =
|
|
31138
|
+
const pkgPath = join33(execDir, "package.json");
|
|
29562
31139
|
const pkg = packageJsonSchema.parse(await readPackageJson(pkgPath, fs));
|
|
29563
31140
|
const merged = { ...pkg, imports: { ...pkg.imports, ...flowSubpathImports } };
|
|
29564
31141
|
await fs.writeFile(pkgPath, JSON.stringify(merged, undefined, 2));
|
|
@@ -29580,10 +31157,10 @@ async function readPackageJson(pkgPath, fs) {
|
|
|
29580
31157
|
}
|
|
29581
31158
|
|
|
29582
31159
|
// src/domains/runtimeEnv/innerHop.ts
|
|
29583
|
-
import { join as
|
|
31160
|
+
import { join as join35 } from "node:path";
|
|
29584
31161
|
|
|
29585
31162
|
// src/domains/runtimeEnv/linkPinnedPackages.ts
|
|
29586
|
-
import { dirname as dirname9, join as
|
|
31163
|
+
import { dirname as dirname9, join as join34 } from "node:path";
|
|
29587
31164
|
|
|
29588
31165
|
// src/domains/runtimeEnv/symlinkDir.ts
|
|
29589
31166
|
import { symlink } from "node:fs/promises";
|
|
@@ -29595,16 +31172,16 @@ async function createDirSymlink(source, target) {
|
|
|
29595
31172
|
// src/domains/runtimeEnv/linkPinnedPackages.ts
|
|
29596
31173
|
async function linkPinnedPackages(args) {
|
|
29597
31174
|
const { depsRoot, nodeModulesDir, fs } = args;
|
|
29598
|
-
const managedModules =
|
|
31175
|
+
const managedModules = join34(depsRoot, "node_modules");
|
|
29599
31176
|
await fs.mkdir(nodeModulesDir, { recursive: true });
|
|
29600
31177
|
for (const { name } of pinnedPackages) {
|
|
29601
31178
|
const segments = name.split("/");
|
|
29602
|
-
const target =
|
|
31179
|
+
const target = join34(nodeModulesDir, ...segments);
|
|
29603
31180
|
if (segments.length > 1) {
|
|
29604
31181
|
await fs.mkdir(dirname9(target), { recursive: true });
|
|
29605
31182
|
}
|
|
29606
31183
|
await fs.rm(target, { recursive: true, force: true });
|
|
29607
|
-
await createDirSymlink(
|
|
31184
|
+
await createDirSymlink(join34(managedModules, ...segments), target);
|
|
29608
31185
|
}
|
|
29609
31186
|
}
|
|
29610
31187
|
|
|
@@ -29613,18 +31190,18 @@ async function populateInnerHop(args) {
|
|
|
29613
31190
|
const { depsRoot, execDir, fs } = args;
|
|
29614
31191
|
await linkPinnedPackages({
|
|
29615
31192
|
depsRoot,
|
|
29616
|
-
nodeModulesDir:
|
|
31193
|
+
nodeModulesDir: join35(execDir, "node_modules"),
|
|
29617
31194
|
fs
|
|
29618
31195
|
});
|
|
29619
31196
|
}
|
|
29620
31197
|
|
|
29621
31198
|
// src/domains/runtimeEnv/outerHop.ts
|
|
29622
31199
|
import { lstat as lstat2 } from "node:fs/promises";
|
|
29623
|
-
import { dirname as dirname11, join as
|
|
31200
|
+
import { dirname as dirname11, join as join37 } from "node:path";
|
|
29624
31201
|
|
|
29625
31202
|
// src/domains/runtimeEnv/carryOverPackages.ts
|
|
29626
31203
|
import { lstat } from "node:fs/promises";
|
|
29627
|
-
import { dirname as dirname10, join as
|
|
31204
|
+
import { dirname as dirname10, join as join36 } from "node:path";
|
|
29628
31205
|
|
|
29629
31206
|
// src/domains/runtimeEnv/carryOverPlan.ts
|
|
29630
31207
|
var executorPackageNames = new Set(pinnedPackages.map((p) => p.name));
|
|
@@ -29646,12 +31223,12 @@ async function carryOverPackages(args) {
|
|
|
29646
31223
|
const linked = [];
|
|
29647
31224
|
for (const name of names) {
|
|
29648
31225
|
const segments = name.split("/");
|
|
29649
|
-
const target =
|
|
31226
|
+
const target = join36(nodeModulesDir, ...segments);
|
|
29650
31227
|
if (await pathOccupied(target))
|
|
29651
31228
|
continue;
|
|
29652
31229
|
if (segments.length > 1)
|
|
29653
31230
|
await fs.mkdir(dirname10(target), { recursive: true });
|
|
29654
|
-
await createDirSymlink(
|
|
31231
|
+
await createDirSymlink(join36(projectModulesDir, ...segments), target);
|
|
29655
31232
|
linked.push(name);
|
|
29656
31233
|
}
|
|
29657
31234
|
return linked;
|
|
@@ -29674,18 +31251,18 @@ async function listPackageNames(dir, fs) {
|
|
|
29674
31251
|
const names = [];
|
|
29675
31252
|
for (const entry of entries) {
|
|
29676
31253
|
if (!entry.startsWith("@")) {
|
|
29677
|
-
if (fs.existsSync(
|
|
31254
|
+
if (fs.existsSync(join36(dir, entry, "package.json")))
|
|
29678
31255
|
names.push(entry);
|
|
29679
31256
|
continue;
|
|
29680
31257
|
}
|
|
29681
31258
|
let scoped;
|
|
29682
31259
|
try {
|
|
29683
|
-
scoped = await fs.readdir(
|
|
31260
|
+
scoped = await fs.readdir(join36(dir, entry));
|
|
29684
31261
|
} catch {
|
|
29685
31262
|
continue;
|
|
29686
31263
|
}
|
|
29687
31264
|
for (const inner of scoped) {
|
|
29688
|
-
if (fs.existsSync(
|
|
31265
|
+
if (fs.existsSync(join36(dir, entry, inner, "package.json"))) {
|
|
29689
31266
|
names.push(`${entry}/${inner}`);
|
|
29690
31267
|
}
|
|
29691
31268
|
}
|
|
@@ -29703,7 +31280,7 @@ async function populateOuterHop(args) {
|
|
|
29703
31280
|
const depNames = Object.keys(installableDeps);
|
|
29704
31281
|
const { satisfying, rejected } = await findSatisfyingNodeModulesDir(projectDir, depNames, fs);
|
|
29705
31282
|
if (satisfying !== undefined) {
|
|
29706
|
-
await createDirSymlink(satisfying,
|
|
31283
|
+
await createDirSymlink(satisfying, join37(runDir, "node_modules"));
|
|
29707
31284
|
return { mode: "symlink", nodeModulesDir: satisfying };
|
|
29708
31285
|
}
|
|
29709
31286
|
if (depNames.length === 0)
|
|
@@ -29712,12 +31289,12 @@ async function populateOuterHop(args) {
|
|
|
29712
31289
|
await installOuterDeps(runDir, installableDeps, fs, args.install ?? spawnNpmInstall);
|
|
29713
31290
|
await linkPinnedPackages({
|
|
29714
31291
|
depsRoot: args.depsRoot,
|
|
29715
|
-
nodeModulesDir:
|
|
31292
|
+
nodeModulesDir: join37(runDir, "node_modules"),
|
|
29716
31293
|
fs
|
|
29717
31294
|
});
|
|
29718
31295
|
const carriedOver = await carryOverPackages({
|
|
29719
|
-
projectModulesDir:
|
|
29720
|
-
nodeModulesDir:
|
|
31296
|
+
projectModulesDir: join37(projectDir, "node_modules"),
|
|
31297
|
+
nodeModulesDir: join37(runDir, "node_modules"),
|
|
29721
31298
|
fs
|
|
29722
31299
|
});
|
|
29723
31300
|
return { mode: "install", depCount: depNames.length, rejected, carriedOver };
|
|
@@ -29726,10 +31303,10 @@ async function findSatisfyingNodeModulesDir(startDir, depNames, fs) {
|
|
|
29726
31303
|
const rejected = [];
|
|
29727
31304
|
let dir = startDir;
|
|
29728
31305
|
while (true) {
|
|
29729
|
-
const candidate =
|
|
31306
|
+
const candidate = join37(dir, "node_modules");
|
|
29730
31307
|
const stats = await lstatSafe(candidate);
|
|
29731
31308
|
if (stats !== undefined && stats.isDirectory() && !stats.isSymbolicLink()) {
|
|
29732
|
-
const missing = depNames.filter((name) => !fs.existsSync(
|
|
31309
|
+
const missing = depNames.filter((name) => !fs.existsSync(join37(candidate, name, "package.json")));
|
|
29733
31310
|
if (missing.length === 0)
|
|
29734
31311
|
return { satisfying: candidate, rejected };
|
|
29735
31312
|
rejected.push({ dir: candidate, missing });
|
|
@@ -29750,7 +31327,7 @@ async function lstatSafe(path) {
|
|
|
29750
31327
|
async function readInstallableDeps(projectDir, fs) {
|
|
29751
31328
|
let content;
|
|
29752
31329
|
try {
|
|
29753
|
-
content = await fs.readFile(
|
|
31330
|
+
content = await fs.readFile(join37(projectDir, "package.json"));
|
|
29754
31331
|
} catch {
|
|
29755
31332
|
return {};
|
|
29756
31333
|
}
|
|
@@ -29768,8 +31345,8 @@ async function readInstallableDeps(projectDir, fs) {
|
|
|
29768
31345
|
return Object.fromEntries(Object.entries(rawDeps).filter(([name]) => !executorPackageNames2.has(name)).filter((entry) => typeof entry[1] === "string"));
|
|
29769
31346
|
}
|
|
29770
31347
|
async function installOuterDeps(runDir, deps, fs, install) {
|
|
29771
|
-
await fs.writeFile(
|
|
29772
|
-
await fs.writeFile(
|
|
31348
|
+
await fs.writeFile(join37(runDir, "package.json"), JSON.stringify({ name: "qawolf-run", private: true, dependencies: deps }, undefined, 2));
|
|
31349
|
+
await fs.writeFile(join37(runDir, ".npmrc"), `@qawolf:registry=https://registry.npmjs.org/
|
|
29773
31350
|
`);
|
|
29774
31351
|
const result = await install(runDir);
|
|
29775
31352
|
if (result.exitCode !== 0) {
|
|
@@ -29779,14 +31356,14 @@ async function installOuterDeps(runDir, deps, fs, install) {
|
|
|
29779
31356
|
|
|
29780
31357
|
// src/domains/runtimeEnv/stageFlowFiles.ts
|
|
29781
31358
|
import { createHash as createHash3 } from "node:crypto";
|
|
29782
|
-
import { basename as basename6, dirname as dirname12, join as
|
|
31359
|
+
import { basename as basename6, dirname as dirname12, join as join39, sep as sep4 } from "node:path";
|
|
29783
31360
|
|
|
29784
31361
|
// src/shell/copyDir.ts
|
|
29785
31362
|
import { cp, readdir as readdir2 } from "node:fs/promises";
|
|
29786
|
-
import { basename as basename5, join as
|
|
31363
|
+
import { basename as basename5, join as join38 } from "node:path";
|
|
29787
31364
|
async function copyDirExcluding(source, destination, excludedNames) {
|
|
29788
31365
|
const entries = await readdir2(source, { withFileTypes: true });
|
|
29789
|
-
await Promise.all(entries.filter((entry) => !excludedNames.has(entry.name)).map((entry) => cp(
|
|
31366
|
+
await Promise.all(entries.filter((entry) => !excludedNames.has(entry.name)).map((entry) => cp(join38(source, entry.name), join38(destination, entry.name), {
|
|
29790
31367
|
recursive: true,
|
|
29791
31368
|
filter: (path) => !excludedNames.has(basename5(path))
|
|
29792
31369
|
})));
|
|
@@ -29803,14 +31380,14 @@ async function stageFlowFiles(args) {
|
|
|
29803
31380
|
if (files.length > 1) {
|
|
29804
31381
|
return Promise.all(files.map((f) => stageOneFile(f, execDir, fs)));
|
|
29805
31382
|
}
|
|
29806
|
-
await Promise.all(files.map((f) => fs.copyFile(f,
|
|
29807
|
-
return files.map((f) =>
|
|
31383
|
+
await Promise.all(files.map((f) => fs.copyFile(f, join39(execDir, basename6(f)))));
|
|
31384
|
+
return files.map((f) => join39(execDir, basename6(f)));
|
|
29808
31385
|
}
|
|
29809
31386
|
async function stageOneFile(file, execDir, fs) {
|
|
29810
31387
|
const dirHash = createHash3("sha256").update(dirname12(file)).digest("hex").slice(0, 8);
|
|
29811
|
-
const subDir =
|
|
31388
|
+
const subDir = join39(execDir, dirHash);
|
|
29812
31389
|
await fs.mkdir(subDir, { recursive: true });
|
|
29813
|
-
const dest =
|
|
31390
|
+
const dest = join39(subDir, basename6(file));
|
|
29814
31391
|
await fs.copyFile(file, dest);
|
|
29815
31392
|
return dest;
|
|
29816
31393
|
}
|
|
@@ -29818,7 +31395,7 @@ function remapPath(file, projectDir, execDir) {
|
|
|
29818
31395
|
if (file === projectDir)
|
|
29819
31396
|
return execDir;
|
|
29820
31397
|
if (file.startsWith(projectDir + sep4)) {
|
|
29821
|
-
return
|
|
31398
|
+
return join39(execDir, file.slice(projectDir.length + 1));
|
|
29822
31399
|
}
|
|
29823
31400
|
return;
|
|
29824
31401
|
}
|
|
@@ -29828,10 +31405,10 @@ async function prepareRunDir(args) {
|
|
|
29828
31405
|
const { files, projectDir, depsRoot, runRoot } = args;
|
|
29829
31406
|
const fs = args.fs ?? makeDefaultFs();
|
|
29830
31407
|
const runId = buildRunId(projectDir, files);
|
|
29831
|
-
const runDir =
|
|
31408
|
+
const runDir = join40(runRoot, runId);
|
|
29832
31409
|
await fs.rm(runDir, { recursive: true, force: true });
|
|
29833
31410
|
await fs.mkdir(runDir, { recursive: true });
|
|
29834
|
-
const execDir =
|
|
31411
|
+
const execDir = join40(runDir, "exec");
|
|
29835
31412
|
await fs.mkdir(execDir, { recursive: true });
|
|
29836
31413
|
await populateInnerHop({ depsRoot, execDir, fs });
|
|
29837
31414
|
const stagedFiles = await stageFlowFiles({ files, projectDir, execDir, fs });
|
|
@@ -29862,17 +31439,17 @@ function buildRunId(projectDir, files) {
|
|
|
29862
31439
|
}
|
|
29863
31440
|
|
|
29864
31441
|
// src/shell/testkit.ts
|
|
29865
|
-
import { join as
|
|
31442
|
+
import { join as join41 } from "node:path";
|
|
29866
31443
|
function notAvailableLocally(name) {
|
|
29867
31444
|
throw new Error(runnerMessages.notAvailableLocally(name));
|
|
29868
31445
|
}
|
|
29869
31446
|
async function loadSdkDeps(cwd) {
|
|
29870
|
-
const testkitDir =
|
|
31447
|
+
const testkitDir = join41(cwd, "node_modules", "@qawolf", "testkit");
|
|
29871
31448
|
try {
|
|
29872
31449
|
const clientMod = await importFromPath(resolveFromEnvDir(cwd, "@qawolf/testkit/client"));
|
|
29873
31450
|
if (typeof clientMod.createTestkitClient !== "function")
|
|
29874
31451
|
throw new Error("createTestkitClient is not a function");
|
|
29875
|
-
const scopeMod = await importFromPath(
|
|
31452
|
+
const scopeMod = await importFromPath(join41(testkitDir, "dist", "clientScope.js"));
|
|
29876
31453
|
if (typeof scopeMod.configureTestkitClient !== "function")
|
|
29877
31454
|
throw new Error("configureTestkitClient is not a function");
|
|
29878
31455
|
return {
|
|
@@ -29930,9 +31507,9 @@ async function registerLazyEmailsClient(getInbox, cwd, deps) {
|
|
|
29930
31507
|
}
|
|
29931
31508
|
|
|
29932
31509
|
// src/commands/flows/envVarDeps.ts
|
|
29933
|
-
import { join as
|
|
31510
|
+
import { join as join42 } from "node:path";
|
|
29934
31511
|
function envFilePath(envDir) {
|
|
29935
|
-
return
|
|
31512
|
+
return join42(envDir, ".env");
|
|
29936
31513
|
}
|
|
29937
31514
|
async function readEnv(envDir, fs) {
|
|
29938
31515
|
try {
|
|
@@ -30056,7 +31633,7 @@ async function selectRunByTag(args) {
|
|
|
30056
31633
|
}
|
|
30057
31634
|
|
|
30058
31635
|
// src/commands/flows/runStagedFlows.ts
|
|
30059
|
-
import { join as
|
|
31636
|
+
import { join as join46 } from "node:path";
|
|
30060
31637
|
|
|
30061
31638
|
// src/shell/appium/createAppiumServer.ts
|
|
30062
31639
|
import { existsSync as existsSync2 } from "node:fs";
|
|
@@ -30190,7 +31767,7 @@ var defaultAdb = async (args) => {
|
|
|
30190
31767
|
|
|
30191
31768
|
// src/shell/appium/createAndroidEmulator.ts
|
|
30192
31769
|
var defaultBootTimeoutMs = 120000;
|
|
30193
|
-
var
|
|
31770
|
+
var pollIntervalMs2 = 2000;
|
|
30194
31771
|
var defaultSpawnEmulator = (bin, args) => {
|
|
30195
31772
|
const child = spawn3(bin, args, { stdio: "ignore" });
|
|
30196
31773
|
child.unref();
|
|
@@ -30208,7 +31785,7 @@ async function bootSequence(adb, serial, cancelled) {
|
|
|
30208
31785
|
]).catch(() => ({ stdout: "" }));
|
|
30209
31786
|
if (stdout.trim() === "1")
|
|
30210
31787
|
return;
|
|
30211
|
-
await new Promise((r) => setTimeout(r,
|
|
31788
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs2));
|
|
30212
31789
|
}
|
|
30213
31790
|
}
|
|
30214
31791
|
function waitForBoot(adb, serial, timeoutMs) {
|
|
@@ -31362,14 +32939,14 @@ async function runWebFlow({
|
|
|
31362
32939
|
|
|
31363
32940
|
// src/shell/embeddedWorkerCli.ts
|
|
31364
32941
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
31365
|
-
import { basename as basename7, join as
|
|
32942
|
+
import { basename as basename7, join as join43 } from "node:path";
|
|
31366
32943
|
var embeddedCliPathEnv = "QAWOLF_EMBEDDED_CLI_PATH";
|
|
31367
32944
|
function extractEmbeddedWorkerCli() {
|
|
31368
32945
|
const assetPath = process.env[embeddedCliPathEnv];
|
|
31369
32946
|
if (assetPath === undefined || assetPath === "")
|
|
31370
32947
|
return;
|
|
31371
|
-
const dir =
|
|
31372
|
-
const dest =
|
|
32948
|
+
const dir = join43(getDataDir(), "worker");
|
|
32949
|
+
const dest = join43(dir, basename7(assetPath));
|
|
31373
32950
|
if (existsSync3(dest))
|
|
31374
32951
|
return dest;
|
|
31375
32952
|
mkdirSync3(dir, { recursive: true });
|
|
@@ -31527,33 +33104,33 @@ function makePooledDispatch(resolvedDir) {
|
|
|
31527
33104
|
import { dirname as dirname13 } from "node:path";
|
|
31528
33105
|
|
|
31529
33106
|
// src/shell/reporter/createConsoleReporter.ts
|
|
31530
|
-
import { styleText as
|
|
33107
|
+
import { styleText as styleText5 } from "node:util";
|
|
31531
33108
|
function fmtDuration(ms) {
|
|
31532
33109
|
return `(${(ms / 1000).toFixed(2)}s)`;
|
|
31533
33110
|
}
|
|
31534
33111
|
function fmtStampLine(manifest) {
|
|
31535
33112
|
const shortHash = manifest.contentHash.slice(0, 8);
|
|
31536
|
-
return ` ${
|
|
33113
|
+
return ` ${styleText5("dim", `env=${manifest.envId} hash=${shortHash}`)}
|
|
31537
33114
|
`;
|
|
31538
33115
|
}
|
|
31539
33116
|
function createConsoleReporter(deps) {
|
|
31540
33117
|
return {
|
|
31541
33118
|
onFlowStart({ name, path }) {
|
|
31542
|
-
deps.stdout.write(`${
|
|
33119
|
+
deps.stdout.write(`${styleText5("magenta", "•")} ${styleText5(["bold", "magenta"], name)} ${styleText5("dim", path)}
|
|
31543
33120
|
`);
|
|
31544
33121
|
},
|
|
31545
33122
|
onTestResult({ label, status, durationMs }) {
|
|
31546
|
-
const icon = status === "pass" ?
|
|
31547
|
-
deps.stdout.write(` - ${label} ${icon} ${
|
|
33123
|
+
const icon = status === "pass" ? styleText5("green", "✓") : styleText5("red", "✗");
|
|
33124
|
+
deps.stdout.write(` - ${label} ${icon} ${styleText5("dim", fmtDuration(durationMs))}
|
|
31548
33125
|
`);
|
|
31549
33126
|
},
|
|
31550
33127
|
onScreenshot({ path }) {
|
|
31551
|
-
deps.stdout.write(` ${
|
|
33128
|
+
deps.stdout.write(` ${styleText5("dim", runnerMessages.screenshot(path))}
|
|
31552
33129
|
`);
|
|
31553
33130
|
},
|
|
31554
33131
|
onFlowPass({ tests, durationMs, manifest }) {
|
|
31555
33132
|
const counts = tests.total > 0 ? `${tests.passed}/${tests.total} tests ` : "";
|
|
31556
|
-
deps.stdout.write(` ${
|
|
33133
|
+
deps.stdout.write(` ${styleText5("green", "✓")} ${counts}passed ${styleText5("dim", fmtDuration(durationMs))}
|
|
31557
33134
|
`);
|
|
31558
33135
|
if (manifest)
|
|
31559
33136
|
deps.stdout.write(fmtStampLine(manifest));
|
|
@@ -31564,8 +33141,8 @@ function createConsoleReporter(deps) {
|
|
|
31564
33141
|
`);
|
|
31565
33142
|
const indent = " ";
|
|
31566
33143
|
const formatted = [
|
|
31567
|
-
|
|
31568
|
-
...restLines.map((line) =>
|
|
33144
|
+
styleText5("red", `${indent}${firstLine}`),
|
|
33145
|
+
...restLines.map((line) => styleText5("dim", `${indent}${line}`))
|
|
31569
33146
|
].join(`
|
|
31570
33147
|
`);
|
|
31571
33148
|
deps.stderr.write(`${formatted}
|
|
@@ -31573,12 +33150,12 @@ function createConsoleReporter(deps) {
|
|
|
31573
33150
|
`);
|
|
31574
33151
|
const hint = flowFailureHint(errStr, deps.projectDir);
|
|
31575
33152
|
if (hint !== undefined) {
|
|
31576
|
-
deps.stderr.write(`${
|
|
33153
|
+
deps.stderr.write(`${styleText5("yellow", `${indent}${hint}`)}
|
|
31577
33154
|
|
|
31578
33155
|
`);
|
|
31579
33156
|
}
|
|
31580
33157
|
const counts = tests.total > 0 ? `${tests.passed}/${tests.total} tests ` : "";
|
|
31581
|
-
deps.stdout.write(` ${
|
|
33158
|
+
deps.stdout.write(` ${styleText5("red", "✗")} ${counts}passed ${styleText5("dim", fmtDuration(durationMs))}
|
|
31582
33159
|
`);
|
|
31583
33160
|
if (manifest)
|
|
31584
33161
|
deps.stdout.write(fmtStampLine(manifest));
|
|
@@ -31593,21 +33170,21 @@ ${runnerMessages.retrying(attempt, maxAttempts)}
|
|
|
31593
33170
|
if (total <= 1)
|
|
31594
33171
|
return;
|
|
31595
33172
|
const allPassed = summary.flowsFailed === 0;
|
|
31596
|
-
const icon =
|
|
33173
|
+
const icon = styleText5(allPassed ? "green" : "red", allPassed ? "✓" : "✗");
|
|
31597
33174
|
const skippedStr = summary.flowsSkipped > 0 ? ` (${summary.flowsSkipped} skipped)` : "";
|
|
31598
33175
|
const flowCount = `${summary.flowsPassed}/${total} flows passed${skippedStr}`;
|
|
31599
33176
|
const testCount = summary.testsTotal > 0 ? ` · ${summary.testsPassed}/${summary.testsTotal} tests passed` : "";
|
|
31600
33177
|
const width = deps.columns ?? process.stdout.columns ?? 72;
|
|
31601
33178
|
deps.stdout.write(`
|
|
31602
|
-
${
|
|
33179
|
+
${styleText5("dim", "─".repeat(width))}
|
|
31603
33180
|
`);
|
|
31604
|
-
deps.stdout.write(` ${icon} ${flowCount}${testCount} ${
|
|
33181
|
+
deps.stdout.write(` ${icon} ${flowCount}${testCount} ${styleText5("dim", fmtDuration(summary.durationMs))}
|
|
31605
33182
|
`);
|
|
31606
33183
|
}
|
|
31607
33184
|
};
|
|
31608
33185
|
}
|
|
31609
33186
|
// src/shell/reporter/createJUnitReporter.ts
|
|
31610
|
-
import { join as
|
|
33187
|
+
import { join as join44 } from "node:path";
|
|
31611
33188
|
|
|
31612
33189
|
// src/shell/reporter/junitXml.ts
|
|
31613
33190
|
function escapeXml(str) {
|
|
@@ -31646,7 +33223,7 @@ ${suites}`;
|
|
|
31646
33223
|
|
|
31647
33224
|
// src/shell/reporter/createJUnitReporter.ts
|
|
31648
33225
|
function resolveJUnitOutputPath(junit, outputDir) {
|
|
31649
|
-
return typeof junit === "string" && junit.trim() !== "" ? junit :
|
|
33226
|
+
return typeof junit === "string" && junit.trim() !== "" ? junit : join44(outputDir, "junit-report.xml");
|
|
31650
33227
|
}
|
|
31651
33228
|
function createJUnitReporter(deps) {
|
|
31652
33229
|
const flows = [];
|
|
@@ -31737,11 +33314,11 @@ function buildFlowsRunDeps(args) {
|
|
|
31737
33314
|
|
|
31738
33315
|
// src/commands/flows/loadEnvFile.ts
|
|
31739
33316
|
import { readFile } from "node:fs/promises";
|
|
31740
|
-
import { join as
|
|
33317
|
+
import { join as join45 } from "node:path";
|
|
31741
33318
|
async function loadEnvFile(envDir) {
|
|
31742
33319
|
let content;
|
|
31743
33320
|
try {
|
|
31744
|
-
content = await readFile(
|
|
33321
|
+
content = await readFile(join45(envDir, ".env"), "utf8");
|
|
31745
33322
|
} catch (err) {
|
|
31746
33323
|
if (isNoEntError(err))
|
|
31747
33324
|
return;
|
|
@@ -31786,7 +33363,7 @@ async function runStagedFlows(args) {
|
|
|
31786
33363
|
for (const candidate of staged.outerHop.rejected) {
|
|
31787
33364
|
log.debug(runnerMessages.outerHopCandidateRejected(candidate.dir, candidate.missing));
|
|
31788
33365
|
}
|
|
31789
|
-
const ownModules = projectDir === undefined ? undefined :
|
|
33366
|
+
const ownModules = projectDir === undefined ? undefined : join46(projectDir, "node_modules");
|
|
31790
33367
|
const own = staged.outerHop.rejected.find((c) => c.dir === ownModules);
|
|
31791
33368
|
if (own !== undefined) {
|
|
31792
33369
|
ctx.ui.warn(runnerMessages.outerHopFallbackNotice(own.dir, own.missing));
|
|
@@ -31882,7 +33459,7 @@ async function chooseEnv(ctx, files, allEnvs) {
|
|
|
31882
33459
|
}
|
|
31883
33460
|
|
|
31884
33461
|
// src/commands/flows/hybridRunDefaults.ts
|
|
31885
|
-
import { join as
|
|
33462
|
+
import { join as join47, resolve as resolve10 } from "node:path";
|
|
31886
33463
|
|
|
31887
33464
|
// src/core/selectFlowFiles.ts
|
|
31888
33465
|
function selectFlowFiles(args) {
|
|
@@ -31987,7 +33564,7 @@ async function handleHybridFlowsRun(ctx, pattern, flags, options = {}) {
|
|
|
31987
33564
|
if (validation !== "ok") {
|
|
31988
33565
|
return { error: validation.error, exitCode: 2 };
|
|
31989
33566
|
}
|
|
31990
|
-
const envDir = resolve10(
|
|
33567
|
+
const envDir = resolve10(join47(".qawolf", flags.env));
|
|
31991
33568
|
const patternArgs = buildPatternArgs(pattern);
|
|
31992
33569
|
const globFlows = () => resolvedDeps.expandPatterns(patternArgs, envDir, ctx.log("flows"));
|
|
31993
33570
|
let files = await globFlows();
|
|
@@ -32183,12 +33760,12 @@ function registerFlowsCommand(program, signals, deps = { withResolvedEnv }) {
|
|
|
32183
33760
|
}
|
|
32184
33761
|
|
|
32185
33762
|
// src/domains/init/init.ts
|
|
32186
|
-
import { dirname as dirname14, join as
|
|
33763
|
+
import { dirname as dirname14, join as join49, relative as relative9 } from "node:path";
|
|
32187
33764
|
|
|
32188
33765
|
// src/domains/init/ensurePackageJson.ts
|
|
32189
|
-
import { join as
|
|
33766
|
+
import { join as join48 } from "node:path";
|
|
32190
33767
|
async function ensurePackageJson(ctx, yes, deps) {
|
|
32191
|
-
const pkgPath =
|
|
33768
|
+
const pkgPath = join48(deps.cwd, "package.json");
|
|
32192
33769
|
if (!await deps.fs.pathExists(pkgPath)) {
|
|
32193
33770
|
const confirmed = await ctx.ui.confirm(initMessages.createPackageJsonPrompt, { yes });
|
|
32194
33771
|
if (!confirmed.ok || !confirmed.value) {
|
|
@@ -32314,9 +33891,9 @@ function makeDefaultInitDeps() {
|
|
|
32314
33891
|
async function handleInit(ctx, opts, deps = makeDefaultInitDeps()) {
|
|
32315
33892
|
ctx.ui.gap();
|
|
32316
33893
|
ctx.ui.intro(initMessages.title);
|
|
32317
|
-
const configPath =
|
|
32318
|
-
const flowPath =
|
|
32319
|
-
const gitignorePath =
|
|
33894
|
+
const configPath = join49(deps.cwd, "qawolf.config.ts");
|
|
33895
|
+
const flowPath = join49(deps.cwd, "src", "flows", "example.flow.ts");
|
|
33896
|
+
const gitignorePath = join49(deps.cwd, ".qawolf", ".gitignore");
|
|
32320
33897
|
await writeWithPrompt(ctx, configPath, qawolfConfigTs, opts.yes, deps);
|
|
32321
33898
|
await writeWithPrompt(ctx, flowPath, exampleFlowTs, opts.yes, deps);
|
|
32322
33899
|
await writeWithPrompt(ctx, gitignorePath, qawolfGitignore, opts.yes, deps);
|
|
@@ -32350,11 +33927,8 @@ Examples:
|
|
|
32350
33927
|
});
|
|
32351
33928
|
}
|
|
32352
33929
|
|
|
32353
|
-
// src/domains/install/android/index.ts
|
|
32354
|
-
import { parseExecutionTarget as parseExecutionTarget4 } from "@qawolf/flow-targets";
|
|
32355
|
-
|
|
32356
33930
|
// src/domains/install/android/avd.ts
|
|
32357
|
-
import { join as
|
|
33931
|
+
import { join as join50 } from "node:path";
|
|
32358
33932
|
async function installAvds(ctx, specs, deps) {
|
|
32359
33933
|
const sdkManagerPath = sdkManagerBin(deps.androidHome, deps.platform);
|
|
32360
33934
|
const avdManagerPath = avdManagerBin(deps.androidHome, deps.platform);
|
|
@@ -32364,7 +33938,7 @@ async function installAvds(ctx, specs, deps) {
|
|
|
32364
33938
|
if (versionResult.exitCode !== 0) {
|
|
32365
33939
|
throw new Error(installMessages.android.sdkmanagerNotFound(sdkManagerPath));
|
|
32366
33940
|
}
|
|
32367
|
-
const licenseFile =
|
|
33941
|
+
const licenseFile = join50(deps.androidHome, "licenses", "android-sdk-license");
|
|
32368
33942
|
if (deps.checkExists(licenseFile)) {
|
|
32369
33943
|
ctx.ui.info(installMessages.android.licensesAlreadyAccepted);
|
|
32370
33944
|
} else {
|
|
@@ -32379,7 +33953,7 @@ async function installAvds(ctx, specs, deps) {
|
|
|
32379
33953
|
for (const spec of specs) {
|
|
32380
33954
|
if (installedImages.has(spec.systemImage))
|
|
32381
33955
|
continue;
|
|
32382
|
-
const systemImg =
|
|
33956
|
+
const systemImg = join50(deps.androidHome, ...spec.systemImage.split(";"), "system.img");
|
|
32383
33957
|
if (deps.checkExists(systemImg)) {
|
|
32384
33958
|
ctx.ui.info(installMessages.android.systemImageAlreadyInstalled(spec.systemImage));
|
|
32385
33959
|
installedImages.add(spec.systemImage);
|
|
@@ -32492,7 +34066,7 @@ function buildAvdSpecs(targets, arch) {
|
|
|
32492
34066
|
const avdName = avdNameForTarget(target);
|
|
32493
34067
|
if (!avdName || seen.has(avdName))
|
|
32494
34068
|
continue;
|
|
32495
|
-
const parsed =
|
|
34069
|
+
const parsed = parseExecutionTarget(target);
|
|
32496
34070
|
if (parsed.platform !== "android")
|
|
32497
34071
|
continue;
|
|
32498
34072
|
const { deviceModel, androidVersion } = parsed.meta;
|
|
@@ -32881,6 +34455,8 @@ async function handlePublicApiCommand(ctx, spec, options) {
|
|
|
32881
34455
|
|
|
32882
34456
|
// src/domains/publicApi/skippedContracts.ts
|
|
32883
34457
|
var skippedContractNames = new Set([
|
|
34458
|
+
"agent.get",
|
|
34459
|
+
"agent.send",
|
|
32884
34460
|
"flow.list",
|
|
32885
34461
|
"runner.evaluateSnippet",
|
|
32886
34462
|
"runner.get",
|
|
@@ -32899,34 +34475,6 @@ var skippedContractNames = new Set([
|
|
|
32899
34475
|
"runner.terminate"
|
|
32900
34476
|
]);
|
|
32901
34477
|
|
|
32902
|
-
// src/commands/publicApi/environmentOptions.ts
|
|
32903
|
-
var optionEnvironmentVariables = new Map([
|
|
32904
|
-
["environmentId", "QAWOLF_ENVIRONMENT"],
|
|
32905
|
-
["public.run.create.aiTaskId", "QAWOLF_AI_TASK_ID"],
|
|
32906
|
-
["public.run.create.chatSessionId", "QAWOLF_CHAT_SESSION_ID"]
|
|
32907
|
-
]);
|
|
32908
|
-
function optionEnvironmentVariable(spec, path) {
|
|
32909
|
-
const dotted = path.join(".");
|
|
32910
|
-
return optionEnvironmentVariables.get(`${spec.trpcPath}.${dotted}`) ?? optionEnvironmentVariables.get(dotted);
|
|
32911
|
-
}
|
|
32912
|
-
var exclusiveOptions = new Map([
|
|
32913
|
-
["public.run.create", { keep: "aiTaskId", drop: "chatSessionId" }]
|
|
32914
|
-
]);
|
|
32915
|
-
function withoutExclusiveConflict(spec, command, options) {
|
|
32916
|
-
const pair = exclusiveOptions.get(spec.trpcPath);
|
|
32917
|
-
if (!pair)
|
|
32918
|
-
return options;
|
|
32919
|
-
if (options[pair.keep] === undefined || options[pair.drop] === undefined) {
|
|
32920
|
-
return options;
|
|
32921
|
-
}
|
|
32922
|
-
const fromEnvironment = (key) => command.getOptionValueSource(key) === "env";
|
|
32923
|
-
if (!fromEnvironment(pair.keep) && !fromEnvironment(pair.drop)) {
|
|
32924
|
-
return options;
|
|
32925
|
-
}
|
|
32926
|
-
const dropped = fromEnvironment(pair.drop) ? pair.drop : pair.keep;
|
|
32927
|
-
return Object.fromEntries(Object.entries(options).filter(([key]) => key !== dropped));
|
|
32928
|
-
}
|
|
32929
|
-
|
|
32930
34478
|
// src/commands/publicApi/index.ts
|
|
32931
34479
|
var groupDescriptions = {
|
|
32932
34480
|
run: "Trigger and manage QA Wolf runs on the platform"
|
|
@@ -33063,14 +34611,12 @@ function parseRunnerName(runnerName) {
|
|
|
33063
34611
|
|
|
33064
34612
|
// src/domains/interactiveRunner/resolveRunner.ts
|
|
33065
34613
|
var runnerIdEnvironmentVariable = "QAWOLF_RUNNER_ID";
|
|
33066
|
-
|
|
33067
|
-
|
|
33068
|
-
|
|
33069
|
-
|
|
33070
|
-
|
|
33071
|
-
|
|
33072
|
-
return deps.store.readDefaultRunnerId();
|
|
33073
|
-
}
|
|
34614
|
+
var chooseRunnerId = (runner, deps) => resolveIdFrom({
|
|
34615
|
+
env: deps.env,
|
|
34616
|
+
environmentVariable: runnerIdEnvironmentVariable,
|
|
34617
|
+
given: runner,
|
|
34618
|
+
readStored: deps.store.readDefaultRunnerId
|
|
34619
|
+
});
|
|
33074
34620
|
async function resolveRunner(ctx, options, deps) {
|
|
33075
34621
|
const chosen = await chooseRunnerId(options.runner, deps);
|
|
33076
34622
|
if (chosen !== undefined) {
|
|
@@ -33096,11 +34642,15 @@ async function resolveRunner(ctx, options, deps) {
|
|
|
33096
34642
|
type: "failed"
|
|
33097
34643
|
};
|
|
33098
34644
|
}
|
|
33099
|
-
return {
|
|
34645
|
+
return {
|
|
34646
|
+
runnerId: launched.value.id,
|
|
34647
|
+
type: "launched",
|
|
34648
|
+
url: launched.value.url
|
|
34649
|
+
};
|
|
33100
34650
|
}
|
|
33101
34651
|
function announceRunner(ctx, resolved) {
|
|
33102
34652
|
if (resolved.type === "launched") {
|
|
33103
|
-
ctx.ui.info(interactiveRunnerMessages.launchedForCommand(resolved.runnerId));
|
|
34653
|
+
ctx.ui.info(interactiveRunnerMessages.launchedForCommand(resolved.runnerId, resolved.url));
|
|
33104
34654
|
}
|
|
33105
34655
|
}
|
|
33106
34656
|
|
|
@@ -33241,7 +34791,7 @@ async function handleRunnerExec(ctx, options, deps) {
|
|
|
33241
34791
|
}
|
|
33242
34792
|
|
|
33243
34793
|
// src/shell/interactiveRunner/collectRunFiles.ts
|
|
33244
|
-
import { join as
|
|
34794
|
+
import { join as join52 } from "node:path";
|
|
33245
34795
|
|
|
33246
34796
|
// src/core/interactiveRunner/getImports.ts
|
|
33247
34797
|
function getImports(options) {
|
|
@@ -33280,7 +34830,7 @@ function isPathAlias(importPath, paths) {
|
|
|
33280
34830
|
}
|
|
33281
34831
|
|
|
33282
34832
|
// src/core/interactiveRunner/resolveImportPath.ts
|
|
33283
|
-
import { dirname as dirname15, join as
|
|
34833
|
+
import { dirname as dirname15, join as join51, normalize as normalize3 } from "node:path/posix";
|
|
33284
34834
|
|
|
33285
34835
|
// src/core/interactiveRunner/tsconfigPaths.ts
|
|
33286
34836
|
function isRecord4(value) {
|
|
@@ -33333,7 +34883,7 @@ function candidatesForExplicitExtension(options) {
|
|
|
33333
34883
|
}
|
|
33334
34884
|
function resolveImportPath(options) {
|
|
33335
34885
|
const aliasTarget = resolvePathAlias(options.importPath, options.tsconfigPaths);
|
|
33336
|
-
const resolvedPath = aliasTarget === undefined ? normalize3(
|
|
34886
|
+
const resolvedPath = aliasTarget === undefined ? normalize3(join51(dirname15(options.importingFilePath), options.importPath)) : normalize3(aliasTarget);
|
|
33337
34887
|
const hasExplicitExtension = supportedExtensions.some((extension) => options.importPath.endsWith(extension));
|
|
33338
34888
|
const candidates = hasExplicitExtension ? candidatesForExplicitExtension({
|
|
33339
34889
|
importPath: options.importPath,
|
|
@@ -33357,7 +34907,7 @@ function resolveImportPath(options) {
|
|
|
33357
34907
|
var tsconfigPath = "tsconfig.json";
|
|
33358
34908
|
async function collectRunFiles(options) {
|
|
33359
34909
|
const held = await listShippablePaths(options);
|
|
33360
|
-
const readFile = (path) => options.fs.readFile(
|
|
34910
|
+
const readFile = (path) => options.fs.readFile(join52(options.cwd, path));
|
|
33361
34911
|
const tsconfigContent = held.has(tsconfigPath) ? await readFile(tsconfigPath).catch(() => {
|
|
33362
34912
|
return;
|
|
33363
34913
|
}) : undefined;
|
|
@@ -33440,7 +34990,7 @@ function makeRunnerId() {
|
|
|
33440
34990
|
}
|
|
33441
34991
|
|
|
33442
34992
|
// src/shell/interactiveRunner/runFilesManifest.ts
|
|
33443
|
-
import { join as
|
|
34993
|
+
import { join as join53 } from "node:path";
|
|
33444
34994
|
var manifestFileName = "runner-files.json";
|
|
33445
34995
|
var manifestSchema2 = object({
|
|
33446
34996
|
files: array(object({ contentHash: string2(), path: string2() })),
|
|
@@ -33448,75 +34998,37 @@ var manifestSchema2 = object({
|
|
|
33448
34998
|
version: literal(1)
|
|
33449
34999
|
});
|
|
33450
35000
|
function makeRunFilesManifestStore(options) {
|
|
33451
|
-
const directory =
|
|
33452
|
-
const path =
|
|
33453
|
-
let pendingWrites = 0;
|
|
35001
|
+
const directory = join53(options.cwd, qawolfDir);
|
|
35002
|
+
const path = join53(directory, manifestFileName);
|
|
33454
35003
|
return {
|
|
33455
|
-
|
|
33456
|
-
const contents = await options.fs.readFile(path).catch(() => {
|
|
33457
|
-
return;
|
|
33458
|
-
});
|
|
33459
|
-
if (contents === undefined)
|
|
33460
|
-
return;
|
|
33461
|
-
const parsed = manifestSchema2.safeParse(parseJson(contents));
|
|
33462
|
-
return parsed.success ? parsed.data : undefined;
|
|
33463
|
-
},
|
|
35004
|
+
read: () => readJsonFile(options.fs, path, manifestSchema2),
|
|
33464
35005
|
async write(manifest) {
|
|
33465
|
-
const pendingPath = `${path}.${String(process.pid)}.${String(++pendingWrites)}.tmp`;
|
|
33466
35006
|
await options.fs.mkdir(directory, { recursive: true });
|
|
33467
|
-
await options.fs
|
|
33468
|
-
`);
|
|
33469
|
-
await options.fs.rename(pendingPath, path);
|
|
35007
|
+
await writeJsonFileAtomically(options.fs, path, manifest);
|
|
33470
35008
|
}
|
|
33471
35009
|
};
|
|
33472
35010
|
}
|
|
33473
|
-
function parseJson(text) {
|
|
33474
|
-
try {
|
|
33475
|
-
return JSON.parse(text);
|
|
33476
|
-
} catch {
|
|
33477
|
-
return;
|
|
33478
|
-
}
|
|
33479
|
-
}
|
|
33480
35011
|
|
|
33481
35012
|
// src/shell/interactiveRunner/runnerStore.ts
|
|
33482
|
-
import { join as
|
|
33483
|
-
var
|
|
35013
|
+
import { join as join54 } from "node:path";
|
|
35014
|
+
var storeFileName2 = "runner.json";
|
|
33484
35015
|
var runnersDirName = "runners";
|
|
33485
35016
|
var storedRunnerSchema = object({
|
|
33486
35017
|
id: string2(),
|
|
33487
35018
|
runnerName: string2().optional()
|
|
33488
35019
|
});
|
|
33489
|
-
var
|
|
35020
|
+
var storeSchema2 = object({
|
|
33490
35021
|
defaultRunnerId: string2().optional()
|
|
33491
35022
|
});
|
|
33492
|
-
function parseJson2(text) {
|
|
33493
|
-
try {
|
|
33494
|
-
return JSON.parse(text);
|
|
33495
|
-
} catch {
|
|
33496
|
-
return;
|
|
33497
|
-
}
|
|
33498
|
-
}
|
|
33499
|
-
var pendingWrites = 0;
|
|
33500
35023
|
function makeRunnerStore(options) {
|
|
33501
|
-
const directory =
|
|
33502
|
-
const path =
|
|
33503
|
-
const runnersDir =
|
|
33504
|
-
const
|
|
33505
|
-
const
|
|
33506
|
-
const writeAtomically = async (target, contents) => {
|
|
33507
|
-
const pendingPath = nextPendingPath(target);
|
|
33508
|
-
await options.fs.writeFile(pendingPath, `${JSON.stringify(contents, undefined, 2)}
|
|
33509
|
-
`);
|
|
33510
|
-
await options.fs.rename(pendingPath, target);
|
|
33511
|
-
};
|
|
35024
|
+
const directory = join54(options.cwd, qawolfDir);
|
|
35025
|
+
const path = join54(directory, storeFileName2);
|
|
35026
|
+
const runnersDir = join54(directory, runnersDirName);
|
|
35027
|
+
const runnerPath = (runnerId) => join54(runnersDir, `${encodeURIComponent(runnerId)}.json`);
|
|
35028
|
+
const writeAtomically = (target, contents) => writeJsonFileAtomically(options.fs, target, contents);
|
|
33512
35029
|
const readDefaultRunnerId = async () => {
|
|
33513
|
-
const
|
|
33514
|
-
|
|
33515
|
-
});
|
|
33516
|
-
if (contents === undefined)
|
|
33517
|
-
return;
|
|
33518
|
-
const parsed = storeSchema.safeParse(parseJson2(contents));
|
|
33519
|
-
return parsed.success ? parsed.data.defaultRunnerId : undefined;
|
|
35030
|
+
const stored = await readJsonFile(options.fs, path, storeSchema2);
|
|
35031
|
+
return stored?.defaultRunnerId;
|
|
33520
35032
|
};
|
|
33521
35033
|
const writeDefaultRunnerId = async (runnerId) => {
|
|
33522
35034
|
await options.fs.mkdir(directory, { recursive: true });
|
|
@@ -33538,15 +35050,7 @@ function makeRunnerStore(options) {
|
|
|
33538
35050
|
},
|
|
33539
35051
|
readDefaultRunnerId,
|
|
33540
35052
|
async readRunners() {
|
|
33541
|
-
const runners = await Promise.all((await readRunnerFileNames()).map(
|
|
33542
|
-
const contents = await options.fs.readFile(join53(runnersDir, name)).catch(() => {
|
|
33543
|
-
return;
|
|
33544
|
-
});
|
|
33545
|
-
if (contents === undefined)
|
|
33546
|
-
return;
|
|
33547
|
-
const parsed = storedRunnerSchema.safeParse(parseJson2(contents));
|
|
33548
|
-
return parsed.success ? parsed.data : undefined;
|
|
33549
|
-
}));
|
|
35053
|
+
const runners = await Promise.all((await readRunnerFileNames()).map((name) => readJsonFile(options.fs, join54(runnersDir, name), storedRunnerSchema)));
|
|
33550
35054
|
return runners.filter((runner) => !!runner).sort((left, right) => left.id.localeCompare(right.id));
|
|
33551
35055
|
},
|
|
33552
35056
|
async rememberLaunch(runner) {
|
|
@@ -33558,13 +35062,13 @@ function makeRunnerStore(options) {
|
|
|
33558
35062
|
await Promise.all(runnerIds.map((runnerId) => options.fs.rm(runnerPath(runnerId), { force: true })));
|
|
33559
35063
|
const names = await readRunnerFileNames();
|
|
33560
35064
|
await Promise.all(names.map(async (name) => {
|
|
33561
|
-
const runnerFile =
|
|
35065
|
+
const runnerFile = join54(runnersDir, name);
|
|
33562
35066
|
const contents = await options.fs.readFile(runnerFile).catch(() => {
|
|
33563
35067
|
return;
|
|
33564
35068
|
});
|
|
33565
35069
|
if (contents === undefined)
|
|
33566
35070
|
return;
|
|
33567
|
-
if (storedRunnerSchema.safeParse(
|
|
35071
|
+
if (storedRunnerSchema.safeParse(parseJson(contents)).success)
|
|
33568
35072
|
return;
|
|
33569
35073
|
await options.fs.rm(runnerFile, { force: true });
|
|
33570
35074
|
}));
|
|
@@ -33736,7 +35240,7 @@ function registerRunnerHighlightSelectorCommand(runner, signals) {
|
|
|
33736
35240
|
}
|
|
33737
35241
|
|
|
33738
35242
|
// src/domains/interactiveRunner/importPackage.ts
|
|
33739
|
-
import { join as
|
|
35243
|
+
import { join as join55 } from "node:path";
|
|
33740
35244
|
|
|
33741
35245
|
// src/core/interactiveRunner/npmDependencies.ts
|
|
33742
35246
|
var sectionsInPrecedenceOrder = ["dependencies", "devDependencies"];
|
|
@@ -33777,7 +35281,7 @@ function readNpmDependencies(packageJsonContent) {
|
|
|
33777
35281
|
// src/domains/interactiveRunner/importPackage.ts
|
|
33778
35282
|
var defaultPackageVersion = "latest";
|
|
33779
35283
|
async function handleRunnerImportPackage(ctx, options, deps) {
|
|
33780
|
-
const content = await deps.readFile(
|
|
35284
|
+
const content = await deps.readFile(join55(deps.cwd, runPackageJsonPath)).catch(() => {
|
|
33781
35285
|
return;
|
|
33782
35286
|
});
|
|
33783
35287
|
if (content === undefined) {
|
|
@@ -34523,7 +36027,8 @@ async function handleRunnerLaunch(ctx, options, deps) {
|
|
|
34523
36027
|
if (envRunnerId && envRunnerId !== launched.value.id) {
|
|
34524
36028
|
ctx.ui.warn(interactiveRunnerMessages.envRunnerIdShadowsLaunch(launched.value.id, envRunnerId));
|
|
34525
36029
|
}
|
|
34526
|
-
|
|
36030
|
+
const runner = launched.value;
|
|
36031
|
+
ctx.ui.output(runner, runner.alreadyRunning ? interactiveRunnerMessages.alreadyRunning(runner.id, runner.url) : interactiveRunnerMessages.launched(runner.id, runner.url));
|
|
34527
36032
|
return;
|
|
34528
36033
|
}
|
|
34529
36034
|
|
|
@@ -34561,7 +36066,8 @@ async function listRunners(ctx, deps) {
|
|
|
34561
36066
|
id: runner.id,
|
|
34562
36067
|
isDefault: runner.id === defaultRunnerId,
|
|
34563
36068
|
launchedHere: heldIds.has(runner.id),
|
|
34564
|
-
runnerName: runner.runnerName
|
|
36069
|
+
runnerName: runner.runnerName,
|
|
36070
|
+
url: runner.url
|
|
34565
36071
|
}));
|
|
34566
36072
|
return {
|
|
34567
36073
|
items: items.sort((left, right) => rank(left) - rank(right) || left.id.localeCompare(right.id)),
|
|
@@ -34718,16 +36224,6 @@ function registerRunnerPromoteSnapshotCommand(runner, signals) {
|
|
|
34718
36224
|
|
|
34719
36225
|
// src/core/interactiveRunner/followTimeout.ts
|
|
34720
36226
|
var defaultFollowTimeoutSeconds = 3600;
|
|
34721
|
-
var followTimeoutSchema = exports_coerce.number().int().positive();
|
|
34722
|
-
function parseFollowTimeout(seconds) {
|
|
34723
|
-
if (seconds === undefined) {
|
|
34724
|
-
return { ok: true, seconds: defaultFollowTimeoutSeconds };
|
|
34725
|
-
}
|
|
34726
|
-
const parsed = followTimeoutSchema.safeParse(seconds);
|
|
34727
|
-
if (!parsed.success)
|
|
34728
|
-
return { error: prettifyError(parsed.error), ok: false };
|
|
34729
|
-
return { ok: true, seconds: parsed.data };
|
|
34730
|
-
}
|
|
34731
36227
|
|
|
34732
36228
|
// src/core/interactiveRunner/journal.ts
|
|
34733
36229
|
function formatJournalLine(entry, options) {
|
|
@@ -34857,12 +36353,12 @@ function createUnreachableBudget(pollIntervalMs) {
|
|
|
34857
36353
|
}
|
|
34858
36354
|
|
|
34859
36355
|
// src/domains/interactiveRunner/events.ts
|
|
34860
|
-
var
|
|
36356
|
+
var pollIntervalMs3 = 1000;
|
|
34861
36357
|
async function handleRunnerEvents(ctx, options, deps) {
|
|
34862
36358
|
const parsed = parseEventsOptions(options);
|
|
34863
36359
|
if (!parsed.ok)
|
|
34864
36360
|
return { error: parsed.error, exitCode: exitCodes.invalidArgs };
|
|
34865
|
-
const timeout = parseFollowTimeout(options.timeout);
|
|
36361
|
+
const timeout = parseFollowTimeout(options.timeout, defaultFollowTimeoutSeconds);
|
|
34866
36362
|
if (!timeout.ok) {
|
|
34867
36363
|
return { error: timeout.error, exitCode: exitCodes.invalidArgs };
|
|
34868
36364
|
}
|
|
@@ -34875,8 +36371,8 @@ async function handleRunnerEvents(ctx, options, deps) {
|
|
|
34875
36371
|
ctx.ui.warn(interactiveRunnerMessages.unknownStream(parsed.value.stream, known));
|
|
34876
36372
|
}
|
|
34877
36373
|
const read = createJournalCursor(ctx, resolved.runnerId, parsed.value);
|
|
34878
|
-
const unreachable = createUnreachableBudget(
|
|
34879
|
-
const maxPolls = Math.max(1, Math.ceil(timeout.seconds * 1000 /
|
|
36374
|
+
const unreachable = createUnreachableBudget(pollIntervalMs3);
|
|
36375
|
+
const maxPolls = Math.max(1, Math.ceil(timeout.seconds * 1000 / pollIntervalMs3));
|
|
34880
36376
|
for (let poll = 1;; poll++) {
|
|
34881
36377
|
const window = await read();
|
|
34882
36378
|
if (window.type === "failed")
|
|
@@ -34902,7 +36398,7 @@ async function handleRunnerEvents(ctx, options, deps) {
|
|
|
34902
36398
|
exitCode: exitCodes.timeout
|
|
34903
36399
|
};
|
|
34904
36400
|
}
|
|
34905
|
-
await deps.sleep(
|
|
36401
|
+
await deps.sleep(pollIntervalMs3);
|
|
34906
36402
|
}
|
|
34907
36403
|
}
|
|
34908
36404
|
|
|
@@ -34967,8 +36463,8 @@ function createFollowPrinters(ctx, options) {
|
|
|
34967
36463
|
}
|
|
34968
36464
|
|
|
34969
36465
|
// src/domains/interactiveRunner/followRun.ts
|
|
34970
|
-
var
|
|
34971
|
-
function
|
|
36466
|
+
var pollIntervalMs4 = 1000;
|
|
36467
|
+
function reportSettlement2(ctx, settlement) {
|
|
34972
36468
|
if (settlement.type === "passed") {
|
|
34973
36469
|
ctx.ui.success(interactiveRunnerMessages.runPassed);
|
|
34974
36470
|
return;
|
|
@@ -34984,7 +36480,7 @@ async function followRun(ctx, options, deps) {
|
|
|
34984
36480
|
runId: options.runId,
|
|
34985
36481
|
stream: "run-status"
|
|
34986
36482
|
});
|
|
34987
|
-
const unreachable = createUnreachableBudget(
|
|
36483
|
+
const unreachable = createUnreachableBudget(pollIntervalMs4);
|
|
34988
36484
|
const printAll = async () => {
|
|
34989
36485
|
for (const print of printers) {
|
|
34990
36486
|
const window = await print();
|
|
@@ -35003,7 +36499,7 @@ async function followRun(ctx, options, deps) {
|
|
|
35003
36499
|
progressReported = true;
|
|
35004
36500
|
ctx.ui.stream(entry, interactiveRunnerMessages.runInProgress);
|
|
35005
36501
|
};
|
|
35006
|
-
const maxPolls = Math.max(1, Math.ceil(options.timeoutSeconds * 1000 /
|
|
36502
|
+
const maxPolls = Math.max(1, Math.ceil(options.timeoutSeconds * 1000 / pollIntervalMs4));
|
|
35007
36503
|
for (let poll = 1;; poll++) {
|
|
35008
36504
|
const interrupted = await printAll();
|
|
35009
36505
|
if (interrupted?.type === "failed")
|
|
@@ -35022,7 +36518,7 @@ async function followRun(ctx, options, deps) {
|
|
|
35022
36518
|
if (await printAll() !== undefined) {
|
|
35023
36519
|
ctx.ui.warn(interactiveRunnerMessages.followEndCutShort);
|
|
35024
36520
|
}
|
|
35025
|
-
return
|
|
36521
|
+
return reportSettlement2(ctx, settlement);
|
|
35026
36522
|
}
|
|
35027
36523
|
}
|
|
35028
36524
|
if (poll >= maxPolls) {
|
|
@@ -35031,7 +36527,7 @@ async function followRun(ctx, options, deps) {
|
|
|
35031
36527
|
exitCode: exitCodes.timeout
|
|
35032
36528
|
};
|
|
35033
36529
|
}
|
|
35034
|
-
await deps.sleep(
|
|
36530
|
+
await deps.sleep(pollIntervalMs4);
|
|
35035
36531
|
}
|
|
35036
36532
|
}
|
|
35037
36533
|
|
|
@@ -35311,7 +36807,7 @@ async function finish(sent, fileSync, options, deps) {
|
|
|
35311
36807
|
|
|
35312
36808
|
// src/domains/interactiveRunner/runFlow.ts
|
|
35313
36809
|
async function handleRunnerRun(ctx, options, deps) {
|
|
35314
|
-
const timeout = parseFollowTimeout(options.timeout);
|
|
36810
|
+
const timeout = parseFollowTimeout(options.timeout, defaultFollowTimeoutSeconds);
|
|
35315
36811
|
if (!timeout.ok) {
|
|
35316
36812
|
return { error: timeout.error, exitCode: exitCodes.invalidArgs };
|
|
35317
36813
|
}
|
|
@@ -35422,6 +36918,7 @@ function createProgram({
|
|
|
35422
36918
|
const program = new Command2().name("qawolf").description("Run QA Wolf flows locally").version(package_default.version).option("--verbose", "Enable debug logging to stderr").option("--json", "Output as JSON").option("--agent", "Output for agent consumption").exitOverride((err) => {
|
|
35423
36919
|
exit(err.exitCode === 0 ? exitCodes.success : exitCodes.invalidArgs);
|
|
35424
36920
|
});
|
|
36921
|
+
registerAgentCommand(program, signals);
|
|
35425
36922
|
registerAuthCommand(program, signals);
|
|
35426
36923
|
registerDoctorCommand(program, signals);
|
|
35427
36924
|
registerFlowsCommand(program, signals);
|
|
@@ -35442,4 +36939,4 @@ createProgram({ signals }).parseAsync().catch(() => {
|
|
|
35442
36939
|
process.exitCode = 1;
|
|
35443
36940
|
}).finally(() => exitWhenIdle(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
35444
36941
|
|
|
35445
|
-
//# debugId=
|
|
36942
|
+
//# debugId=65A771FAB553A0D964756E2164756E21
|