@qawolf/cli 1.24.0 → 1.25.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 +1935 -582
- package/dist/runner-sdk.js +567 -72
- package/package.json +1 -1
- package/skills/qawolf-cli/SKILL.md +2 -1
package/dist/cli.js
CHANGED
|
@@ -8390,11 +8390,82 @@ 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
|
+
|
|
8393
8398
|
// src/core/formatSeconds.ts
|
|
8394
8399
|
function formatSeconds(ms) {
|
|
8395
8400
|
return `${Math.round(ms / 1000)}s`;
|
|
8396
8401
|
}
|
|
8397
8402
|
|
|
8403
|
+
// src/core/messages/authErrors.ts
|
|
8404
|
+
var authErrorMessages = {
|
|
8405
|
+
identity: {
|
|
8406
|
+
invalidOrUnauthorized: "API key is invalid or unauthorized",
|
|
8407
|
+
unexpectedFormat: "Could not verify API key: unexpected response format",
|
|
8408
|
+
couldNotVerify: (detail, status) => `Could not verify API key: ${detail || `HTTP ${status}`}`,
|
|
8409
|
+
couldNotVerifyNetwork: (cause) => `Could not verify API key: ${cause}`,
|
|
8410
|
+
timedOut: (timeoutMs) => `Could not verify API key: the QA Wolf API did not answer within ${formatSeconds(timeoutMs)}.`
|
|
8411
|
+
},
|
|
8412
|
+
request: {
|
|
8413
|
+
rejected401: (noun) => `QA Wolf API rejected the${noun ? ` ${noun}` : ""} request (HTTP 401). Check your API key.`,
|
|
8414
|
+
rejected402: (noun) => `QA Wolf API refused the${noun ? ` ${noun}` : ""} request (HTTP 402): billing prevented it.`,
|
|
8415
|
+
rejected403: (noun) => `QA Wolf API rejected the${noun ? ` ${noun}` : ""} request (HTTP 403). Check that your API key has access to this environment.`,
|
|
8416
|
+
notFound404: (noun) => `QA Wolf API could not find ${noun ? `${noun} for that environment` : "that environment"} (HTTP 404). Check the --env value.`,
|
|
8417
|
+
failedWithStatus: (status, noun) => `QA Wolf API${noun ? ` ${noun}` : ""} request failed (HTTP ${status}).`,
|
|
8418
|
+
networkUnreachable: (baseUrl, noun) => `Could not reach the QA Wolf API at ${baseUrl}${noun ? ` to fetch ${noun}` : ""}. Check your network connection and QAWOLF_HOST_URL.`,
|
|
8419
|
+
timedOut: (timeoutMs, noun) => `The QA Wolf API${noun ? ` ${noun}` : ""} request timed out after ${formatSeconds(timeoutMs)}. The work may still be finishing on the platform.`,
|
|
8420
|
+
unexpectedResponse: (noun) => `Unexpected${noun ? ` ${noun}` : ""} response from the QA Wolf API.`
|
|
8421
|
+
},
|
|
8422
|
+
workos: {
|
|
8423
|
+
unexpectedResponse: "WorkOS returned an unexpected response",
|
|
8424
|
+
unexpectedResponseWithStatus: (status) => `WorkOS returned an unexpected response (HTTP ${status})`,
|
|
8425
|
+
unreachable: (detail) => `Could not reach WorkOS: ${detail}`,
|
|
8426
|
+
redirected: "WorkOS answered with a redirect, which the CLI does not follow for a sign-in request",
|
|
8427
|
+
noClientForSession: "This session names no WorkOS client"
|
|
8428
|
+
},
|
|
8429
|
+
bundle: {
|
|
8430
|
+
linkExpired: "The flow bundle download link has expired. Please run `qawolf flows pull` again to refresh.",
|
|
8431
|
+
failedWithStatus: (status) => `Could not download the flow bundle (HTTP ${status}).`,
|
|
8432
|
+
networkUnreachable: "Could not reach the flow bundle storage. Check your network connection and try again.",
|
|
8433
|
+
timedOut: (timeoutMs) => `Downloading the flow bundle stalled — no data arrived for ${formatSeconds(timeoutMs)}. Please try again.`,
|
|
8434
|
+
malformed: "The flow bundle download was malformed. Please run `qawolf flows pull` again."
|
|
8435
|
+
}
|
|
8436
|
+
};
|
|
8437
|
+
|
|
8438
|
+
// src/core/messages/whoami.ts
|
|
8439
|
+
var whoamiMessages = {
|
|
8440
|
+
source: (source) => `Source: ${source}`,
|
|
8441
|
+
authFailed: (source, error) => `Authentication failed (source: ${source}): ${error}`,
|
|
8442
|
+
authenticatedAs: (teamName, source) => `Authenticated as ${teamName} (source: ${source})`,
|
|
8443
|
+
teamNote: (input) => [
|
|
8444
|
+
`Workspace: ${input.team.name}`,
|
|
8445
|
+
`ID: ${input.team.id}`,
|
|
8446
|
+
input.team.slug ? `Slug: ${input.team.slug}` : undefined,
|
|
8447
|
+
input.teamUrl ? `URL: ${input.teamUrl}` : undefined,
|
|
8448
|
+
`Source: ${input.source}`
|
|
8449
|
+
].filter((line) => Boolean(line)).join(`
|
|
8450
|
+
`),
|
|
8451
|
+
organizationNote: (input) => [
|
|
8452
|
+
`Organization: ${input.organization.name}`,
|
|
8453
|
+
`ID: ${input.organization.id}`,
|
|
8454
|
+
`Source: ${input.source}`
|
|
8455
|
+
].join(`
|
|
8456
|
+
`),
|
|
8457
|
+
activeWorkspace: (workspaceId, found) => found ? `${found.workspace} (${found.organization})` : `${workspaceId} — no longer in reach; run 'qawolf auth switch'`,
|
|
8458
|
+
userNote: (input) => [
|
|
8459
|
+
`User: ${input.user.email}`,
|
|
8460
|
+
`ID: ${input.user.id}`,
|
|
8461
|
+
`Organization: ${input.organization.name}`,
|
|
8462
|
+
input.activeWorkspace ? `Workspace: ${input.activeWorkspace}` : undefined,
|
|
8463
|
+
input.organizations.length > 0 ? `Workspaces: ${input.organizations.map((o) => `${o.name}: ${o.workspaces.map((w) => w.name).join(", ")}`).join(" | ")}` : undefined,
|
|
8464
|
+
`Source: ${input.source}`
|
|
8465
|
+
].filter((line) => Boolean(line)).join(`
|
|
8466
|
+
`)
|
|
8467
|
+
};
|
|
8468
|
+
|
|
8398
8469
|
// src/core/messages/auth.ts
|
|
8399
8470
|
var authMessages = {
|
|
8400
8471
|
title: "QA Wolf Authentication",
|
|
@@ -8412,7 +8483,47 @@ var authMessages = {
|
|
|
8412
8483
|
whoamiFailed: "Not authenticated",
|
|
8413
8484
|
login: {
|
|
8414
8485
|
nonInteractive: "auth login requires an interactive terminal. Set the QAWOLF_API_KEY environment variable for CI authentication.",
|
|
8415
|
-
reAuthPrompt: "You are already authenticated. Re-authenticate?"
|
|
8486
|
+
reAuthPrompt: "You are already authenticated. Re-authenticate?",
|
|
8487
|
+
chooseMethod: "How do you want to sign in?",
|
|
8488
|
+
methodBrowser: "Browser",
|
|
8489
|
+
methodBrowserHint: "Sign in with your QA Wolf account",
|
|
8490
|
+
methodApiKey: "API key",
|
|
8491
|
+
methodApiKeyHint: "Paste a team key — needed for flows pull and flows run",
|
|
8492
|
+
apiKeyPrecedence: {
|
|
8493
|
+
env: "QAWOLF_API_KEY is set, and an API key takes precedence over a browser session. Commands continue to use that key until you unset the variable.",
|
|
8494
|
+
stored: "A stored API key takes precedence over a browser session. Commands continue to use that key until you run 'qawolf auth logout' and sign in again."
|
|
8495
|
+
}
|
|
8496
|
+
},
|
|
8497
|
+
device: {
|
|
8498
|
+
unavailable: "This QA Wolf deployment does not offer browser sign-in. Run 'qawolf auth login' again and choose 'API key'.",
|
|
8499
|
+
configUnreachable: "Could not ask this QA Wolf deployment whether it offers browser sign-in. Check your connection, then try again.",
|
|
8500
|
+
confirmCode: (userCode) => `Your code is ${userCode}`,
|
|
8501
|
+
visitUrl: (url) => `Confirm it at ${url}`,
|
|
8502
|
+
visitUrlPlain: (url) => `Or go to ${url} and enter the code`,
|
|
8503
|
+
openFailed: (url) => `Could not open a browser automatically. Open ${url} yourself to continue.`,
|
|
8504
|
+
waiting: "Waiting for you to finish in the browser",
|
|
8505
|
+
signedIn: (email) => `Signed in as ${email}.`,
|
|
8506
|
+
failed: {
|
|
8507
|
+
"access-denied": "The sign-in request was rejected.",
|
|
8508
|
+
expired: "The sign-in request expired. Run 'qawolf auth login' to retry.",
|
|
8509
|
+
timeout: "The sign-in request timed out. Run 'qawolf auth login' to retry.",
|
|
8510
|
+
network: "Could not reach WorkOS to complete sign-in.",
|
|
8511
|
+
unavailable: "Could not start browser sign-in.",
|
|
8512
|
+
cancelled: "Sign-in cancelled."
|
|
8513
|
+
}
|
|
8514
|
+
},
|
|
8515
|
+
workspace: {
|
|
8516
|
+
chooseOrganization: "Which organization do you want to work in?",
|
|
8517
|
+
choose: "Which workspace do you want to use?",
|
|
8518
|
+
workspaceCount: (count) => pluralize(count, "workspace"),
|
|
8519
|
+
working: (organization, workspace) => `Working in ${workspace} (${organization}).`,
|
|
8520
|
+
none: "This account reaches no organizations yet.",
|
|
8521
|
+
cancelled: "Workspace not changed.",
|
|
8522
|
+
notSignedIn: "Workspace switching needs a browser sign-in. Run 'qawolf auth login' and choose Browser.",
|
|
8523
|
+
sessionExpired: "Your session could not be renewed. Run 'qawolf auth login' to sign in again.",
|
|
8524
|
+
nonInteractive: "auth switch needs an interactive terminal, or set QAWOLF_WORKSPACE to name a workspace.",
|
|
8525
|
+
sessionChanged: "The stored sign-in changed while you made your choice. Run the command again.",
|
|
8526
|
+
saveFailed: (detail) => `Could not save the workspace choice: ${detail}`
|
|
8416
8527
|
},
|
|
8417
8528
|
logout: {
|
|
8418
8529
|
title: "Log Out",
|
|
@@ -8424,58 +8535,8 @@ var authMessages = {
|
|
|
8424
8535
|
success: "Logged out successfully.",
|
|
8425
8536
|
cancelled: "Logout cancelled."
|
|
8426
8537
|
},
|
|
8427
|
-
errors:
|
|
8428
|
-
|
|
8429
|
-
invalidOrUnauthorized: "API key is invalid or unauthorized",
|
|
8430
|
-
unexpectedFormat: "Could not verify API key: unexpected response format",
|
|
8431
|
-
couldNotVerify: (detail, status) => `Could not verify API key: ${detail || `HTTP ${status}`}`,
|
|
8432
|
-
couldNotVerifyNetwork: (cause) => `Could not verify API key: ${cause}`,
|
|
8433
|
-
timedOut: (timeoutMs) => `Could not verify API key: the QA Wolf API did not answer within ${formatSeconds(timeoutMs)}.`
|
|
8434
|
-
},
|
|
8435
|
-
request: {
|
|
8436
|
-
rejected401: (noun) => `QA Wolf API rejected the${noun ? ` ${noun}` : ""} request (HTTP 401). Check your API key.`,
|
|
8437
|
-
rejected402: (noun) => `QA Wolf API refused the${noun ? ` ${noun}` : ""} request (HTTP 402): billing prevented it.`,
|
|
8438
|
-
rejected403: (noun) => `QA Wolf API rejected the${noun ? ` ${noun}` : ""} request (HTTP 403). Check that your API key has access to this environment.`,
|
|
8439
|
-
notFound404: (noun) => `QA Wolf API could not find ${noun ? `${noun} for that environment` : "that environment"} (HTTP 404). Check the --env value.`,
|
|
8440
|
-
failedWithStatus: (status, noun) => `QA Wolf API${noun ? ` ${noun}` : ""} request failed (HTTP ${status}).`,
|
|
8441
|
-
networkUnreachable: (baseUrl, noun) => `Could not reach the QA Wolf API at ${baseUrl}${noun ? ` to fetch ${noun}` : ""}. Check your network connection and QAWOLF_HOST_URL.`,
|
|
8442
|
-
timedOut: (timeoutMs, noun) => `The QA Wolf API${noun ? ` ${noun}` : ""} request timed out after ${formatSeconds(timeoutMs)}. The work may still be finishing on the platform.`,
|
|
8443
|
-
unexpectedResponse: (noun) => `Unexpected${noun ? ` ${noun}` : ""} response from the QA Wolf API.`
|
|
8444
|
-
},
|
|
8445
|
-
bundle: {
|
|
8446
|
-
linkExpired: "The flow bundle download link has expired. Please run `qawolf flows pull` again to refresh.",
|
|
8447
|
-
failedWithStatus: (status) => `Could not download the flow bundle (HTTP ${status}).`,
|
|
8448
|
-
networkUnreachable: "Could not reach the flow bundle storage. Check your network connection and try again.",
|
|
8449
|
-
timedOut: (timeoutMs) => `Downloading the flow bundle stalled — no data arrived for ${formatSeconds(timeoutMs)}. Please try again.`,
|
|
8450
|
-
malformed: "The flow bundle download was malformed. Please run `qawolf flows pull` again."
|
|
8451
|
-
}
|
|
8452
|
-
},
|
|
8453
|
-
whoami: {
|
|
8454
|
-
source: (source) => `Source: ${source}`,
|
|
8455
|
-
authFailed: (source, error) => `Authentication failed (source: ${source}): ${error}`,
|
|
8456
|
-
authenticatedAs: (teamName, source) => `Authenticated as ${teamName} (source: ${source})`,
|
|
8457
|
-
teamNote: (input) => [
|
|
8458
|
-
`Team: ${input.team.name}`,
|
|
8459
|
-
`ID: ${input.team.id}`,
|
|
8460
|
-
input.team.slug ? `Slug: ${input.team.slug}` : undefined,
|
|
8461
|
-
input.teamUrl ? `URL: ${input.teamUrl}` : undefined,
|
|
8462
|
-
`Source: ${input.source}`
|
|
8463
|
-
].filter((line) => Boolean(line)).join(`
|
|
8464
|
-
`),
|
|
8465
|
-
organizationNote: (input) => [
|
|
8466
|
-
`Organization: ${input.organization.name}`,
|
|
8467
|
-
`ID: ${input.organization.id}`,
|
|
8468
|
-
`Source: ${input.source}`
|
|
8469
|
-
].join(`
|
|
8470
|
-
`),
|
|
8471
|
-
userNote: (input) => [
|
|
8472
|
-
`User: ${input.user.email}`,
|
|
8473
|
-
`ID: ${input.user.id}`,
|
|
8474
|
-
`Organization: ${input.organization.name}`,
|
|
8475
|
-
`Source: ${input.source}`
|
|
8476
|
-
].join(`
|
|
8477
|
-
`)
|
|
8478
|
-
}
|
|
8538
|
+
errors: authErrorMessages,
|
|
8539
|
+
whoami: whoamiMessages
|
|
8479
8540
|
};
|
|
8480
8541
|
// src/core/messages/toolNotFound.ts
|
|
8481
8542
|
var installRemedy = "Run `qawolf install` to install the runtime dependencies.";
|
|
@@ -8568,11 +8629,6 @@ var environmentsMessages = {
|
|
|
8568
8629
|
usingPulledEnv: (env) => `Could not reach the platform to resolve environment ${env}; using the copy pulled into .qawolf/${env}.`,
|
|
8569
8630
|
tooManyPages: (pages) => `Stopped listing environments after ${pages} pages. Pass --env explicitly.`
|
|
8570
8631
|
};
|
|
8571
|
-
// src/core/pluralize.ts
|
|
8572
|
-
function pluralize(count, singular, plural = `${singular}s`) {
|
|
8573
|
-
return `${String(count)} ${count === 1 ? singular : plural}`;
|
|
8574
|
-
}
|
|
8575
|
-
|
|
8576
8632
|
// src/core/messages/flows.ts
|
|
8577
8633
|
var flowsMessages = {
|
|
8578
8634
|
title: "Flows",
|
|
@@ -9161,43 +9217,30 @@ function resolveHostUrl(env) {
|
|
|
9161
9217
|
}
|
|
9162
9218
|
|
|
9163
9219
|
// src/domains/auth/resolve.ts
|
|
9164
|
-
import { Entry as
|
|
9165
|
-
|
|
9166
|
-
// src/domains/auth/store/delete.ts
|
|
9167
|
-
import { join as join2 } from "node:path";
|
|
9168
|
-
import { Entry } from "@napi-rs/keyring";
|
|
9169
|
-
|
|
9170
|
-
// src/domains/auth/store/constants.ts
|
|
9171
|
-
var service = "qawolf-cli";
|
|
9172
|
-
var account = "api-key";
|
|
9173
|
-
var credentialsFile = "credentials.json";
|
|
9220
|
+
import { Entry as Entry5 } from "@napi-rs/keyring";
|
|
9174
9221
|
|
|
9175
|
-
// src/
|
|
9176
|
-
function
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
return
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
async function deleteFromFile(configDir, fs) {
|
|
9222
|
+
// src/core/deviceAuth/tokenExpiry.ts
|
|
9223
|
+
function readAccessTokenExpiry(accessToken) {
|
|
9224
|
+
const segments = accessToken.split(".");
|
|
9225
|
+
if (segments.length !== 3)
|
|
9226
|
+
return;
|
|
9227
|
+
const [, payload] = segments;
|
|
9228
|
+
if (!payload)
|
|
9229
|
+
return;
|
|
9230
|
+
let claims;
|
|
9185
9231
|
try {
|
|
9186
|
-
|
|
9187
|
-
return "deleted";
|
|
9232
|
+
claims = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
9188
9233
|
} catch {
|
|
9189
|
-
return
|
|
9234
|
+
return;
|
|
9190
9235
|
}
|
|
9236
|
+
if (typeof claims !== "object" || claims === null)
|
|
9237
|
+
return;
|
|
9238
|
+
const exp = claims.exp;
|
|
9239
|
+
if (typeof exp !== "number" || !Number.isFinite(exp))
|
|
9240
|
+
return;
|
|
9241
|
+
const expiresAtMs = exp * 1000;
|
|
9242
|
+
return Number.isFinite(expiresAtMs) ? expiresAtMs : undefined;
|
|
9191
9243
|
}
|
|
9192
|
-
async function deleteApiKey(configDir, fs) {
|
|
9193
|
-
const [keychain, file] = await Promise.all([
|
|
9194
|
-
Promise.resolve(deleteFromKeychain()),
|
|
9195
|
-
deleteFromFile(configDir, fs)
|
|
9196
|
-
]);
|
|
9197
|
-
return { keychain, file };
|
|
9198
|
-
}
|
|
9199
|
-
// src/domains/auth/store/load.ts
|
|
9200
|
-
import { join as join3 } from "node:path";
|
|
9201
9244
|
|
|
9202
9245
|
// node_modules/zod/v4/core/core.js
|
|
9203
9246
|
var _a;
|
|
@@ -14424,10 +14467,229 @@ function date4(params) {
|
|
|
14424
14467
|
|
|
14425
14468
|
// node_modules/zod/v4/classic/external.js
|
|
14426
14469
|
config(en_default());
|
|
14470
|
+
// src/shell/workos/types.ts
|
|
14471
|
+
var defaultWorkosBaseUrl = "https://api.workos.com";
|
|
14472
|
+
var defaultIntervalSec = 5;
|
|
14473
|
+
var deviceAuthorizationBody = object({
|
|
14474
|
+
device_code: string2().min(1),
|
|
14475
|
+
user_code: string2().min(1),
|
|
14476
|
+
verification_uri: string2().min(1),
|
|
14477
|
+
verification_uri_complete: string2().min(1).optional(),
|
|
14478
|
+
expires_in: number2().int().positive(),
|
|
14479
|
+
interval: number2().int().positive().optional()
|
|
14480
|
+
});
|
|
14481
|
+
var deviceTokenBody = object({
|
|
14482
|
+
access_token: string2().min(1),
|
|
14483
|
+
refresh_token: string2().min(1),
|
|
14484
|
+
user: object({ email: string2().min(1) }),
|
|
14485
|
+
organization_id: string2().min(1).optional()
|
|
14486
|
+
});
|
|
14487
|
+
var oauthErrorBody = object({
|
|
14488
|
+
error: string2().min(1),
|
|
14489
|
+
error_description: string2().min(1).optional()
|
|
14490
|
+
});
|
|
14491
|
+
var authenticationErrorBody = object({
|
|
14492
|
+
code: string2().min(1),
|
|
14493
|
+
message: string2().min(1).optional()
|
|
14494
|
+
});
|
|
14495
|
+
|
|
14496
|
+
// src/shell/workos/send.ts
|
|
14497
|
+
var timeoutMs = 15000;
|
|
14498
|
+
var unexpectedResponse = authErrorMessages.workos.unexpectedResponse;
|
|
14499
|
+
function isTransientStatus(status) {
|
|
14500
|
+
return status >= 500 || status === 429 || status === 408;
|
|
14501
|
+
}
|
|
14502
|
+
async function sendWorkosRequest(url, init, fetchFn) {
|
|
14503
|
+
let response;
|
|
14504
|
+
try {
|
|
14505
|
+
response = await fetchFn(url, {
|
|
14506
|
+
method: "POST",
|
|
14507
|
+
headers: init.headers,
|
|
14508
|
+
body: init.body,
|
|
14509
|
+
redirect: "manual",
|
|
14510
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
14511
|
+
});
|
|
14512
|
+
} catch (err) {
|
|
14513
|
+
return {
|
|
14514
|
+
kind: "failure",
|
|
14515
|
+
detail: authErrorMessages.workos.unreachable(errorMessage(err)),
|
|
14516
|
+
retryable: true
|
|
14517
|
+
};
|
|
14518
|
+
}
|
|
14519
|
+
if (response.status >= 300 && response.status < 400) {
|
|
14520
|
+
return {
|
|
14521
|
+
kind: "failure",
|
|
14522
|
+
detail: authErrorMessages.workos.redirected,
|
|
14523
|
+
retryable: false
|
|
14524
|
+
};
|
|
14525
|
+
}
|
|
14526
|
+
let json;
|
|
14527
|
+
try {
|
|
14528
|
+
json = await response.json();
|
|
14529
|
+
} catch {
|
|
14530
|
+
return {
|
|
14531
|
+
kind: "failure",
|
|
14532
|
+
detail: authErrorMessages.workos.unexpectedResponseWithStatus(response.status),
|
|
14533
|
+
retryable: response.ok || isTransientStatus(response.status)
|
|
14534
|
+
};
|
|
14535
|
+
}
|
|
14536
|
+
if (response.ok)
|
|
14537
|
+
return { kind: "json", json };
|
|
14538
|
+
if (isTransientStatus(response.status)) {
|
|
14539
|
+
return {
|
|
14540
|
+
kind: "failure",
|
|
14541
|
+
detail: authErrorMessages.workos.unexpectedResponseWithStatus(response.status),
|
|
14542
|
+
retryable: true
|
|
14543
|
+
};
|
|
14544
|
+
}
|
|
14545
|
+
const parsed = oauthErrorBody.safeParse(json);
|
|
14546
|
+
if (parsed.success) {
|
|
14547
|
+
return {
|
|
14548
|
+
kind: "oauth-error",
|
|
14549
|
+
code: parsed.data.error,
|
|
14550
|
+
description: parsed.data.error_description
|
|
14551
|
+
};
|
|
14552
|
+
}
|
|
14553
|
+
const authError = authenticationErrorBody.safeParse(json);
|
|
14554
|
+
if (authError.success) {
|
|
14555
|
+
return {
|
|
14556
|
+
kind: "oauth-error",
|
|
14557
|
+
code: authError.data.code,
|
|
14558
|
+
description: authError.data.message
|
|
14559
|
+
};
|
|
14560
|
+
}
|
|
14561
|
+
return {
|
|
14562
|
+
kind: "failure",
|
|
14563
|
+
detail: authErrorMessages.workos.unexpectedResponseWithStatus(response.status),
|
|
14564
|
+
retryable: false
|
|
14565
|
+
};
|
|
14566
|
+
}
|
|
14567
|
+
|
|
14568
|
+
// src/shell/workos/refreshAccessToken.ts
|
|
14569
|
+
async function refreshAccessToken(refreshToken, organizationId, deps) {
|
|
14570
|
+
const params = new URLSearchParams({
|
|
14571
|
+
grant_type: "refresh_token",
|
|
14572
|
+
refresh_token: refreshToken,
|
|
14573
|
+
client_id: deps.clientId
|
|
14574
|
+
});
|
|
14575
|
+
if (organizationId)
|
|
14576
|
+
params.set("organization_id", organizationId);
|
|
14577
|
+
const outcome = await sendWorkosRequest(`${deps.baseUrl}/user_management/authenticate`, {
|
|
14578
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
14579
|
+
body: params.toString()
|
|
14580
|
+
}, deps.fetch);
|
|
14581
|
+
if (outcome.kind === "failure") {
|
|
14582
|
+
return { ok: false, error: outcome.detail, retryable: outcome.retryable };
|
|
14583
|
+
}
|
|
14584
|
+
if (outcome.kind === "oauth-error") {
|
|
14585
|
+
return {
|
|
14586
|
+
ok: false,
|
|
14587
|
+
error: outcome.description ?? outcome.code,
|
|
14588
|
+
retryable: false
|
|
14589
|
+
};
|
|
14590
|
+
}
|
|
14591
|
+
const parsed = deviceTokenBody.safeParse(outcome.json);
|
|
14592
|
+
if (!parsed.success) {
|
|
14593
|
+
return { ok: false, error: unexpectedResponse, retryable: false };
|
|
14594
|
+
}
|
|
14595
|
+
return {
|
|
14596
|
+
ok: true,
|
|
14597
|
+
value: {
|
|
14598
|
+
accessToken: parsed.data.access_token,
|
|
14599
|
+
refreshToken: parsed.data.refresh_token,
|
|
14600
|
+
expiresAt: readAccessTokenExpiry(parsed.data.access_token),
|
|
14601
|
+
email: parsed.data.user.email,
|
|
14602
|
+
organizationId: parsed.data.organization_id
|
|
14603
|
+
}
|
|
14604
|
+
};
|
|
14605
|
+
}
|
|
14606
|
+
|
|
14607
|
+
// src/shell/workos/config.ts
|
|
14608
|
+
function resolveWorkosConfig(publishedClientId) {
|
|
14609
|
+
const clientId = publishedClientId?.trim();
|
|
14610
|
+
if (!clientId)
|
|
14611
|
+
return { configured: false };
|
|
14612
|
+
return { configured: true, clientId, baseUrl: defaultWorkosBaseUrl };
|
|
14613
|
+
}
|
|
14614
|
+
|
|
14615
|
+
// src/domains/auth/store/delete.ts
|
|
14616
|
+
import { join as join2 } from "node:path";
|
|
14617
|
+
import { Entry } from "@napi-rs/keyring";
|
|
14618
|
+
|
|
14619
|
+
// src/domains/auth/store/constants.ts
|
|
14620
|
+
var service = "qawolf-cli";
|
|
14621
|
+
var account = "api-key";
|
|
14622
|
+
var credentialsFile = "credentials.json";
|
|
14623
|
+
var tokensAccount = "oauth-tokens";
|
|
14624
|
+
var tokensFile = "tokens.json";
|
|
14625
|
+
|
|
14626
|
+
// src/domains/auth/store/delete.ts
|
|
14627
|
+
function deleteFromKeychain() {
|
|
14628
|
+
try {
|
|
14629
|
+
new Entry(service, account).deletePassword();
|
|
14630
|
+
return "deleted";
|
|
14631
|
+
} catch {
|
|
14632
|
+
return "unavailable";
|
|
14633
|
+
}
|
|
14634
|
+
}
|
|
14635
|
+
async function deleteFromFile(configDir, fs) {
|
|
14636
|
+
try {
|
|
14637
|
+
await fs.unlink(join2(configDir, credentialsFile));
|
|
14638
|
+
return "deleted";
|
|
14639
|
+
} catch (err) {
|
|
14640
|
+
if (isNoEntError(err))
|
|
14641
|
+
return "not-found";
|
|
14642
|
+
throw err;
|
|
14643
|
+
}
|
|
14644
|
+
}
|
|
14645
|
+
async function deleteApiKey(configDir, fs) {
|
|
14646
|
+
const [keychain, file] = await Promise.all([
|
|
14647
|
+
Promise.resolve(deleteFromKeychain()),
|
|
14648
|
+
deleteFromFile(configDir, fs)
|
|
14649
|
+
]);
|
|
14650
|
+
return { keychain, file };
|
|
14651
|
+
}
|
|
14652
|
+
// src/domains/auth/store/hasStoredCredentials.ts
|
|
14653
|
+
import { join as join3 } from "node:path";
|
|
14654
|
+
import { Entry as Entry2 } from "@napi-rs/keyring";
|
|
14655
|
+
async function fileExists(path, fs) {
|
|
14656
|
+
try {
|
|
14657
|
+
await fs.readFile(path);
|
|
14658
|
+
return true;
|
|
14659
|
+
} catch (err) {
|
|
14660
|
+
return !isNoEntError(err);
|
|
14661
|
+
}
|
|
14662
|
+
}
|
|
14663
|
+
function keychainHolds(entryAccount) {
|
|
14664
|
+
try {
|
|
14665
|
+
return Boolean(new Entry2(service, entryAccount).getPassword());
|
|
14666
|
+
} catch {
|
|
14667
|
+
return false;
|
|
14668
|
+
}
|
|
14669
|
+
}
|
|
14670
|
+
async function hasStoredCredentials(configDir, fs) {
|
|
14671
|
+
const [apiKeyFile, tokenFile] = await Promise.all([
|
|
14672
|
+
fileExists(join3(configDir, credentialsFile), fs),
|
|
14673
|
+
fileExists(join3(configDir, tokensFile), fs)
|
|
14674
|
+
]);
|
|
14675
|
+
return apiKeyFile || tokenFile || keychainHolds(account) || keychainHolds(tokensAccount);
|
|
14676
|
+
}
|
|
14677
|
+
// src/domains/auth/store/load.ts
|
|
14678
|
+
import { join as join4 } from "node:path";
|
|
14679
|
+
|
|
14427
14680
|
// src/domains/auth/store/types.ts
|
|
14428
14681
|
var credentialsFileSchema = object({
|
|
14429
14682
|
apiKey: string2().min(1)
|
|
14430
14683
|
});
|
|
14684
|
+
var oauthTokensSchema = object({
|
|
14685
|
+
accessToken: string2().min(1),
|
|
14686
|
+
refreshToken: string2().min(1),
|
|
14687
|
+
expiresAt: number2().int().optional(),
|
|
14688
|
+
email: string2().min(1),
|
|
14689
|
+
organizationId: string2().min(1).optional(),
|
|
14690
|
+
workspaceId: string2().min(1).optional(),
|
|
14691
|
+
clientId: string2().min(1).optional()
|
|
14692
|
+
});
|
|
14431
14693
|
|
|
14432
14694
|
// src/domains/auth/store/load.ts
|
|
14433
14695
|
async function loadApiKey(configDir, deps) {
|
|
@@ -14441,7 +14703,7 @@ async function loadApiKey(configDir, deps) {
|
|
|
14441
14703
|
errors.keychain = errorMessage(err);
|
|
14442
14704
|
}
|
|
14443
14705
|
try {
|
|
14444
|
-
const content = await deps.fs.readFile(
|
|
14706
|
+
const content = await deps.fs.readFile(join4(configDir, credentialsFile));
|
|
14445
14707
|
const parsed = credentialsFileSchema.safeParse(JSON.parse(content));
|
|
14446
14708
|
if (parsed.success) {
|
|
14447
14709
|
return { found: true, key: parsed.data.apiKey, source: "file" };
|
|
@@ -14453,16 +14715,16 @@ async function loadApiKey(configDir, deps) {
|
|
|
14453
14715
|
return { found: false, errors };
|
|
14454
14716
|
}
|
|
14455
14717
|
// src/domains/auth/store/save.ts
|
|
14456
|
-
import { join as
|
|
14457
|
-
import { Entry as
|
|
14718
|
+
import { join as join5 } from "node:path";
|
|
14719
|
+
import { Entry as Entry3 } from "@napi-rs/keyring";
|
|
14458
14720
|
async function saveToFile(configDir, key, fs) {
|
|
14459
14721
|
const payload = { apiKey: key };
|
|
14460
14722
|
await fs.mkdir(configDir, { recursive: true, mode: 448 });
|
|
14461
|
-
await fs.writeFile(
|
|
14723
|
+
await fs.writeFile(join5(configDir, credentialsFile), JSON.stringify(payload, undefined, 2), { mode: 384 });
|
|
14462
14724
|
}
|
|
14463
14725
|
async function saveApiKey(configDir, key, fs) {
|
|
14464
14726
|
try {
|
|
14465
|
-
const entry = new
|
|
14727
|
+
const entry = new Entry3(service, account);
|
|
14466
14728
|
entry.setPassword(key);
|
|
14467
14729
|
return { stored: "keychain" };
|
|
14468
14730
|
} catch (err) {
|
|
@@ -14470,10 +14732,159 @@ async function saveApiKey(configDir, key, fs) {
|
|
|
14470
14732
|
return { stored: "file", keychainError: errorMessage(err) };
|
|
14471
14733
|
}
|
|
14472
14734
|
}
|
|
14735
|
+
// src/domains/auth/store/loadTokens.ts
|
|
14736
|
+
import { join as join6 } from "node:path";
|
|
14737
|
+
var invalidPayload = "Invalid stored token format";
|
|
14738
|
+
function parseTokens(raw) {
|
|
14739
|
+
const parsed = oauthTokensSchema.safeParse(JSON.parse(raw));
|
|
14740
|
+
if (!parsed.success)
|
|
14741
|
+
return;
|
|
14742
|
+
return {
|
|
14743
|
+
accessToken: parsed.data.accessToken,
|
|
14744
|
+
refreshToken: parsed.data.refreshToken,
|
|
14745
|
+
expiresAt: parsed.data.expiresAt,
|
|
14746
|
+
email: parsed.data.email,
|
|
14747
|
+
organizationId: parsed.data.organizationId,
|
|
14748
|
+
workspaceId: parsed.data.workspaceId,
|
|
14749
|
+
clientId: parsed.data.clientId
|
|
14750
|
+
};
|
|
14751
|
+
}
|
|
14752
|
+
async function loadTokens(configDir, deps) {
|
|
14753
|
+
const errors = {};
|
|
14754
|
+
try {
|
|
14755
|
+
const raw = new deps.EntryClass(service, tokensAccount).getPassword();
|
|
14756
|
+
if (raw) {
|
|
14757
|
+
const tokens = parseTokens(raw);
|
|
14758
|
+
if (tokens)
|
|
14759
|
+
return { found: true, tokens, source: "keychain" };
|
|
14760
|
+
errors.keychain = invalidPayload;
|
|
14761
|
+
}
|
|
14762
|
+
} catch (err) {
|
|
14763
|
+
errors.keychain = errorMessage(err);
|
|
14764
|
+
}
|
|
14765
|
+
try {
|
|
14766
|
+
const raw = await deps.fs.readFile(join6(configDir, tokensFile));
|
|
14767
|
+
const tokens = parseTokens(raw);
|
|
14768
|
+
if (tokens)
|
|
14769
|
+
return { found: true, tokens, source: "file" };
|
|
14770
|
+
errors.file = invalidPayload;
|
|
14771
|
+
} catch (err) {
|
|
14772
|
+
errors.file = errorMessage(err);
|
|
14773
|
+
}
|
|
14774
|
+
return { found: false, errors };
|
|
14775
|
+
}
|
|
14776
|
+
|
|
14777
|
+
// src/domains/auth/store/saveTokens.ts
|
|
14778
|
+
import { randomUUID } from "node:crypto";
|
|
14779
|
+
import { join as join7 } from "node:path";
|
|
14780
|
+
import { Entry as Entry4 } from "@napi-rs/keyring";
|
|
14781
|
+
async function saveToFile2(configDir, tokens, fs) {
|
|
14782
|
+
await fs.mkdir(configDir, { recursive: true, mode: 448 });
|
|
14783
|
+
const target = join7(configDir, tokensFile);
|
|
14784
|
+
const staging = `${target}.${randomUUID()}.tmp`;
|
|
14785
|
+
try {
|
|
14786
|
+
await fs.writeFile(staging, JSON.stringify(tokens, undefined, 2), {
|
|
14787
|
+
mode: 384
|
|
14788
|
+
});
|
|
14789
|
+
await fs.rename(staging, target);
|
|
14790
|
+
} catch (err) {
|
|
14791
|
+
await fs.unlink(staging).catch(() => {});
|
|
14792
|
+
throw err;
|
|
14793
|
+
}
|
|
14794
|
+
}
|
|
14795
|
+
async function saveTokens(configDir, tokens, fs) {
|
|
14796
|
+
try {
|
|
14797
|
+
new Entry4(service, tokensAccount).setPassword(JSON.stringify(tokens));
|
|
14798
|
+
return { stored: "keychain" };
|
|
14799
|
+
} catch (err) {
|
|
14800
|
+
try {
|
|
14801
|
+
new Entry4(service, tokensAccount).deletePassword();
|
|
14802
|
+
} catch {}
|
|
14803
|
+
await saveToFile2(configDir, tokens, fs);
|
|
14804
|
+
return { stored: "file", keychainError: errorMessage(err) };
|
|
14805
|
+
}
|
|
14806
|
+
}
|
|
14807
|
+
|
|
14808
|
+
// src/domains/auth/resolveOauthToken.ts
|
|
14809
|
+
var expiryMarginMs = 30000;
|
|
14810
|
+
async function resolveOauthToken(configDir, deps) {
|
|
14811
|
+
const stored = await deps.loadTokens(configDir);
|
|
14812
|
+
if (!stored.found)
|
|
14813
|
+
return;
|
|
14814
|
+
const { tokens } = stored;
|
|
14815
|
+
const expiresAt = tokens.expiresAt;
|
|
14816
|
+
const isFresh = expiresAt !== undefined && expiresAt - expiryMarginMs > deps.now();
|
|
14817
|
+
if (isFresh) {
|
|
14818
|
+
return {
|
|
14819
|
+
key: tokens.accessToken,
|
|
14820
|
+
email: tokens.email,
|
|
14821
|
+
workspaceId: tokens.workspaceId
|
|
14822
|
+
};
|
|
14823
|
+
}
|
|
14824
|
+
const refreshed = await deps.refreshTokens({
|
|
14825
|
+
refreshToken: tokens.refreshToken,
|
|
14826
|
+
organizationId: tokens.organizationId,
|
|
14827
|
+
clientId: tokens.clientId
|
|
14828
|
+
});
|
|
14829
|
+
if (!refreshed.ok) {
|
|
14830
|
+
if (refreshed.retryable && expiresAt !== undefined && expiresAt > deps.now()) {
|
|
14831
|
+
return {
|
|
14832
|
+
key: tokens.accessToken,
|
|
14833
|
+
email: tokens.email,
|
|
14834
|
+
workspaceId: tokens.workspaceId
|
|
14835
|
+
};
|
|
14836
|
+
}
|
|
14837
|
+
const current = await deps.loadTokens(configDir);
|
|
14838
|
+
if (current.found && current.tokens.refreshToken !== tokens.refreshToken && current.tokens.email === tokens.email && current.tokens.organizationId === tokens.organizationId && current.tokens.clientId === tokens.clientId && current.tokens.expiresAt !== undefined && current.tokens.expiresAt > deps.now()) {
|
|
14839
|
+
return {
|
|
14840
|
+
key: current.tokens.accessToken,
|
|
14841
|
+
email: current.tokens.email,
|
|
14842
|
+
workspaceId: current.tokens.workspaceId
|
|
14843
|
+
};
|
|
14844
|
+
}
|
|
14845
|
+
return;
|
|
14846
|
+
}
|
|
14847
|
+
try {
|
|
14848
|
+
await deps.saveTokens(configDir, {
|
|
14849
|
+
...refreshed.value,
|
|
14850
|
+
workspaceId: tokens.workspaceId,
|
|
14851
|
+
clientId: tokens.clientId
|
|
14852
|
+
});
|
|
14853
|
+
} catch {}
|
|
14854
|
+
return {
|
|
14855
|
+
key: refreshed.value.accessToken,
|
|
14856
|
+
email: refreshed.value.email,
|
|
14857
|
+
workspaceId: tokens.workspaceId
|
|
14858
|
+
};
|
|
14859
|
+
}
|
|
14860
|
+
|
|
14473
14861
|
// src/domains/auth/resolve.ts
|
|
14862
|
+
function makeOauthDeps(fs) {
|
|
14863
|
+
return {
|
|
14864
|
+
loadTokens: (configDir) => loadTokens(configDir, { EntryClass: Entry5, fs }),
|
|
14865
|
+
refreshTokens: async ({ refreshToken, organizationId, clientId }) => {
|
|
14866
|
+
const config = resolveWorkosConfig(clientId);
|
|
14867
|
+
if (!config.configured) {
|
|
14868
|
+
return {
|
|
14869
|
+
ok: false,
|
|
14870
|
+
error: authErrorMessages.workos.noClientForSession,
|
|
14871
|
+
retryable: false
|
|
14872
|
+
};
|
|
14873
|
+
}
|
|
14874
|
+
return refreshAccessToken(refreshToken, organizationId, {
|
|
14875
|
+
fetch: globalThis.fetch,
|
|
14876
|
+
baseUrl: config.baseUrl,
|
|
14877
|
+
clientId: config.clientId
|
|
14878
|
+
});
|
|
14879
|
+
},
|
|
14880
|
+
saveTokens: (configDir, tokens) => saveTokens(configDir, tokens, fs),
|
|
14881
|
+
now: () => Date.now()
|
|
14882
|
+
};
|
|
14883
|
+
}
|
|
14474
14884
|
function makeDefaultDeps(fs) {
|
|
14475
14885
|
return {
|
|
14476
|
-
loadApiKey: (configDir) => loadApiKey(configDir, { EntryClass:
|
|
14886
|
+
loadApiKey: (configDir) => loadApiKey(configDir, { EntryClass: Entry5, fs }),
|
|
14887
|
+
resolveOauth: (configDir) => resolveOauthToken(configDir, makeOauthDeps(fs)),
|
|
14477
14888
|
env: process.env
|
|
14478
14889
|
};
|
|
14479
14890
|
}
|
|
@@ -14481,11 +14892,19 @@ async function resolveApiKey(configDir, fs, deps) {
|
|
|
14481
14892
|
const resolvedDeps = deps ?? makeDefaultDeps(fs);
|
|
14482
14893
|
const envKey = resolvedDeps.env["QAWOLF_API_KEY"];
|
|
14483
14894
|
if (envKey?.trim()) {
|
|
14484
|
-
return { key: envKey.trim(), source: "env" };
|
|
14895
|
+
return { key: envKey.trim(), source: "env", workspaceId: undefined };
|
|
14485
14896
|
}
|
|
14486
14897
|
const stored = await resolvedDeps.loadApiKey(configDir);
|
|
14487
14898
|
if (stored.found) {
|
|
14488
|
-
return { key: stored.key, source: stored.source };
|
|
14899
|
+
return { key: stored.key, source: stored.source, workspaceId: undefined };
|
|
14900
|
+
}
|
|
14901
|
+
const oauth = await resolvedDeps.resolveOauth(configDir);
|
|
14902
|
+
if (oauth) {
|
|
14903
|
+
return {
|
|
14904
|
+
key: oauth.key,
|
|
14905
|
+
source: "browser",
|
|
14906
|
+
workspaceId: oauth.workspaceId
|
|
14907
|
+
};
|
|
14489
14908
|
}
|
|
14490
14909
|
return;
|
|
14491
14910
|
}
|
|
@@ -14507,9 +14926,9 @@ async function validateApiKey(deps) {
|
|
|
14507
14926
|
// src/shell/logger.ts
|
|
14508
14927
|
var import_pino = __toESM(require_pino(), 1);
|
|
14509
14928
|
import { mkdirSync as mkdirSync2, openSync } from "node:fs";
|
|
14510
|
-
import { dirname, join as
|
|
14929
|
+
import { dirname, join as join8 } from "node:path";
|
|
14511
14930
|
function defaultLogPath() {
|
|
14512
|
-
return
|
|
14931
|
+
return join8(envPaths("qawolf", { suffix: "" }).log, "cli.log");
|
|
14513
14932
|
}
|
|
14514
14933
|
function resolveStderrLevel(env, verbose) {
|
|
14515
14934
|
if (verbose)
|
|
@@ -14577,14 +14996,184 @@ function createLoggingSystem(opts) {
|
|
|
14577
14996
|
};
|
|
14578
14997
|
}
|
|
14579
14998
|
|
|
14580
|
-
// src/
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
|
|
14585
|
-
|
|
14586
|
-
|
|
14587
|
-
|
|
14999
|
+
// src/core/publicApi/flagKind.ts
|
|
15000
|
+
function flagKind(schema) {
|
|
15001
|
+
if (schema.type === "string")
|
|
15002
|
+
return { ok: true, kind: "string" };
|
|
15003
|
+
if (schema.type === "number" || schema.type === "integer") {
|
|
15004
|
+
return { ok: true, kind: "number" };
|
|
15005
|
+
}
|
|
15006
|
+
if (schema.type === "boolean")
|
|
15007
|
+
return { ok: true, kind: "boolean" };
|
|
15008
|
+
if (schema.type === "array") {
|
|
15009
|
+
if (schema.items?.type !== "string") {
|
|
15010
|
+
return {
|
|
15011
|
+
ok: false,
|
|
15012
|
+
reason: "only string arrays can be expressed as flags"
|
|
15013
|
+
};
|
|
15014
|
+
}
|
|
15015
|
+
return { ok: true, kind: "string-array" };
|
|
15016
|
+
}
|
|
15017
|
+
if (schema.type === "object") {
|
|
15018
|
+
if (schema.properties) {
|
|
15019
|
+
return {
|
|
15020
|
+
ok: false,
|
|
15021
|
+
reason: "nested objects cannot be expressed as flags"
|
|
15022
|
+
};
|
|
15023
|
+
}
|
|
15024
|
+
if (typeof schema.additionalProperties === "object" && schema.additionalProperties.type === "string") {
|
|
15025
|
+
return { ok: true, kind: "key-value-record" };
|
|
15026
|
+
}
|
|
15027
|
+
return { ok: false, reason: "nested objects cannot be expressed as flags" };
|
|
15028
|
+
}
|
|
15029
|
+
return {
|
|
15030
|
+
ok: false,
|
|
15031
|
+
reason: `type ${schema.type ?? "unknown"} cannot be expressed as a flag`
|
|
15032
|
+
};
|
|
15033
|
+
}
|
|
15034
|
+
|
|
15035
|
+
// src/core/publicApi/objectShape.ts
|
|
15036
|
+
var asObjectShape = (schema) => schema.type === "object" && schema.properties ? { properties: schema.properties, required: new Set(schema.required) } : undefined;
|
|
15037
|
+
function mergeIntersection(members) {
|
|
15038
|
+
const shape = { properties: {}, required: new Set };
|
|
15039
|
+
for (const member of members) {
|
|
15040
|
+
const memberShape = asObjectShape(member);
|
|
15041
|
+
if (!memberShape) {
|
|
15042
|
+
return {
|
|
15043
|
+
ok: false,
|
|
15044
|
+
field: "",
|
|
15045
|
+
reason: "intersection members must be object schemas"
|
|
15046
|
+
};
|
|
15047
|
+
}
|
|
15048
|
+
for (const [field, fieldSchema] of Object.entries(memberShape.properties)) {
|
|
15049
|
+
if (field in shape.properties) {
|
|
15050
|
+
return {
|
|
15051
|
+
ok: false,
|
|
15052
|
+
field,
|
|
15053
|
+
reason: "field appears in multiple intersection members"
|
|
15054
|
+
};
|
|
15055
|
+
}
|
|
15056
|
+
shape.properties[field] = fieldSchema;
|
|
15057
|
+
if (memberShape.required.has(field))
|
|
15058
|
+
shape.required.add(field);
|
|
15059
|
+
}
|
|
15060
|
+
}
|
|
15061
|
+
return { ok: true, shape };
|
|
15062
|
+
}
|
|
15063
|
+
function mergeUnion(branches) {
|
|
15064
|
+
const shapes = [];
|
|
15065
|
+
for (const branch of branches) {
|
|
15066
|
+
const branchShape = asObjectShape(branch);
|
|
15067
|
+
if (!branchShape) {
|
|
15068
|
+
return {
|
|
15069
|
+
ok: false,
|
|
15070
|
+
field: "",
|
|
15071
|
+
reason: "union branches must be object schemas"
|
|
15072
|
+
};
|
|
15073
|
+
}
|
|
15074
|
+
shapes.push(branchShape);
|
|
15075
|
+
}
|
|
15076
|
+
const shape = { properties: {}, required: new Set };
|
|
15077
|
+
for (const branchShape of shapes) {
|
|
15078
|
+
for (const [field, fieldSchema] of Object.entries(branchShape.properties)) {
|
|
15079
|
+
const existing = shape.properties[field];
|
|
15080
|
+
if (!existing) {
|
|
15081
|
+
shape.properties[field] = { ...fieldSchema };
|
|
15082
|
+
continue;
|
|
15083
|
+
}
|
|
15084
|
+
const kinds = [flagKind(existing), flagKind(fieldSchema)];
|
|
15085
|
+
if (kinds[0]?.ok && kinds[1]?.ok) {
|
|
15086
|
+
if (kinds[0].kind !== kinds[1].kind) {
|
|
15087
|
+
return {
|
|
15088
|
+
ok: false,
|
|
15089
|
+
field,
|
|
15090
|
+
reason: "field has conflicting types across union branches"
|
|
15091
|
+
};
|
|
15092
|
+
}
|
|
15093
|
+
} else if (JSON.stringify({ ...existing, description: undefined }) !== JSON.stringify({ ...fieldSchema, description: undefined })) {
|
|
15094
|
+
return {
|
|
15095
|
+
ok: false,
|
|
15096
|
+
field,
|
|
15097
|
+
reason: "field has conflicting object schemas across union branches"
|
|
15098
|
+
};
|
|
15099
|
+
}
|
|
15100
|
+
if (!existing.description && fieldSchema.description) {
|
|
15101
|
+
existing.description = fieldSchema.description;
|
|
15102
|
+
}
|
|
15103
|
+
}
|
|
15104
|
+
}
|
|
15105
|
+
const discriminator = Object.keys(shape.properties).find((field) => {
|
|
15106
|
+
const values = shapes.map((branch) => branch.properties[field]?.const);
|
|
15107
|
+
return values.every((value) => typeof value === "string") && new Set(values).size === shapes.length && shapes.every((branch) => branch.required.has(field));
|
|
15108
|
+
});
|
|
15109
|
+
for (const [field, fieldSchema] of Object.entries(shape.properties)) {
|
|
15110
|
+
const occurrences = shapes.filter((branch) => (field in branch.properties));
|
|
15111
|
+
if (occurrences.length === shapes.length && occurrences.every((branch) => branch.required.has(field))) {
|
|
15112
|
+
shape.required.add(field);
|
|
15113
|
+
}
|
|
15114
|
+
if (field === discriminator) {
|
|
15115
|
+
const values = shapes.map((branch) => branch.properties[field]?.const);
|
|
15116
|
+
fieldSchema.description = `One of: ${values.join(", ")}`;
|
|
15117
|
+
}
|
|
15118
|
+
}
|
|
15119
|
+
return { ok: true, shape };
|
|
15120
|
+
}
|
|
15121
|
+
function toObjectShape(schema) {
|
|
15122
|
+
if (schema.allOf)
|
|
15123
|
+
return mergeIntersection(schema.allOf);
|
|
15124
|
+
const branches = schema.oneOf ?? schema.anyOf;
|
|
15125
|
+
if (branches)
|
|
15126
|
+
return mergeUnion(branches);
|
|
15127
|
+
const shape = asObjectShape(schema);
|
|
15128
|
+
if (shape)
|
|
15129
|
+
return { ok: true, shape };
|
|
15130
|
+
return {
|
|
15131
|
+
ok: false,
|
|
15132
|
+
field: "",
|
|
15133
|
+
reason: "contract input must be an object schema"
|
|
15134
|
+
};
|
|
15135
|
+
}
|
|
15136
|
+
|
|
15137
|
+
// src/shell/platform/applyWorkspaceId.ts
|
|
15138
|
+
var acceptsWorkspace = new WeakMap;
|
|
15139
|
+
function takesWorkspaceId(inputSchema) {
|
|
15140
|
+
const cached = acceptsWorkspace.get(inputSchema);
|
|
15141
|
+
if (cached !== undefined)
|
|
15142
|
+
return cached;
|
|
15143
|
+
let accepted = false;
|
|
15144
|
+
try {
|
|
15145
|
+
const jsonSchema = toJSONSchema(inputSchema, {
|
|
15146
|
+
io: "input"
|
|
15147
|
+
});
|
|
15148
|
+
const shape = toObjectShape(jsonSchema);
|
|
15149
|
+
accepted = shape.ok && "workspaceId" in shape.shape.properties;
|
|
15150
|
+
} catch {
|
|
15151
|
+
accepted = false;
|
|
15152
|
+
}
|
|
15153
|
+
acceptsWorkspace.set(inputSchema, accepted);
|
|
15154
|
+
return accepted;
|
|
15155
|
+
}
|
|
15156
|
+
function applyWorkspaceId(inputSchema, input, workspaceId) {
|
|
15157
|
+
if (!workspaceId)
|
|
15158
|
+
return input;
|
|
15159
|
+
if (typeof input !== "object" || input === null)
|
|
15160
|
+
return input;
|
|
15161
|
+
const existing = input.workspaceId;
|
|
15162
|
+
if (existing !== undefined)
|
|
15163
|
+
return input;
|
|
15164
|
+
if (!takesWorkspaceId(inputSchema))
|
|
15165
|
+
return input;
|
|
15166
|
+
return { ...input, workspaceId };
|
|
15167
|
+
}
|
|
15168
|
+
|
|
15169
|
+
// src/shell/platform/parseErrorBody.ts
|
|
15170
|
+
var defaultMaxLength = 1024;
|
|
15171
|
+
function asRecord(value) {
|
|
15172
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
15173
|
+
}
|
|
15174
|
+
function asString(value) {
|
|
15175
|
+
return typeof value === "string" ? value : undefined;
|
|
15176
|
+
}
|
|
14588
15177
|
function extractMessage(parsed) {
|
|
14589
15178
|
const root = asRecord(parsed);
|
|
14590
15179
|
if (!root)
|
|
@@ -14743,7 +15332,7 @@ function callPublicApi(trpc, contract, input, options) {
|
|
|
14743
15332
|
}
|
|
14744
15333
|
function makeCallPublicApiMethod(trpc, deps, readBackoffMs) {
|
|
14745
15334
|
return async (contract, input, options) => requestWithRetry({
|
|
14746
|
-
call: () => callPublicApi(trpc, contract, input, options),
|
|
15335
|
+
call: () => callPublicApi(trpc, contract, applyWorkspaceId(contract.input, input, deps.workspaceId), options),
|
|
14747
15336
|
backoffMs: contract.kind === "read" ? readBackoffMs : [],
|
|
14748
15337
|
describe: (err) => describeRequestError(err, deps.baseUrl, contract.name),
|
|
14749
15338
|
sleep: deps.sleep
|
|
@@ -15646,7 +16235,7 @@ function summarize(error) {
|
|
|
15646
16235
|
// src/shell/platform/downloadBundle.ts
|
|
15647
16236
|
import { randomBytes } from "node:crypto";
|
|
15648
16237
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
15649
|
-
import { join as
|
|
16238
|
+
import { join as join9 } from "node:path";
|
|
15650
16239
|
|
|
15651
16240
|
// src/shell/platform/fetchSignedUrl.ts
|
|
15652
16241
|
var defaultStallTimeoutMs = 30000;
|
|
@@ -15734,7 +16323,7 @@ async function fetchSignedUrl(args, deps = { fetch: globalThis.fetch }) {
|
|
|
15734
16323
|
|
|
15735
16324
|
// src/shell/platform/downloadBundle.ts
|
|
15736
16325
|
async function downloadBundle(signedUrl, deps) {
|
|
15737
|
-
const tmpArchive =
|
|
16326
|
+
const tmpArchive = join9(tmpdir2(), `qawolf-pull-${randomBytes(8).toString("hex")}.tar.gz`);
|
|
15738
16327
|
const result = await fetchSignedUrl({ url: signedUrl, dest: tmpArchive }, { fetch: deps.fetch, fs: deps.fs });
|
|
15739
16328
|
if (!result.ok) {
|
|
15740
16329
|
await deps.fs.unlink(tmpArchive).catch(() => {});
|
|
@@ -15838,6 +16427,10 @@ var identityResponse = union([
|
|
|
15838
16427
|
user: never().optional()
|
|
15839
16428
|
}).transform(({ organization }) => ({ organization }))
|
|
15840
16429
|
]);
|
|
16430
|
+
// node_modules/@qawolf/api-contracts/dist/v1/identity/organizations.js
|
|
16431
|
+
var identityOrganizationsResponse = object({
|
|
16432
|
+
organizations: array(identityOrganization)
|
|
16433
|
+
});
|
|
15841
16434
|
// node_modules/@qawolf/api-contracts/dist/v1/ids.js
|
|
15842
16435
|
var defaultIdSchemas = {
|
|
15843
16436
|
aiTask: string2().min(1).describe("The id of the AI task."),
|
|
@@ -17537,19 +18130,70 @@ var makeContractsV1 = (ids) => {
|
|
|
17537
18130
|
};
|
|
17538
18131
|
var publicContractsV1 = makeContractsV1(defaultIdSchemas);
|
|
17539
18132
|
|
|
18133
|
+
// src/shell/platform/organizations.ts
|
|
18134
|
+
function parseOrganizationsResponse(json) {
|
|
18135
|
+
const parsed = identityOrganizationsResponse.safeParse(json);
|
|
18136
|
+
return parsed.success ? parsed.data.organizations : undefined;
|
|
18137
|
+
}
|
|
18138
|
+
|
|
18139
|
+
// src/shell/platform/getAccessibleOrganizations.ts
|
|
18140
|
+
var timeoutMs2 = 1e4;
|
|
18141
|
+
async function getAccessibleOrganizations(apiKey, deps) {
|
|
18142
|
+
const url = `${deps.baseUrl}/api/v0/identity/organizations`;
|
|
18143
|
+
let response;
|
|
18144
|
+
try {
|
|
18145
|
+
response = await deps.fetch(url, {
|
|
18146
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
18147
|
+
signal: AbortSignal.timeout(timeoutMs2)
|
|
18148
|
+
});
|
|
18149
|
+
} catch (error) {
|
|
18150
|
+
if (isTimeoutError(error)) {
|
|
18151
|
+
return { ok: false, error: { kind: "timeout", timeoutMs: timeoutMs2 } };
|
|
18152
|
+
}
|
|
18153
|
+
return { ok: false, error: { kind: "network", cause: toError(error) } };
|
|
18154
|
+
}
|
|
18155
|
+
if (!response.ok) {
|
|
18156
|
+
const body = await response.text().catch(() => "");
|
|
18157
|
+
return {
|
|
18158
|
+
ok: false,
|
|
18159
|
+
error: { kind: "http", status: response.status, body }
|
|
18160
|
+
};
|
|
18161
|
+
}
|
|
18162
|
+
let json;
|
|
18163
|
+
try {
|
|
18164
|
+
json = await response.json();
|
|
18165
|
+
} catch (error) {
|
|
18166
|
+
if (isTimeoutError(error)) {
|
|
18167
|
+
return { ok: false, error: { kind: "timeout", timeoutMs: timeoutMs2 } };
|
|
18168
|
+
}
|
|
18169
|
+
json = undefined;
|
|
18170
|
+
}
|
|
18171
|
+
const organizations = parseOrganizationsResponse(json);
|
|
18172
|
+
if (!organizations) {
|
|
18173
|
+
return {
|
|
18174
|
+
ok: false,
|
|
18175
|
+
error: {
|
|
18176
|
+
kind: "parse",
|
|
18177
|
+
cause: Error("organizations response did not match the contract")
|
|
18178
|
+
}
|
|
18179
|
+
};
|
|
18180
|
+
}
|
|
18181
|
+
return { ok: true, data: organizations };
|
|
18182
|
+
}
|
|
18183
|
+
|
|
17540
18184
|
// src/shell/platform/getIdentity.ts
|
|
17541
|
-
var
|
|
18185
|
+
var timeoutMs3 = 1e4;
|
|
17542
18186
|
async function getIdentity(apiKey, deps) {
|
|
17543
18187
|
const url = `${deps.baseUrl}/api/v0/identity`;
|
|
17544
18188
|
let response;
|
|
17545
18189
|
try {
|
|
17546
18190
|
response = await deps.fetch(url, {
|
|
17547
18191
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
17548
|
-
signal: AbortSignal.timeout(
|
|
18192
|
+
signal: AbortSignal.timeout(timeoutMs3)
|
|
17549
18193
|
});
|
|
17550
18194
|
} catch (error) {
|
|
17551
18195
|
if (isTimeoutError(error)) {
|
|
17552
|
-
return { ok: false, error: { kind: "timeout", timeoutMs } };
|
|
18196
|
+
return { ok: false, error: { kind: "timeout", timeoutMs: timeoutMs3 } };
|
|
17553
18197
|
}
|
|
17554
18198
|
return {
|
|
17555
18199
|
ok: false,
|
|
@@ -17568,7 +18212,7 @@ async function getIdentity(apiKey, deps) {
|
|
|
17568
18212
|
json = await response.json();
|
|
17569
18213
|
} catch (error) {
|
|
17570
18214
|
if (isTimeoutError(error)) {
|
|
17571
|
-
return { ok: false, error: { kind: "timeout", timeoutMs } };
|
|
18215
|
+
return { ok: false, error: { kind: "timeout", timeoutMs: timeoutMs3 } };
|
|
17572
18216
|
}
|
|
17573
18217
|
json = undefined;
|
|
17574
18218
|
}
|
|
@@ -17579,6 +18223,24 @@ async function getIdentity(apiKey, deps) {
|
|
|
17579
18223
|
return { ok: true, data: parsed.data };
|
|
17580
18224
|
}
|
|
17581
18225
|
|
|
18226
|
+
// src/shell/platform/identityMethods.ts
|
|
18227
|
+
function createIdentityMethods(apiKey, deps, backoffMs) {
|
|
18228
|
+
return {
|
|
18229
|
+
getIdentity: () => requestWithRetry({
|
|
18230
|
+
call: () => getIdentity(apiKey, deps),
|
|
18231
|
+
backoffMs,
|
|
18232
|
+
describe: describeIdentityError,
|
|
18233
|
+
sleep: deps.sleep
|
|
18234
|
+
}),
|
|
18235
|
+
getAccessibleOrganizations: () => requestWithRetry({
|
|
18236
|
+
call: () => getAccessibleOrganizations(apiKey, deps),
|
|
18237
|
+
backoffMs,
|
|
18238
|
+
describe: describeIdentityError,
|
|
18239
|
+
sleep: deps.sleep
|
|
18240
|
+
})
|
|
18241
|
+
};
|
|
18242
|
+
}
|
|
18243
|
+
|
|
17582
18244
|
// src/shell/platform/types.ts
|
|
17583
18245
|
var environmentListItemSchema = object({
|
|
17584
18246
|
envId: string2(),
|
|
@@ -17706,7 +18368,7 @@ function isUnsafeSegment(segment) {
|
|
|
17706
18368
|
|
|
17707
18369
|
// src/shell/platform/teamStorageAssetSnapshot.ts
|
|
17708
18370
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
17709
|
-
import { join as
|
|
18371
|
+
import { join as join10, sep as sep2 } from "node:path";
|
|
17710
18372
|
function mintAssetSnapshotPath(assetsAbs, label) {
|
|
17711
18373
|
return `${assetsAbs}.${label}-${randomBytes2(8).toString("hex")}`;
|
|
17712
18374
|
}
|
|
@@ -17756,9 +18418,9 @@ function expectedEntries(filePaths) {
|
|
|
17756
18418
|
return entries;
|
|
17757
18419
|
}
|
|
17758
18420
|
async function collectEntries(root, relDir, out, fs) {
|
|
17759
|
-
const current = relDir ?
|
|
18421
|
+
const current = relDir ? join10(root, relDir) : root;
|
|
17760
18422
|
for (const entry of await fs.readdirWithTypes(current)) {
|
|
17761
|
-
const relPath = relDir ?
|
|
18423
|
+
const relPath = relDir ? join10(relDir, entry.name) : entry.name;
|
|
17762
18424
|
out.add(relPath);
|
|
17763
18425
|
if (entry.isDirectory()) {
|
|
17764
18426
|
await collectEntries(root, relPath, out, fs);
|
|
@@ -17772,7 +18434,7 @@ function setsEqual(left, right) {
|
|
|
17772
18434
|
}
|
|
17773
18435
|
|
|
17774
18436
|
// src/shell/platform/teamStorageAssetReuse.ts
|
|
17775
|
-
import { join as
|
|
18437
|
+
import { join as join11 } from "node:path";
|
|
17776
18438
|
async function reusableAssetPaths(assetsAbs, safeFiles, manifest, fs) {
|
|
17777
18439
|
const reusable = new Set;
|
|
17778
18440
|
for (const { file, relativePath } of safeFiles) {
|
|
@@ -17788,20 +18450,20 @@ async function canReuseAsset(assetsAbs, relativePath, file, manifest, fs) {
|
|
|
17788
18450
|
const previous = manifest.get(relativePath);
|
|
17789
18451
|
if (previous?.etag !== file.etag)
|
|
17790
18452
|
return false;
|
|
17791
|
-
return fs.pathExists(
|
|
18453
|
+
return fs.pathExists(join11(assetsAbs, relativePath));
|
|
17792
18454
|
}
|
|
17793
18455
|
|
|
17794
18456
|
// src/shell/platform/writeAssetSnapshot.ts
|
|
17795
|
-
import { dirname as dirname3, join as
|
|
18457
|
+
import { dirname as dirname3, join as join12 } from "node:path";
|
|
17796
18458
|
async function writeAssetSnapshot(args) {
|
|
17797
18459
|
let downloadedCount = 0;
|
|
17798
18460
|
const total = args.safeFiles.filter(({ relativePath }) => !args.reusable.has(relativePath)).length;
|
|
17799
18461
|
await args.deps.fs.mkdir(args.tmpAssets, { recursive: true });
|
|
17800
18462
|
for (const { file, relativePath } of args.safeFiles) {
|
|
17801
|
-
const dest =
|
|
18463
|
+
const dest = join12(args.tmpAssets, relativePath);
|
|
17802
18464
|
await args.deps.fs.mkdir(dirname3(dest), { recursive: true });
|
|
17803
18465
|
if (args.reusable.has(relativePath)) {
|
|
17804
|
-
await args.deps.fs.copyFile(
|
|
18466
|
+
await args.deps.fs.copyFile(join12(args.assetsAbs, relativePath), dest);
|
|
17805
18467
|
continue;
|
|
17806
18468
|
}
|
|
17807
18469
|
args.deps.onProgress?.({ current: downloadedCount + 1, total });
|
|
@@ -17878,14 +18540,7 @@ function createPlatformClient(apiKey, deps) {
|
|
|
17878
18540
|
return { ok: true, value: { signedUrl: result.value.url } };
|
|
17879
18541
|
}
|
|
17880
18542
|
return {
|
|
17881
|
-
|
|
17882
|
-
return requestWithRetry({
|
|
17883
|
-
call: () => getIdentity(apiKey, deps),
|
|
17884
|
-
backoffMs: requestBackoffMs2,
|
|
17885
|
-
describe: describeIdentityError,
|
|
17886
|
-
sleep: deps.sleep
|
|
17887
|
-
});
|
|
17888
|
-
},
|
|
18543
|
+
...createIdentityMethods(apiKey, deps, requestBackoffMs2),
|
|
17889
18544
|
getFlowsBundleUrl: getFlowsBundleUrlImpl,
|
|
17890
18545
|
callPublicApi: makeCallPublicApiMethod(trpc, deps, requestBackoffMs2),
|
|
17891
18546
|
async getEnvVars(envId) {
|
|
@@ -18584,6 +19239,86 @@ class V {
|
|
|
18584
19239
|
}
|
|
18585
19240
|
}
|
|
18586
19241
|
}
|
|
19242
|
+
function p$1(l, e) {
|
|
19243
|
+
if (l === undefined || e.length === 0)
|
|
19244
|
+
return 0;
|
|
19245
|
+
const i = e.findIndex((s) => s.value === l);
|
|
19246
|
+
return i !== -1 ? i : 0;
|
|
19247
|
+
}
|
|
19248
|
+
function g(l, e) {
|
|
19249
|
+
return (e.label ?? String(e.value)).toLowerCase().includes(l.toLowerCase());
|
|
19250
|
+
}
|
|
19251
|
+
function m2(l, e) {
|
|
19252
|
+
if (e)
|
|
19253
|
+
return l ? e : e[0];
|
|
19254
|
+
}
|
|
19255
|
+
var T$1 = class T extends V {
|
|
19256
|
+
filteredOptions;
|
|
19257
|
+
multiple;
|
|
19258
|
+
isNavigating = false;
|
|
19259
|
+
selectedValues = [];
|
|
19260
|
+
focusedValue;
|
|
19261
|
+
#e = 0;
|
|
19262
|
+
#s = "";
|
|
19263
|
+
#t;
|
|
19264
|
+
#i;
|
|
19265
|
+
#n;
|
|
19266
|
+
get cursor() {
|
|
19267
|
+
return this.#e;
|
|
19268
|
+
}
|
|
19269
|
+
get userInputWithCursor() {
|
|
19270
|
+
if (!this.userInput)
|
|
19271
|
+
return styleText(["inverse", "hidden"], "_");
|
|
19272
|
+
if (this._cursor >= this.userInput.length)
|
|
19273
|
+
return `${this.userInput}█`;
|
|
19274
|
+
const e = this.userInput.slice(0, this._cursor), [t, ...i] = this.userInput.slice(this._cursor);
|
|
19275
|
+
return `${e}${styleText("inverse", t)}${i.join("")}`;
|
|
19276
|
+
}
|
|
19277
|
+
get options() {
|
|
19278
|
+
return typeof this.#i == "function" ? this.#i() : this.#i;
|
|
19279
|
+
}
|
|
19280
|
+
constructor(e) {
|
|
19281
|
+
super(e), this.#i = e.options, this.#n = e.placeholder;
|
|
19282
|
+
const t = this.options;
|
|
19283
|
+
this.filteredOptions = [...t], this.multiple = e.multiple === true, this.#t = typeof e.options == "function" ? e.filter : e.filter ?? g;
|
|
19284
|
+
let i;
|
|
19285
|
+
if (e.initialValue && Array.isArray(e.initialValue) ? this.multiple ? i = e.initialValue : i = e.initialValue.slice(0, 1) : !this.multiple && this.options.length > 0 && (i = [this.options[0].value]), i)
|
|
19286
|
+
for (const s of i) {
|
|
19287
|
+
const n = t.findIndex((o) => o.value === s);
|
|
19288
|
+
n !== -1 && (this.toggleSelected(s), this.#e = n);
|
|
19289
|
+
}
|
|
19290
|
+
this.focusedValue = this.options[this.#e]?.value, this.on("key", (s, n) => this.#l(s, n)), this.on("userInput", (s) => this.#u(s));
|
|
19291
|
+
}
|
|
19292
|
+
_isActionKey(e, t) {
|
|
19293
|
+
return e === "\t" || this.multiple && this.isNavigating && t.name === "space" && e !== undefined && e !== "";
|
|
19294
|
+
}
|
|
19295
|
+
#l(e, t) {
|
|
19296
|
+
const i = t.name === "up", s = t.name === "down", n = t.name === "return", o = this.userInput === "" || this.userInput === "\t", u = this.#n, h = this.options, f = u !== undefined && u !== "" && h.some((r) => !r.disabled && (this.#t ? this.#t(u, r) : true));
|
|
19297
|
+
if (t.name === "tab" && o && f) {
|
|
19298
|
+
this.userInput === "\t" && this._clearUserInput(), this._setUserInput(u, true), this.isNavigating = false;
|
|
19299
|
+
return;
|
|
19300
|
+
}
|
|
19301
|
+
i || s ? (this.#e = findCursor(this.#e, i ? -1 : 1, this.filteredOptions), this.focusedValue = this.filteredOptions[this.#e]?.value, this.multiple || (this.selectedValues = [this.focusedValue]), this.isNavigating = true) : n ? this.value = m2(this.multiple, this.selectedValues) : this.multiple ? this.focusedValue !== undefined && (t.name === "tab" || this.isNavigating && t.name === "space") ? this.toggleSelected(this.focusedValue) : this.isNavigating = false : (this.focusedValue && (this.selectedValues = [this.focusedValue]), this.isNavigating = false);
|
|
19302
|
+
}
|
|
19303
|
+
deselectAll() {
|
|
19304
|
+
this.selectedValues = [];
|
|
19305
|
+
}
|
|
19306
|
+
toggleSelected(e) {
|
|
19307
|
+
this.filteredOptions.length !== 0 && (this.multiple ? this.selectedValues.includes(e) ? this.selectedValues = this.selectedValues.filter((t) => t !== e) : this.selectedValues = [...this.selectedValues, e] : this.selectedValues = [e]);
|
|
19308
|
+
}
|
|
19309
|
+
#u(e) {
|
|
19310
|
+
if (e !== this.#s) {
|
|
19311
|
+
this.#s = e;
|
|
19312
|
+
const t = this.options;
|
|
19313
|
+
e && this.#t ? this.filteredOptions = t.filter((n) => this.#t?.(e, n)) : this.filteredOptions = [...t];
|
|
19314
|
+
const i = p$1(this.focusedValue, this.filteredOptions);
|
|
19315
|
+
this.#e = findCursor(i, 0, this.filteredOptions);
|
|
19316
|
+
const s = this.filteredOptions[this.#e];
|
|
19317
|
+
s && !s.disabled ? this.focusedValue = s.value : this.focusedValue = undefined, this.multiple || (this.focusedValue !== undefined ? this.toggleSelected(this.focusedValue) : this.deselectAll());
|
|
19318
|
+
}
|
|
19319
|
+
}
|
|
19320
|
+
};
|
|
19321
|
+
|
|
18587
19322
|
class r extends V {
|
|
18588
19323
|
get cursor() {
|
|
18589
19324
|
return this.value ? 0 : 1;
|
|
@@ -18770,6 +19505,89 @@ var limitOptions = ({
|
|
|
18770
19505
|
b.push(n);
|
|
18771
19506
|
return u && b.push(C), b;
|
|
18772
19507
|
};
|
|
19508
|
+
function P(t) {
|
|
19509
|
+
return t.label ?? String(t.value ?? "");
|
|
19510
|
+
}
|
|
19511
|
+
function E(t, c) {
|
|
19512
|
+
if (!t)
|
|
19513
|
+
return true;
|
|
19514
|
+
const n = (c.label ?? String(c.value ?? "")).toLowerCase(), i = (c.hint ?? "").toLowerCase(), l = String(c.value).toLowerCase(), o = t.toLowerCase();
|
|
19515
|
+
return n.includes(o) || i.includes(o) || l.includes(o);
|
|
19516
|
+
}
|
|
19517
|
+
function N(t, c) {
|
|
19518
|
+
const n = [];
|
|
19519
|
+
for (const i of c)
|
|
19520
|
+
t.includes(i.value) && n.push(i);
|
|
19521
|
+
return n;
|
|
19522
|
+
}
|
|
19523
|
+
var autocomplete = (t) => new T$1({
|
|
19524
|
+
options: t.options,
|
|
19525
|
+
initialValue: t.initialValue ? [t.initialValue] : undefined,
|
|
19526
|
+
initialUserInput: t.initialUserInput,
|
|
19527
|
+
placeholder: t.placeholder,
|
|
19528
|
+
filter: t.filter ?? ((n, i) => E(n, i)),
|
|
19529
|
+
signal: t.signal,
|
|
19530
|
+
input: t.input,
|
|
19531
|
+
output: t.output,
|
|
19532
|
+
validate: t.validate,
|
|
19533
|
+
render() {
|
|
19534
|
+
const n = t.withGuide ?? settings.withGuide, i = n ? [`${styleText2("gray", S_BAR)}`, `${symbol(this.state)} ${t.message}`] : [`${symbol(this.state)} ${t.message}`], l = this.userInput, o = this.options, m = t.placeholder, p = l === "" && m !== undefined, $ = (r, s) => {
|
|
19535
|
+
const a = P(r), u = r.hint && r.value === this.focusedValue ? styleText2("dim", ` (${r.hint})`) : "";
|
|
19536
|
+
switch (s) {
|
|
19537
|
+
case "active":
|
|
19538
|
+
return `${styleText2("green", S_RADIO_ACTIVE)} ${a}${u}`;
|
|
19539
|
+
case "inactive":
|
|
19540
|
+
return `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", a)}`;
|
|
19541
|
+
case "disabled":
|
|
19542
|
+
return `${styleText2("gray", S_RADIO_INACTIVE)} ${styleText2(["strikethrough", "gray"], a)}`;
|
|
19543
|
+
}
|
|
19544
|
+
};
|
|
19545
|
+
switch (this.state) {
|
|
19546
|
+
case "submit": {
|
|
19547
|
+
const r = N(this.selectedValues, o), s = r.length > 0 ? ` ${styleText2("dim", r.map(P).join(", "))}` : "", a = n ? styleText2("gray", S_BAR) : "";
|
|
19548
|
+
return `${i.join(`
|
|
19549
|
+
`)}
|
|
19550
|
+
${a}${s}`;
|
|
19551
|
+
}
|
|
19552
|
+
case "cancel": {
|
|
19553
|
+
const r = l ? ` ${styleText2(["strikethrough", "dim"], l)}` : "", s = n ? styleText2("gray", S_BAR) : "";
|
|
19554
|
+
return `${i.join(`
|
|
19555
|
+
`)}
|
|
19556
|
+
${s}${r}`;
|
|
19557
|
+
}
|
|
19558
|
+
default: {
|
|
19559
|
+
const r = this.state === "error" ? "yellow" : "cyan", s = n ? `${styleText2(r, S_BAR)} ` : "", a = n ? styleText2(r, S_BAR_END) : "";
|
|
19560
|
+
let u = "";
|
|
19561
|
+
if (this.isNavigating || p) {
|
|
19562
|
+
const d = p ? m : l;
|
|
19563
|
+
u = d !== "" ? ` ${styleText2("dim", d)}` : "";
|
|
19564
|
+
} else
|
|
19565
|
+
u = ` ${this.userInputWithCursor}`;
|
|
19566
|
+
const V = this.filteredOptions.length !== o.length ? styleText2("dim", ` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? "" : "es"})`) : "", y = this.filteredOptions.length === 0 && l ? [`${s}${styleText2("yellow", "No matches found")}`] : [], b = this.state === "error" ? [`${s}${styleText2("yellow", this.error)}`] : [];
|
|
19567
|
+
n && i.push(`${s.trimEnd()}`), i.push(`${s}${styleText2("dim", "Search:")}${u}${V}`, ...y, ...b);
|
|
19568
|
+
const v = [
|
|
19569
|
+
`${styleText2("dim", "↑/↓")} to select`,
|
|
19570
|
+
`${styleText2("dim", "Enter:")} confirm`,
|
|
19571
|
+
`${styleText2("dim", "Type:")} to search`
|
|
19572
|
+
], g = [`${s}${v.join(" • ")}`, a], O = this.filteredOptions.length === 0 ? [] : limitOptions({
|
|
19573
|
+
cursor: this.cursor,
|
|
19574
|
+
options: this.filteredOptions,
|
|
19575
|
+
columnPadding: n ? 3 : 0,
|
|
19576
|
+
rowPadding: i.length + g.length,
|
|
19577
|
+
style: (d, f) => $(d, d.disabled ? "disabled" : f ? "active" : "inactive"),
|
|
19578
|
+
maxItems: t.maxItems,
|
|
19579
|
+
output: t.output
|
|
19580
|
+
});
|
|
19581
|
+
return [
|
|
19582
|
+
...i,
|
|
19583
|
+
...O.map((d) => `${s}${d}`),
|
|
19584
|
+
...g
|
|
19585
|
+
].join(`
|
|
19586
|
+
`);
|
|
19587
|
+
}
|
|
19588
|
+
}
|
|
19589
|
+
}
|
|
19590
|
+
}).prompt();
|
|
18773
19591
|
var confirm = (i) => {
|
|
18774
19592
|
const a = i.active ?? "Yes", s = i.inactive ?? "No";
|
|
18775
19593
|
return new r({
|
|
@@ -19200,6 +20018,7 @@ function createStyledClack() {
|
|
|
19200
20018
|
cancel,
|
|
19201
20019
|
confirm,
|
|
19202
20020
|
password,
|
|
20021
|
+
autocomplete,
|
|
19203
20022
|
select,
|
|
19204
20023
|
isCancel,
|
|
19205
20024
|
spinner,
|
|
@@ -19459,13 +20278,52 @@ function createPassword({
|
|
|
19459
20278
|
};
|
|
19460
20279
|
}
|
|
19461
20280
|
|
|
19462
|
-
// src/
|
|
19463
|
-
function
|
|
19464
|
-
return
|
|
19465
|
-
|
|
19466
|
-
|
|
19467
|
-
|
|
19468
|
-
|
|
20281
|
+
// src/core/textSearch.ts
|
|
20282
|
+
function normalizeForSearch(value) {
|
|
20283
|
+
return value.toLowerCase().replace(/[-_\s]+/g, " ").trim();
|
|
20284
|
+
}
|
|
20285
|
+
function matchesSearchTerm(search, fields) {
|
|
20286
|
+
const needle = normalizeForSearch(search);
|
|
20287
|
+
if (!needle)
|
|
20288
|
+
return true;
|
|
20289
|
+
return fields.some((field) => field !== undefined && normalizeForSearch(field).includes(needle));
|
|
20290
|
+
}
|
|
20291
|
+
function createSearchIndex(items, fieldsOf) {
|
|
20292
|
+
const indexed = new Map;
|
|
20293
|
+
for (const item of items) {
|
|
20294
|
+
indexed.set(item, fieldsOf(item).flatMap((field) => field === undefined ? [] : [normalizeForSearch(field)]));
|
|
20295
|
+
}
|
|
20296
|
+
let lastSearch;
|
|
20297
|
+
let needle = "";
|
|
20298
|
+
return (search, item) => {
|
|
20299
|
+
if (search !== lastSearch) {
|
|
20300
|
+
lastSearch = search;
|
|
20301
|
+
needle = normalizeForSearch(search);
|
|
20302
|
+
}
|
|
20303
|
+
if (!needle)
|
|
20304
|
+
return true;
|
|
20305
|
+
const fields = indexed.get(item);
|
|
20306
|
+
return fields ? fields.some((field) => field.includes(needle)) : matchesSearchTerm(search, fieldsOf(item));
|
|
20307
|
+
};
|
|
20308
|
+
}
|
|
20309
|
+
|
|
20310
|
+
// src/shell/ui/renderers/select.ts
|
|
20311
|
+
var searchThreshold = 8;
|
|
20312
|
+
var searchPlaceholder = "Type to filter";
|
|
20313
|
+
function searchableFields(option) {
|
|
20314
|
+
return [option.label, option.hint, option.value];
|
|
20315
|
+
}
|
|
20316
|
+
function createSelect({ mode, clack }) {
|
|
20317
|
+
return async (message, options) => {
|
|
20318
|
+
assertHumanMode(mode, "select");
|
|
20319
|
+
const value = options.length > searchThreshold ? await clack.autocomplete({
|
|
20320
|
+
message,
|
|
20321
|
+
options: [...options],
|
|
20322
|
+
placeholder: searchPlaceholder,
|
|
20323
|
+
filter: createSearchIndex([...options], searchableFields)
|
|
20324
|
+
}) : await clack.select({ message, options: [...options] });
|
|
20325
|
+
if (clack.isCancel(value))
|
|
20326
|
+
return { ok: false };
|
|
19469
20327
|
return { ok: true, value };
|
|
19470
20328
|
};
|
|
19471
20329
|
}
|
|
@@ -19511,12 +20369,12 @@ function createVerboseContext(outputMode, isVerbose) {
|
|
|
19511
20369
|
|
|
19512
20370
|
// src/shell/npmRegistry.ts
|
|
19513
20371
|
var registryUrl = "https://registry.npmjs.org";
|
|
19514
|
-
var
|
|
20372
|
+
var timeoutMs4 = 3000;
|
|
19515
20373
|
async function fetchLatestVersion(packageName, deps = {}) {
|
|
19516
20374
|
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
19517
20375
|
try {
|
|
19518
20376
|
const response = await fetchFn(`${registryUrl}/${packageName}/latest`, {
|
|
19519
|
-
signal: AbortSignal.timeout(
|
|
20377
|
+
signal: AbortSignal.timeout(timeoutMs4)
|
|
19520
20378
|
});
|
|
19521
20379
|
if (!response.ok)
|
|
19522
20380
|
return;
|
|
@@ -19531,7 +20389,7 @@ async function fetchLatestVersion(packageName, deps = {}) {
|
|
|
19531
20389
|
}
|
|
19532
20390
|
|
|
19533
20391
|
// src/domains/updateCheck/updateCheck.ts
|
|
19534
|
-
import { join as
|
|
20392
|
+
import { join as join13 } from "node:path";
|
|
19535
20393
|
|
|
19536
20394
|
// src/core/version.ts
|
|
19537
20395
|
function parseRelease(version) {
|
|
@@ -19577,7 +20435,7 @@ function startUpdateCheck(deps) {
|
|
|
19577
20435
|
return;
|
|
19578
20436
|
if (!isNewerVersion(deps.currentVersion, latest))
|
|
19579
20437
|
return;
|
|
19580
|
-
const noticePath =
|
|
20438
|
+
const noticePath = join13(deps.configDir, noticeFile);
|
|
19581
20439
|
try {
|
|
19582
20440
|
const notified = (await deps.fs.readFile(noticePath)).trim();
|
|
19583
20441
|
if (notified === latest)
|
|
@@ -19599,7 +20457,7 @@ function startUpdateCheck(deps) {
|
|
|
19599
20457
|
// package.json
|
|
19600
20458
|
var package_default = {
|
|
19601
20459
|
name: "@qawolf/cli",
|
|
19602
|
-
version: "1.
|
|
20460
|
+
version: "1.25.0",
|
|
19603
20461
|
description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
19604
20462
|
keywords: [
|
|
19605
20463
|
"automation",
|
|
@@ -19789,7 +20647,12 @@ function withAuthContext(signals, fn, deps = {}) {
|
|
|
19789
20647
|
await updateNotifier.notifyIfOutdated();
|
|
19790
20648
|
return;
|
|
19791
20649
|
}
|
|
19792
|
-
const platformClient = (deps.createPlatform ?? createPlatformClient)(resolved.key, {
|
|
20650
|
+
const platformClient = (deps.createPlatform ?? createPlatformClient)(resolved.key, {
|
|
20651
|
+
baseUrl: apiBaseUrl,
|
|
20652
|
+
fetch: globalThis.fetch,
|
|
20653
|
+
logger: ctx.log("trpc"),
|
|
20654
|
+
workspaceId: resolved.workspaceId
|
|
20655
|
+
});
|
|
19793
20656
|
try {
|
|
19794
20657
|
const result = await fn({
|
|
19795
20658
|
...ctx,
|
|
@@ -19810,28 +20673,15 @@ function withAuthContext(signals, fn, deps = {}) {
|
|
|
19810
20673
|
};
|
|
19811
20674
|
}
|
|
19812
20675
|
|
|
19813
|
-
// src/commands/auth/
|
|
19814
|
-
async function
|
|
19815
|
-
if (ctx.ui.mode !== "human") {
|
|
19816
|
-
ctx.ui.error(authMessages.login.nonInteractive);
|
|
19817
|
-
return { error: "non-interactive" };
|
|
19818
|
-
}
|
|
19819
|
-
const existing = await resolveApiKey(ctx.configDir, ctx.fs);
|
|
19820
|
-
if (existing) {
|
|
19821
|
-
const reauth = await ctx.ui.confirm(authMessages.login.reAuthPrompt);
|
|
19822
|
-
if (!reauth.ok || !reauth.value) {
|
|
19823
|
-
ctx.ui.info(authMessages.alreadyConfigured);
|
|
19824
|
-
return;
|
|
19825
|
-
}
|
|
19826
|
-
}
|
|
19827
|
-
ctx.ui.gap();
|
|
19828
|
-
ctx.ui.intro(authMessages.title);
|
|
20676
|
+
// src/commands/auth/loginApiKey.ts
|
|
20677
|
+
async function loginWithApiKey(ctx) {
|
|
19829
20678
|
const result = await ctx.ui.password(authMessages.promptApiKey, "Set QAWOLF_API_KEY to authenticate in non-interactive environments.");
|
|
19830
20679
|
if (!result.ok) {
|
|
19831
20680
|
ctx.ui.cancel(authMessages.cancelled);
|
|
19832
20681
|
return;
|
|
19833
20682
|
}
|
|
19834
|
-
|
|
20683
|
+
const apiKey = result.value.trim();
|
|
20684
|
+
if (!apiKey) {
|
|
19835
20685
|
ctx.ui.cancel(authMessages.cancelled);
|
|
19836
20686
|
return;
|
|
19837
20687
|
}
|
|
@@ -19840,7 +20690,7 @@ async function handleLogin(ctx) {
|
|
|
19840
20690
|
message: authMessages.verifying,
|
|
19841
20691
|
task: async () => {
|
|
19842
20692
|
const v = await validateApiKey({
|
|
19843
|
-
platformClient: createPlatformClient(
|
|
20693
|
+
platformClient: createPlatformClient(apiKey, {
|
|
19844
20694
|
baseUrl: ctx.apiBaseUrl,
|
|
19845
20695
|
fetch: globalThis.fetch
|
|
19846
20696
|
})
|
|
@@ -19851,7 +20701,7 @@ async function handleLogin(ctx) {
|
|
|
19851
20701
|
},
|
|
19852
20702
|
{
|
|
19853
20703
|
message: authMessages.storing,
|
|
19854
|
-
task: async () => saveApiKey(ctx.configDir,
|
|
20704
|
+
task: async () => saveApiKey(ctx.configDir, apiKey, ctx.fs)
|
|
19855
20705
|
}
|
|
19856
20706
|
], ([, saveResult]) => {
|
|
19857
20707
|
return saveResult.stored === "file" ? authMessages.storedFile : authMessages.storedKeychain;
|
|
@@ -19859,14 +20709,632 @@ async function handleLogin(ctx) {
|
|
|
19859
20709
|
ctx.ui.outro(authMessages.outroSuccess);
|
|
19860
20710
|
}
|
|
19861
20711
|
|
|
20712
|
+
// src/core/deviceAuth/pollState.ts
|
|
20713
|
+
var slowDownIncrementMs = 5000;
|
|
20714
|
+
var unreachableBackoffFactor = 2;
|
|
20715
|
+
function capToLifetime(delayMs, state, nowMs) {
|
|
20716
|
+
return Math.min(delayMs, Math.max(1, state.deadlineMs - nowMs));
|
|
20717
|
+
}
|
|
20718
|
+
function nextPollStep(state, response, nowMs) {
|
|
20719
|
+
if (response.kind === "tokens") {
|
|
20720
|
+
return { action: "done", tokens: response.tokens };
|
|
20721
|
+
}
|
|
20722
|
+
if (nowMs > state.deadlineMs) {
|
|
20723
|
+
return { action: "fail", reason: "timeout", detail: undefined };
|
|
20724
|
+
}
|
|
20725
|
+
switch (response.kind) {
|
|
20726
|
+
case "pending":
|
|
20727
|
+
return {
|
|
20728
|
+
action: "poll",
|
|
20729
|
+
delayMs: capToLifetime(state.intervalMs, state, nowMs),
|
|
20730
|
+
state
|
|
20731
|
+
};
|
|
20732
|
+
case "slow-down": {
|
|
20733
|
+
const slowed = {
|
|
20734
|
+
intervalMs: state.intervalMs + slowDownIncrementMs,
|
|
20735
|
+
deadlineMs: state.deadlineMs
|
|
20736
|
+
};
|
|
20737
|
+
return {
|
|
20738
|
+
action: "poll",
|
|
20739
|
+
delayMs: capToLifetime(slowed.intervalMs, slowed, nowMs),
|
|
20740
|
+
state: slowed
|
|
20741
|
+
};
|
|
20742
|
+
}
|
|
20743
|
+
case "denied":
|
|
20744
|
+
return { action: "fail", reason: "access-denied", detail: undefined };
|
|
20745
|
+
case "expired":
|
|
20746
|
+
return { action: "fail", reason: "expired", detail: undefined };
|
|
20747
|
+
case "unreachable": {
|
|
20748
|
+
const backedOff = {
|
|
20749
|
+
intervalMs: state.intervalMs * unreachableBackoffFactor,
|
|
20750
|
+
deadlineMs: state.deadlineMs
|
|
20751
|
+
};
|
|
20752
|
+
return {
|
|
20753
|
+
action: "poll",
|
|
20754
|
+
delayMs: capToLifetime(backedOff.intervalMs, backedOff, nowMs),
|
|
20755
|
+
state: backedOff
|
|
20756
|
+
};
|
|
20757
|
+
}
|
|
20758
|
+
case "error":
|
|
20759
|
+
return { action: "fail", reason: "network", detail: response.detail };
|
|
20760
|
+
}
|
|
20761
|
+
}
|
|
20762
|
+
|
|
20763
|
+
// src/domains/auth/deviceLogin.ts
|
|
20764
|
+
var cancelled = {
|
|
20765
|
+
ok: false,
|
|
20766
|
+
reason: "cancelled",
|
|
20767
|
+
detail: undefined
|
|
20768
|
+
};
|
|
20769
|
+
async function deviceLogin(deps) {
|
|
20770
|
+
if (deps.isCancelled())
|
|
20771
|
+
return cancelled;
|
|
20772
|
+
const authorization = await deps.requestAuthorization();
|
|
20773
|
+
if (!authorization.ok) {
|
|
20774
|
+
return { ok: false, reason: "unavailable", detail: authorization.error };
|
|
20775
|
+
}
|
|
20776
|
+
await deps.onPrompt(authorization.value);
|
|
20777
|
+
let state = {
|
|
20778
|
+
intervalMs: authorization.value.intervalSec * 1000,
|
|
20779
|
+
deadlineMs: deps.now() + authorization.value.expiresInSec * 1000
|
|
20780
|
+
};
|
|
20781
|
+
for (;; ) {
|
|
20782
|
+
if (deps.isCancelled())
|
|
20783
|
+
return cancelled;
|
|
20784
|
+
const response = await deps.pollToken(authorization.value.deviceCode);
|
|
20785
|
+
const step = nextPollStep(state, response, deps.now());
|
|
20786
|
+
if (step.action === "done")
|
|
20787
|
+
return { ok: true, tokens: step.tokens };
|
|
20788
|
+
if (step.action === "fail") {
|
|
20789
|
+
return { ok: false, reason: step.reason, detail: step.detail };
|
|
20790
|
+
}
|
|
20791
|
+
state = step.state;
|
|
20792
|
+
await deps.sleep(step.delayMs);
|
|
20793
|
+
}
|
|
20794
|
+
}
|
|
20795
|
+
|
|
20796
|
+
// src/shell/openBrowser.ts
|
|
20797
|
+
var launchTimeoutMs = 2000;
|
|
20798
|
+
function launcher(url, platform) {
|
|
20799
|
+
if (platform === "darwin")
|
|
20800
|
+
return { cmd: "open", args: [url] };
|
|
20801
|
+
if (platform === "win32") {
|
|
20802
|
+
return { cmd: "rundll32", args: ["url.dll,FileProtocolHandler", url] };
|
|
20803
|
+
}
|
|
20804
|
+
return { cmd: "xdg-open", args: [url] };
|
|
20805
|
+
}
|
|
20806
|
+
async function openBrowser(url, deps) {
|
|
20807
|
+
let parsed;
|
|
20808
|
+
try {
|
|
20809
|
+
parsed = new URL(url);
|
|
20810
|
+
} catch {
|
|
20811
|
+
return false;
|
|
20812
|
+
}
|
|
20813
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
20814
|
+
return false;
|
|
20815
|
+
}
|
|
20816
|
+
const { cmd, args } = launcher(url, deps.platform);
|
|
20817
|
+
const launched = deps.spawn(cmd, args, { platform: deps.platform }).then((result) => result.exitCode === 0).catch(() => false);
|
|
20818
|
+
return Promise.race([launched, deps.sleep(launchTimeoutMs).then(() => true)]);
|
|
20819
|
+
}
|
|
20820
|
+
|
|
20821
|
+
// src/shell/spawn.ts
|
|
20822
|
+
import { spawn } from "node:child_process";
|
|
20823
|
+
|
|
20824
|
+
// src/core/cmdEscape.ts
|
|
20825
|
+
var metaChars = /([()\][%!^"`<>&|;, *?])/g;
|
|
20826
|
+
function escapeCommand(command) {
|
|
20827
|
+
return command.replace(metaChars, "^$1");
|
|
20828
|
+
}
|
|
20829
|
+
function escapeArgument(arg) {
|
|
20830
|
+
const escaped = arg.replace(/(?=(\\+?)?)\1"/g, "$1$1\\\"").replace(/(?=(\\+?)?)\1$/, "$1$1");
|
|
20831
|
+
return `"${escaped}"`.replace(metaChars, "^$1").replace(metaChars, "^$1");
|
|
20832
|
+
}
|
|
20833
|
+
|
|
20834
|
+
// src/shell/spawn.ts
|
|
20835
|
+
function buildSpawnCommand(cmd, args, platform, env) {
|
|
20836
|
+
const options = {};
|
|
20837
|
+
if (env)
|
|
20838
|
+
options.env = env;
|
|
20839
|
+
if (platform !== "win32" || !/\.(cmd|bat)$/i.test(cmd)) {
|
|
20840
|
+
return { cmd, args, options };
|
|
20841
|
+
}
|
|
20842
|
+
const line = [escapeCommand(cmd), ...args.map(escapeArgument)].join(" ");
|
|
20843
|
+
return {
|
|
20844
|
+
cmd: process.env["ComSpec"] ?? "cmd.exe",
|
|
20845
|
+
args: ["/d", "/s", "/c", `"${line}"`],
|
|
20846
|
+
options: { ...options, windowsVerbatimArguments: true }
|
|
20847
|
+
};
|
|
20848
|
+
}
|
|
20849
|
+
var defaultSpawn = (cmd, args, opts) => new Promise((resolve) => {
|
|
20850
|
+
const env = opts.env ? { ...process.env, ...opts.env } : undefined;
|
|
20851
|
+
const built = buildSpawnCommand(cmd, args, opts.platform, env);
|
|
20852
|
+
const child = spawn(built.cmd, built.args, built.options);
|
|
20853
|
+
let stdout = "";
|
|
20854
|
+
let stderr = "";
|
|
20855
|
+
child.stdout?.on("data", (chunk) => {
|
|
20856
|
+
stdout += String(chunk);
|
|
20857
|
+
});
|
|
20858
|
+
child.stderr?.on("data", (chunk) => {
|
|
20859
|
+
stderr += String(chunk);
|
|
20860
|
+
});
|
|
20861
|
+
if (opts?.stdin !== undefined) {
|
|
20862
|
+
child.stdin?.write(opts.stdin);
|
|
20863
|
+
child.stdin?.end();
|
|
20864
|
+
}
|
|
20865
|
+
child.on("error", (err) => resolve({ exitCode: -1, stdout, stderr: stderr || err.message }));
|
|
20866
|
+
child.on("close", (code) => resolve({ exitCode: code ?? -1, stdout, stderr }));
|
|
20867
|
+
});
|
|
20868
|
+
|
|
20869
|
+
// src/shell/platform/getAuthConfig.ts
|
|
20870
|
+
var timeoutMs5 = 1e4;
|
|
20871
|
+
var authConfigBody = object({
|
|
20872
|
+
workOsClientId: string2().trim().min(1)
|
|
20873
|
+
});
|
|
20874
|
+
async function getAuthConfig(deps) {
|
|
20875
|
+
let response;
|
|
20876
|
+
try {
|
|
20877
|
+
response = await deps.fetch(`${deps.baseUrl}/api/v0/auth/config`, {
|
|
20878
|
+
signal: AbortSignal.timeout(timeoutMs5)
|
|
20879
|
+
});
|
|
20880
|
+
} catch (err) {
|
|
20881
|
+
return { kind: "unreachable", detail: errorMessage(err) };
|
|
20882
|
+
}
|
|
20883
|
+
if (response.status === 404)
|
|
20884
|
+
return { kind: "unconfigured" };
|
|
20885
|
+
if (!response.ok) {
|
|
20886
|
+
return { kind: "unreachable", detail: `HTTP ${response.status}` };
|
|
20887
|
+
}
|
|
20888
|
+
let json;
|
|
20889
|
+
try {
|
|
20890
|
+
json = await response.json();
|
|
20891
|
+
} catch (err) {
|
|
20892
|
+
return { kind: "unreachable", detail: errorMessage(err) };
|
|
20893
|
+
}
|
|
20894
|
+
const parsed = authConfigBody.safeParse(json);
|
|
20895
|
+
return parsed.success ? { kind: "configured", clientId: parsed.data.workOsClientId } : { kind: "unconfigured" };
|
|
20896
|
+
}
|
|
20897
|
+
|
|
20898
|
+
// src/shell/workos/pollDeviceToken.ts
|
|
20899
|
+
var deviceCodeGrantType = "urn:ietf:params:oauth:grant-type:device_code";
|
|
20900
|
+
async function pollDeviceToken(deviceCode, deps) {
|
|
20901
|
+
const outcome = await sendWorkosRequest(`${deps.baseUrl}/user_management/authenticate`, {
|
|
20902
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
20903
|
+
body: new URLSearchParams({
|
|
20904
|
+
grant_type: deviceCodeGrantType,
|
|
20905
|
+
device_code: deviceCode,
|
|
20906
|
+
client_id: deps.clientId
|
|
20907
|
+
}).toString()
|
|
20908
|
+
}, deps.fetch);
|
|
20909
|
+
if (outcome.kind === "failure") {
|
|
20910
|
+
return outcome.retryable ? { kind: "unreachable", detail: outcome.detail } : { kind: "error", detail: outcome.detail };
|
|
20911
|
+
}
|
|
20912
|
+
if (outcome.kind === "oauth-error") {
|
|
20913
|
+
switch (outcome.code) {
|
|
20914
|
+
case "authorization_pending":
|
|
20915
|
+
return { kind: "pending" };
|
|
20916
|
+
case "slow_down":
|
|
20917
|
+
return { kind: "slow-down" };
|
|
20918
|
+
case "access_denied":
|
|
20919
|
+
return { kind: "denied" };
|
|
20920
|
+
case "expired_token":
|
|
20921
|
+
case "invalid_grant":
|
|
20922
|
+
return { kind: "expired" };
|
|
20923
|
+
default:
|
|
20924
|
+
return {
|
|
20925
|
+
kind: "error",
|
|
20926
|
+
detail: outcome.description ?? outcome.code
|
|
20927
|
+
};
|
|
20928
|
+
}
|
|
20929
|
+
}
|
|
20930
|
+
const parsed = deviceTokenBody.safeParse(outcome.json);
|
|
20931
|
+
if (!parsed.success) {
|
|
20932
|
+
return { kind: "error", detail: unexpectedResponse };
|
|
20933
|
+
}
|
|
20934
|
+
return {
|
|
20935
|
+
kind: "tokens",
|
|
20936
|
+
tokens: {
|
|
20937
|
+
accessToken: parsed.data.access_token,
|
|
20938
|
+
refreshToken: parsed.data.refresh_token,
|
|
20939
|
+
expiresAt: readAccessTokenExpiry(parsed.data.access_token),
|
|
20940
|
+
email: parsed.data.user.email,
|
|
20941
|
+
organizationId: parsed.data.organization_id
|
|
20942
|
+
}
|
|
20943
|
+
};
|
|
20944
|
+
}
|
|
20945
|
+
|
|
20946
|
+
// src/shell/workos/requestDeviceAuthorization.ts
|
|
20947
|
+
async function requestDeviceAuthorization(deps) {
|
|
20948
|
+
const outcome = await sendWorkosRequest(`${deps.baseUrl}/user_management/authorize/device`, {
|
|
20949
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
20950
|
+
body: new URLSearchParams({ client_id: deps.clientId }).toString()
|
|
20951
|
+
}, deps.fetch);
|
|
20952
|
+
if (outcome.kind === "failure") {
|
|
20953
|
+
return { ok: false, error: outcome.detail, retryable: outcome.retryable };
|
|
20954
|
+
}
|
|
20955
|
+
if (outcome.kind === "oauth-error") {
|
|
20956
|
+
return {
|
|
20957
|
+
ok: false,
|
|
20958
|
+
error: outcome.description ?? outcome.code,
|
|
20959
|
+
retryable: false
|
|
20960
|
+
};
|
|
20961
|
+
}
|
|
20962
|
+
const parsed = deviceAuthorizationBody.safeParse(outcome.json);
|
|
20963
|
+
if (!parsed.success) {
|
|
20964
|
+
return { ok: false, error: unexpectedResponse, retryable: false };
|
|
20965
|
+
}
|
|
20966
|
+
return {
|
|
20967
|
+
ok: true,
|
|
20968
|
+
value: {
|
|
20969
|
+
deviceCode: parsed.data.device_code,
|
|
20970
|
+
userCode: parsed.data.user_code,
|
|
20971
|
+
verificationUri: parsed.data.verification_uri,
|
|
20972
|
+
verificationUriComplete: parsed.data.verification_uri_complete,
|
|
20973
|
+
expiresInSec: parsed.data.expires_in,
|
|
20974
|
+
intervalSec: parsed.data.interval ?? defaultIntervalSec
|
|
20975
|
+
}
|
|
20976
|
+
};
|
|
20977
|
+
}
|
|
20978
|
+
|
|
20979
|
+
// src/domains/auth/nameMatching.ts
|
|
20980
|
+
function matches(candidate, wanted) {
|
|
20981
|
+
return candidate.toLowerCase() === wanted.trim().toLowerCase();
|
|
20982
|
+
}
|
|
20983
|
+
function findOrganization(organizations, wanted) {
|
|
20984
|
+
return organizations.find((organization) => matches(organization.name, wanted) || matches(organization.id, wanted) || matches(organization.workOsOrganizationId, wanted));
|
|
20985
|
+
}
|
|
20986
|
+
function findWorkspace(workspaces, wanted) {
|
|
20987
|
+
return workspaces.find((workspace) => matches(workspace.name, wanted) || matches(workspace.id, wanted) || workspace.slug !== undefined && matches(workspace.slug, wanted));
|
|
20988
|
+
}
|
|
20989
|
+
function findWorkspaceAcross(organizations, wanted) {
|
|
20990
|
+
const hits = organizations.flatMap((organization) => {
|
|
20991
|
+
const workspace = findWorkspace(organization.workspaces, wanted);
|
|
20992
|
+
return workspace ? [{ organization, workspace }] : [];
|
|
20993
|
+
});
|
|
20994
|
+
const [only] = hits;
|
|
20995
|
+
if (!only)
|
|
20996
|
+
return { kind: "none" };
|
|
20997
|
+
if (hits.length > 1) {
|
|
20998
|
+
return {
|
|
20999
|
+
kind: "ambiguous",
|
|
21000
|
+
organizations: hits.map((h) => h.organization)
|
|
21001
|
+
};
|
|
21002
|
+
}
|
|
21003
|
+
return {
|
|
21004
|
+
kind: "found",
|
|
21005
|
+
organization: only.organization,
|
|
21006
|
+
workspace: only.workspace
|
|
21007
|
+
};
|
|
21008
|
+
}
|
|
21009
|
+
function nameList(items) {
|
|
21010
|
+
return items.map((item) => item.slug ?? item.name).join(", ");
|
|
21011
|
+
}
|
|
21012
|
+
|
|
21013
|
+
// src/domains/auth/selectWorkspace.ts
|
|
21014
|
+
async function selectWorkspace(deps) {
|
|
21015
|
+
const { organizations } = deps;
|
|
21016
|
+
if (organizations.length === 0)
|
|
21017
|
+
return { outcome: "none" };
|
|
21018
|
+
let organization;
|
|
21019
|
+
if (deps.preferredOrganization) {
|
|
21020
|
+
organization = findOrganization(organizations, deps.preferredOrganization);
|
|
21021
|
+
if (!organization) {
|
|
21022
|
+
return {
|
|
21023
|
+
outcome: "failed",
|
|
21024
|
+
error: `No organization matches '${deps.preferredOrganization}'. Available: ${nameList(organizations)}.`
|
|
21025
|
+
};
|
|
21026
|
+
}
|
|
21027
|
+
} else if (organizations.length === 1) {
|
|
21028
|
+
organization = organizations[0];
|
|
21029
|
+
} else if (deps.preferredWorkspace) {
|
|
21030
|
+
const match = findWorkspaceAcross(organizations, deps.preferredWorkspace);
|
|
21031
|
+
if (match.kind === "none") {
|
|
21032
|
+
return {
|
|
21033
|
+
outcome: "failed",
|
|
21034
|
+
error: `No workspace matches '${deps.preferredWorkspace}'. Available: ${nameList(organizations.flatMap((o) => o.workspaces))}.`
|
|
21035
|
+
};
|
|
21036
|
+
}
|
|
21037
|
+
if (match.kind === "ambiguous") {
|
|
21038
|
+
return {
|
|
21039
|
+
outcome: "failed",
|
|
21040
|
+
error: `More than one organization has a workspace matching '${deps.preferredWorkspace}': ${nameList(match.organizations)}. Set QAWOLF_ORGANIZATION to choose between them.`
|
|
21041
|
+
};
|
|
21042
|
+
}
|
|
21043
|
+
organization = match.organization;
|
|
21044
|
+
} else {
|
|
21045
|
+
organization = await deps.chooseOrganization(organizations);
|
|
21046
|
+
if (!organization)
|
|
21047
|
+
return { outcome: "cancelled" };
|
|
21048
|
+
}
|
|
21049
|
+
if (!organization)
|
|
21050
|
+
throw Error("organization was not settled");
|
|
21051
|
+
const { workspaces } = organization;
|
|
21052
|
+
if (workspaces.length === 0) {
|
|
21053
|
+
return {
|
|
21054
|
+
outcome: "failed",
|
|
21055
|
+
error: `Organization '${organization.name}' has no workspaces.`
|
|
21056
|
+
};
|
|
21057
|
+
}
|
|
21058
|
+
let workspace;
|
|
21059
|
+
if (deps.preferredWorkspace) {
|
|
21060
|
+
workspace = findWorkspace(workspaces, deps.preferredWorkspace);
|
|
21061
|
+
if (!workspace) {
|
|
21062
|
+
return {
|
|
21063
|
+
outcome: "failed",
|
|
21064
|
+
error: `No workspace matches '${deps.preferredWorkspace}' in ${organization.name}. Available: ${nameList(workspaces)}.`
|
|
21065
|
+
};
|
|
21066
|
+
}
|
|
21067
|
+
} else if (workspaces.length === 1) {
|
|
21068
|
+
workspace = workspaces[0];
|
|
21069
|
+
} else {
|
|
21070
|
+
workspace = await deps.chooseWorkspace(workspaces);
|
|
21071
|
+
if (!workspace)
|
|
21072
|
+
return { outcome: "cancelled" };
|
|
21073
|
+
}
|
|
21074
|
+
if (!workspace)
|
|
21075
|
+
throw Error("workspace was not settled");
|
|
21076
|
+
try {
|
|
21077
|
+
await deps.saveWorkspace(workspace.id);
|
|
21078
|
+
} catch (err) {
|
|
21079
|
+
return {
|
|
21080
|
+
outcome: "failed",
|
|
21081
|
+
error: authMessages.workspace.saveFailed(errorMessage(err))
|
|
21082
|
+
};
|
|
21083
|
+
}
|
|
21084
|
+
return { outcome: "selected", organization, workspace };
|
|
21085
|
+
}
|
|
21086
|
+
|
|
21087
|
+
// src/domains/auth/store/saveWorkspaceId.ts
|
|
21088
|
+
import { Entry as Entry6 } from "@napi-rs/keyring";
|
|
21089
|
+
function makeSaveWorkspaceIdDeps(configDir, fs) {
|
|
21090
|
+
return {
|
|
21091
|
+
loadTokens: () => loadTokens(configDir, { EntryClass: Entry6, fs }),
|
|
21092
|
+
saveTokens: (session) => saveTokens(configDir, session, fs)
|
|
21093
|
+
};
|
|
21094
|
+
}
|
|
21095
|
+
async function saveWorkspaceId(session, workspaceId, deps) {
|
|
21096
|
+
const current = await deps.loadTokens();
|
|
21097
|
+
if (!current.found || !isSameSession(current.tokens, session)) {
|
|
21098
|
+
throw Error(authMessages.workspace.sessionChanged);
|
|
21099
|
+
}
|
|
21100
|
+
return deps.saveTokens({ ...current.tokens, workspaceId });
|
|
21101
|
+
}
|
|
21102
|
+
function isSameSession(stored, captured) {
|
|
21103
|
+
return stored.email === captured.email && stored.organizationId === captured.organizationId;
|
|
21104
|
+
}
|
|
21105
|
+
|
|
21106
|
+
// src/commands/auth/chooseWorkspace.ts
|
|
21107
|
+
async function chooseWorkspace(ctx, args) {
|
|
21108
|
+
const client = createPlatformClient(args.session.accessToken, {
|
|
21109
|
+
baseUrl: ctx.apiBaseUrl,
|
|
21110
|
+
fetch: globalThis.fetch,
|
|
21111
|
+
logger: ctx.log("trpc")
|
|
21112
|
+
});
|
|
21113
|
+
const [identity, discovered] = await Promise.all([
|
|
21114
|
+
client.getIdentity(),
|
|
21115
|
+
client.getAccessibleOrganizations()
|
|
21116
|
+
]);
|
|
21117
|
+
let organizations;
|
|
21118
|
+
if (discovered.ok) {
|
|
21119
|
+
organizations = discovered.value;
|
|
21120
|
+
} else if (identity.ok) {
|
|
21121
|
+
organizations = "user" in identity.value ? identity.value.organizations : [];
|
|
21122
|
+
} else {
|
|
21123
|
+
return { outcome: "failed", error: identity.error };
|
|
21124
|
+
}
|
|
21125
|
+
return selectWorkspace({
|
|
21126
|
+
organizations,
|
|
21127
|
+
preferredOrganization: args.env["QAWOLF_ORGANIZATION"]?.trim(),
|
|
21128
|
+
preferredWorkspace: args.env["QAWOLF_WORKSPACE"]?.trim(),
|
|
21129
|
+
chooseOrganization: async (organizations) => {
|
|
21130
|
+
if (ctx.ui.mode !== "human")
|
|
21131
|
+
return;
|
|
21132
|
+
const picked = await ctx.ui.select(authMessages.workspace.chooseOrganization, organizations.map((organization) => ({
|
|
21133
|
+
value: organization.workOsOrganizationId,
|
|
21134
|
+
label: organization.name,
|
|
21135
|
+
hint: authMessages.workspace.workspaceCount(organization.workspaces.length)
|
|
21136
|
+
})));
|
|
21137
|
+
if (!picked.ok)
|
|
21138
|
+
return;
|
|
21139
|
+
return organizations.find((organization) => organization.workOsOrganizationId === picked.value);
|
|
21140
|
+
},
|
|
21141
|
+
chooseWorkspace: async (workspaces) => {
|
|
21142
|
+
if (ctx.ui.mode !== "human")
|
|
21143
|
+
return;
|
|
21144
|
+
const picked = await ctx.ui.select(authMessages.workspace.choose, workspaces.map((workspace) => ({
|
|
21145
|
+
value: workspace.id,
|
|
21146
|
+
label: workspace.name,
|
|
21147
|
+
...workspace.slug ? { hint: workspace.slug } : {}
|
|
21148
|
+
})));
|
|
21149
|
+
if (!picked.ok)
|
|
21150
|
+
return;
|
|
21151
|
+
return workspaces.find((workspace) => workspace.id === picked.value);
|
|
21152
|
+
},
|
|
21153
|
+
saveWorkspace: (workspaceId) => saveWorkspaceId(args.session, workspaceId, makeSaveWorkspaceIdDeps(ctx.configDir, ctx.fs))
|
|
21154
|
+
});
|
|
21155
|
+
}
|
|
21156
|
+
function reportWorkspace(ctx, result) {
|
|
21157
|
+
switch (result.outcome) {
|
|
21158
|
+
case "selected":
|
|
21159
|
+
ctx.ui.info(authMessages.workspace.working(result.organization.name, result.workspace.name));
|
|
21160
|
+
return;
|
|
21161
|
+
case "none":
|
|
21162
|
+
ctx.ui.info(authMessages.workspace.none);
|
|
21163
|
+
return;
|
|
21164
|
+
case "cancelled":
|
|
21165
|
+
if (ctx.ui.mode !== "human") {
|
|
21166
|
+
return { error: authMessages.workspace.nonInteractive };
|
|
21167
|
+
}
|
|
21168
|
+
ctx.ui.info(authMessages.workspace.cancelled);
|
|
21169
|
+
return;
|
|
21170
|
+
case "failed":
|
|
21171
|
+
return { error: result.error };
|
|
21172
|
+
}
|
|
21173
|
+
}
|
|
21174
|
+
|
|
21175
|
+
// src/commands/auth/loginDevice.ts
|
|
21176
|
+
async function loginWithDevice(ctx, deps = {}) {
|
|
21177
|
+
const authConfig = await getAuthConfig({
|
|
21178
|
+
baseUrl: ctx.apiBaseUrl,
|
|
21179
|
+
fetch: globalThis.fetch
|
|
21180
|
+
});
|
|
21181
|
+
if (authConfig.kind === "unreachable") {
|
|
21182
|
+
ctx.log("auth").debug(`auth config unreachable: ${authConfig.detail}`);
|
|
21183
|
+
return {
|
|
21184
|
+
error: authMessages.device.configUnreachable,
|
|
21185
|
+
errorBody: authConfig.detail
|
|
21186
|
+
};
|
|
21187
|
+
}
|
|
21188
|
+
const config = resolveWorkosConfig(authConfig.kind === "configured" ? authConfig.clientId : undefined);
|
|
21189
|
+
if (!config.configured) {
|
|
21190
|
+
return { error: authMessages.device.unavailable };
|
|
21191
|
+
}
|
|
21192
|
+
const workos = {
|
|
21193
|
+
fetch: globalThis.fetch,
|
|
21194
|
+
baseUrl: config.baseUrl,
|
|
21195
|
+
clientId: config.clientId
|
|
21196
|
+
};
|
|
21197
|
+
let cancelled = false;
|
|
21198
|
+
const unregister = ctx.signals.register(() => {
|
|
21199
|
+
cancelled = true;
|
|
21200
|
+
});
|
|
21201
|
+
const showCode = async (authorization) => {
|
|
21202
|
+
const url = authorization.verificationUriComplete ?? authorization.verificationUri;
|
|
21203
|
+
ctx.ui.note([
|
|
21204
|
+
authMessages.device.confirmCode(authorization.userCode),
|
|
21205
|
+
authMessages.device.visitUrl(url),
|
|
21206
|
+
url === authorization.verificationUri ? undefined : authMessages.device.visitUrlPlain(authorization.verificationUri)
|
|
21207
|
+
].filter((line) => Boolean(line)).join(`
|
|
21208
|
+
`), authMessages.title);
|
|
21209
|
+
const opened = await openBrowser(url, {
|
|
21210
|
+
sleep,
|
|
21211
|
+
spawn: defaultSpawn,
|
|
21212
|
+
platform: deps.platform ?? process.platform
|
|
21213
|
+
});
|
|
21214
|
+
if (!opened)
|
|
21215
|
+
ctx.ui.info(authMessages.device.openFailed(url));
|
|
21216
|
+
ctx.ui.step(authMessages.device.waiting);
|
|
21217
|
+
};
|
|
21218
|
+
try {
|
|
21219
|
+
const result = await deviceLogin({
|
|
21220
|
+
requestAuthorization: () => requestDeviceAuthorization(workos),
|
|
21221
|
+
pollToken: (deviceCode) => pollDeviceToken(deviceCode, workos),
|
|
21222
|
+
onPrompt: showCode,
|
|
21223
|
+
sleep,
|
|
21224
|
+
now: () => Date.now(),
|
|
21225
|
+
isCancelled: () => cancelled
|
|
21226
|
+
});
|
|
21227
|
+
if (!result.ok) {
|
|
21228
|
+
return {
|
|
21229
|
+
error: authMessages.device.failed[result.reason],
|
|
21230
|
+
...result.detail ? { errorBody: result.detail } : {}
|
|
21231
|
+
};
|
|
21232
|
+
}
|
|
21233
|
+
const session = {
|
|
21234
|
+
...result.tokens,
|
|
21235
|
+
workspaceId: undefined,
|
|
21236
|
+
clientId: config.clientId
|
|
21237
|
+
};
|
|
21238
|
+
await saveTokens(ctx.configDir, session, ctx.fs);
|
|
21239
|
+
const workspace = await chooseWorkspace(ctx, {
|
|
21240
|
+
session,
|
|
21241
|
+
env: deps.env ?? process.env
|
|
21242
|
+
});
|
|
21243
|
+
const failure = reportWorkspace(ctx, workspace);
|
|
21244
|
+
if (failure)
|
|
21245
|
+
return failure;
|
|
21246
|
+
ctx.ui.outro(authMessages.device.signedIn(result.tokens.email));
|
|
21247
|
+
return;
|
|
21248
|
+
} finally {
|
|
21249
|
+
unregister();
|
|
21250
|
+
}
|
|
21251
|
+
}
|
|
21252
|
+
|
|
21253
|
+
// src/commands/auth/login.ts
|
|
21254
|
+
var browserMethod = "browser";
|
|
21255
|
+
async function handleLogin(ctx, deps = {}) {
|
|
21256
|
+
if (ctx.ui.mode !== "human") {
|
|
21257
|
+
ctx.ui.error(authMessages.login.nonInteractive);
|
|
21258
|
+
return { error: "non-interactive" };
|
|
21259
|
+
}
|
|
21260
|
+
const resolveApiKey2 = deps.resolveApiKey ?? resolveApiKey;
|
|
21261
|
+
const existing = await resolveApiKey2(ctx.configDir, ctx.fs);
|
|
21262
|
+
if (existing) {
|
|
21263
|
+
const reauth = await ctx.ui.confirm(authMessages.login.reAuthPrompt);
|
|
21264
|
+
if (!reauth.ok || !reauth.value) {
|
|
21265
|
+
ctx.ui.info(authMessages.alreadyConfigured);
|
|
21266
|
+
return;
|
|
21267
|
+
}
|
|
21268
|
+
}
|
|
21269
|
+
ctx.ui.gap();
|
|
21270
|
+
ctx.ui.intro(authMessages.title);
|
|
21271
|
+
const method = await ctx.ui.select(authMessages.login.chooseMethod, [
|
|
21272
|
+
{
|
|
21273
|
+
value: browserMethod,
|
|
21274
|
+
label: authMessages.login.methodBrowser,
|
|
21275
|
+
hint: authMessages.login.methodBrowserHint
|
|
21276
|
+
},
|
|
21277
|
+
{
|
|
21278
|
+
value: "api-key",
|
|
21279
|
+
label: authMessages.login.methodApiKey,
|
|
21280
|
+
hint: authMessages.login.methodApiKeyHint
|
|
21281
|
+
}
|
|
21282
|
+
]);
|
|
21283
|
+
if (!method.ok) {
|
|
21284
|
+
ctx.ui.cancel(authMessages.cancelled);
|
|
21285
|
+
return;
|
|
21286
|
+
}
|
|
21287
|
+
if (method.value !== browserMethod) {
|
|
21288
|
+
return (deps.loginWithApiKey ?? loginWithApiKey)(ctx);
|
|
21289
|
+
}
|
|
21290
|
+
if (existing && existing.source !== "browser") {
|
|
21291
|
+
ctx.ui.warn(existing.source === "env" ? authMessages.login.apiKeyPrecedence.env : authMessages.login.apiKeyPrecedence.stored);
|
|
21292
|
+
}
|
|
21293
|
+
return (deps.loginWithDevice ?? loginWithDevice)(ctx);
|
|
21294
|
+
}
|
|
21295
|
+
|
|
21296
|
+
// src/domains/auth/store/deleteTokens.ts
|
|
21297
|
+
import { join as join14 } from "node:path";
|
|
21298
|
+
import { Entry as Entry7 } from "@napi-rs/keyring";
|
|
21299
|
+
function deleteFromKeychain2() {
|
|
21300
|
+
try {
|
|
21301
|
+
new Entry7(service, tokensAccount).deletePassword();
|
|
21302
|
+
return "deleted";
|
|
21303
|
+
} catch {
|
|
21304
|
+
return "unavailable";
|
|
21305
|
+
}
|
|
21306
|
+
}
|
|
21307
|
+
async function deleteFromFile2(configDir, fs) {
|
|
21308
|
+
try {
|
|
21309
|
+
await fs.unlink(join14(configDir, tokensFile));
|
|
21310
|
+
return "deleted";
|
|
21311
|
+
} catch (err) {
|
|
21312
|
+
if (isNoEntError(err))
|
|
21313
|
+
return "not-found";
|
|
21314
|
+
throw err;
|
|
21315
|
+
}
|
|
21316
|
+
}
|
|
21317
|
+
async function deleteTokens(configDir, fs) {
|
|
21318
|
+
const [keychain, file] = await Promise.all([
|
|
21319
|
+
Promise.resolve(deleteFromKeychain2()),
|
|
21320
|
+
deleteFromFile2(configDir, fs)
|
|
21321
|
+
]);
|
|
21322
|
+
return { keychain, file };
|
|
21323
|
+
}
|
|
21324
|
+
|
|
19862
21325
|
// src/commands/auth/logout.ts
|
|
19863
|
-
async function handleLogout(ctx) {
|
|
19864
|
-
const
|
|
19865
|
-
|
|
21326
|
+
async function handleLogout(ctx, deps = {}) {
|
|
21327
|
+
const hasStoredCredentials2 = deps.hasStoredCredentials ?? hasStoredCredentials;
|
|
21328
|
+
const deleteApiKey2 = deps.deleteApiKey ?? deleteApiKey;
|
|
21329
|
+
const deleteTokens2 = deps.deleteTokens ?? deleteTokens;
|
|
21330
|
+
const env = deps.env ?? process.env;
|
|
21331
|
+
const envKey = env["QAWOLF_API_KEY"]?.trim();
|
|
21332
|
+
const stored = await hasStoredCredentials2(ctx.configDir, ctx.fs);
|
|
21333
|
+
if (!envKey && !stored) {
|
|
19866
21334
|
ctx.ui.info(authMessages.logout.notAuthenticated);
|
|
19867
21335
|
return;
|
|
19868
21336
|
}
|
|
19869
|
-
if (
|
|
21337
|
+
if (envKey) {
|
|
19870
21338
|
ctx.ui.warn(authMessages.logout.envVarWarning);
|
|
19871
21339
|
}
|
|
19872
21340
|
if (ctx.ui.mode === "human") {
|
|
@@ -19881,7 +21349,12 @@ async function handleLogout(ctx) {
|
|
|
19881
21349
|
await ctx.ui.withProgress([
|
|
19882
21350
|
{
|
|
19883
21351
|
message: authMessages.logout.deleting,
|
|
19884
|
-
task: () =>
|
|
21352
|
+
task: async () => {
|
|
21353
|
+
await Promise.all([
|
|
21354
|
+
deleteApiKey2(ctx.configDir, ctx.fs),
|
|
21355
|
+
deleteTokens2(ctx.configDir, ctx.fs)
|
|
21356
|
+
]);
|
|
21357
|
+
}
|
|
19885
21358
|
}
|
|
19886
21359
|
], () => authMessages.logout.credentialsRemoved);
|
|
19887
21360
|
if (ctx.ui.mode === "human") {
|
|
@@ -19891,6 +21364,76 @@ async function handleLogout(ctx) {
|
|
|
19891
21364
|
}
|
|
19892
21365
|
}
|
|
19893
21366
|
|
|
21367
|
+
// src/domains/auth/refreshStoredSession.ts
|
|
21368
|
+
import { Entry as Entry8 } from "@napi-rs/keyring";
|
|
21369
|
+
function makeDefaultDeps2(fs) {
|
|
21370
|
+
return {
|
|
21371
|
+
loadTokens: (configDir) => loadTokens(configDir, { EntryClass: Entry8, fs }),
|
|
21372
|
+
resolveOauth: (configDir) => resolveOauthToken(configDir, makeOauthDeps(fs))
|
|
21373
|
+
};
|
|
21374
|
+
}
|
|
21375
|
+
async function refreshStoredSession(configDir, fs, deps) {
|
|
21376
|
+
const resolvedDeps = deps ?? makeDefaultDeps2(fs);
|
|
21377
|
+
const before = await resolvedDeps.loadTokens(configDir);
|
|
21378
|
+
if (!before.found)
|
|
21379
|
+
return { kind: "not-signed-in" };
|
|
21380
|
+
const renewed = await resolvedDeps.resolveOauth(configDir);
|
|
21381
|
+
if (!renewed)
|
|
21382
|
+
return { kind: "refresh-failed" };
|
|
21383
|
+
const after = await resolvedDeps.loadTokens(configDir);
|
|
21384
|
+
if (!after.found)
|
|
21385
|
+
return { kind: "refresh-failed" };
|
|
21386
|
+
if (after.tokens.accessToken !== renewed.key) {
|
|
21387
|
+
return { kind: "refresh-failed" };
|
|
21388
|
+
}
|
|
21389
|
+
return { kind: "session", session: after.tokens };
|
|
21390
|
+
}
|
|
21391
|
+
|
|
21392
|
+
// src/commands/auth/switchWorkspace.ts
|
|
21393
|
+
async function handleSwitchWorkspace(ctx, deps = {}) {
|
|
21394
|
+
const env = deps.env ?? process.env;
|
|
21395
|
+
const refreshStoredSession2 = deps.refreshStoredSession ?? refreshStoredSession;
|
|
21396
|
+
const preferred = env["QAWOLF_WORKSPACE"]?.trim() || env["QAWOLF_ORGANIZATION"]?.trim();
|
|
21397
|
+
if (ctx.ui.mode !== "human" && !preferred) {
|
|
21398
|
+
return { error: authMessages.workspace.nonInteractive };
|
|
21399
|
+
}
|
|
21400
|
+
const stored = await refreshStoredSession2(ctx.configDir, ctx.fs);
|
|
21401
|
+
if (stored.kind === "not-signed-in") {
|
|
21402
|
+
return { error: authMessages.workspace.notSignedIn };
|
|
21403
|
+
}
|
|
21404
|
+
if (stored.kind === "refresh-failed") {
|
|
21405
|
+
return { error: authMessages.workspace.sessionExpired };
|
|
21406
|
+
}
|
|
21407
|
+
ctx.ui.gap();
|
|
21408
|
+
ctx.ui.intro(authMessages.title);
|
|
21409
|
+
const result = await chooseWorkspace(ctx, {
|
|
21410
|
+
session: stored.session,
|
|
21411
|
+
env
|
|
21412
|
+
});
|
|
21413
|
+
const failure = reportWorkspace(ctx, result);
|
|
21414
|
+
if (failure)
|
|
21415
|
+
return failure;
|
|
21416
|
+
ctx.ui.outro(authMessages.outroReady);
|
|
21417
|
+
return;
|
|
21418
|
+
}
|
|
21419
|
+
|
|
21420
|
+
// src/commands/auth/whoamiTeam.ts
|
|
21421
|
+
function reportTeamIdentity(ctx, value, source) {
|
|
21422
|
+
const { team } = value;
|
|
21423
|
+
const teamUrl = team.slug ? new URL("/" + encodeURIComponent(team.slug), ctx.apiBaseUrl).toString() : undefined;
|
|
21424
|
+
if (ctx.ui.mode === "human") {
|
|
21425
|
+
ctx.ui.note(authMessages.whoami.teamNote({ team, teamUrl, source }), authMessages.whoamiAuthenticated);
|
|
21426
|
+
ctx.ui.outro(authMessages.outroReady);
|
|
21427
|
+
} else {
|
|
21428
|
+
ctx.ui.output({
|
|
21429
|
+
authenticated: true,
|
|
21430
|
+
source,
|
|
21431
|
+
team,
|
|
21432
|
+
teamUrl
|
|
21433
|
+
}, authMessages.whoami.authenticatedAs(team.name, source));
|
|
21434
|
+
}
|
|
21435
|
+
}
|
|
21436
|
+
|
|
19894
21437
|
// src/commands/auth/whoami.ts
|
|
19895
21438
|
async function handleWhoami(ctx, deps = {}) {
|
|
19896
21439
|
ctx.ui.gap();
|
|
@@ -19932,11 +21475,19 @@ async function handleWhoami(ctx, deps = {}) {
|
|
|
19932
21475
|
const { value } = identity;
|
|
19933
21476
|
if ("user" in value) {
|
|
19934
21477
|
const { organization, user } = value;
|
|
21478
|
+
const found = value.organizations.flatMap((candidate) => candidate.workspaces.map((workspace) => ({
|
|
21479
|
+
organization: candidate.name,
|
|
21480
|
+
workspace: workspace.name,
|
|
21481
|
+
id: workspace.id
|
|
21482
|
+
}))).find((entry) => entry.id === resolved.workspaceId);
|
|
21483
|
+
const activeWorkspace = resolved.workspaceId ? authMessages.whoami.activeWorkspace(resolved.workspaceId, found) : undefined;
|
|
19935
21484
|
if (ctx.ui.mode === "human") {
|
|
19936
21485
|
ctx.ui.note(authMessages.whoami.userNote({
|
|
19937
21486
|
organization,
|
|
19938
21487
|
source: resolved.source,
|
|
19939
|
-
user
|
|
21488
|
+
user,
|
|
21489
|
+
activeWorkspace,
|
|
21490
|
+
organizations: value.organizations
|
|
19940
21491
|
}), authMessages.whoamiAuthenticated);
|
|
19941
21492
|
ctx.ui.outro(authMessages.outroReady);
|
|
19942
21493
|
} else {
|
|
@@ -19944,7 +21495,9 @@ async function handleWhoami(ctx, deps = {}) {
|
|
|
19944
21495
|
authenticated: true,
|
|
19945
21496
|
organization,
|
|
19946
21497
|
source: resolved.source,
|
|
19947
|
-
user
|
|
21498
|
+
user,
|
|
21499
|
+
workspaceId: resolved.workspaceId,
|
|
21500
|
+
organizations: value.organizations
|
|
19948
21501
|
}, authMessages.whoami.authenticatedAs(user.email, resolved.source));
|
|
19949
21502
|
}
|
|
19950
21503
|
return;
|
|
@@ -19966,26 +21519,15 @@ async function handleWhoami(ctx, deps = {}) {
|
|
|
19966
21519
|
}
|
|
19967
21520
|
return;
|
|
19968
21521
|
}
|
|
19969
|
-
|
|
19970
|
-
const teamUrl = team.slug ? new URL("/" + encodeURIComponent(team.slug), ctx.apiBaseUrl).toString() : undefined;
|
|
19971
|
-
if (ctx.ui.mode === "human") {
|
|
19972
|
-
ctx.ui.note(authMessages.whoami.teamNote({ team, teamUrl, source: resolved.source }), authMessages.whoamiAuthenticated);
|
|
19973
|
-
ctx.ui.outro(authMessages.outroReady);
|
|
19974
|
-
} else {
|
|
19975
|
-
ctx.ui.output({
|
|
19976
|
-
authenticated: true,
|
|
19977
|
-
source: resolved.source,
|
|
19978
|
-
team,
|
|
19979
|
-
teamUrl
|
|
19980
|
-
}, authMessages.whoami.authenticatedAs(team.name, resolved.source));
|
|
19981
|
-
}
|
|
21522
|
+
reportTeamIdentity(ctx, value, resolved.source);
|
|
19982
21523
|
}
|
|
19983
21524
|
|
|
19984
21525
|
// src/commands/auth/index.ts
|
|
19985
21526
|
function registerAuthCommand(program, signals) {
|
|
19986
21527
|
const auth = program.command("auth").description("Manage authentication with QA Wolf");
|
|
19987
|
-
declareCommandKind(auth.command("login"), "local").description("Authenticate with
|
|
21528
|
+
declareCommandKind(auth.command("login"), "local").description("Authenticate with QA Wolf in a browser or with an API key").action(withContext(signals, handleLogin));
|
|
19988
21529
|
declareCommandKind(auth.command("logout"), "local").description("Remove stored credentials").action(withContext(signals, handleLogout));
|
|
21530
|
+
declareCommandKind(auth.command("switch"), "local").description("Choose which workspace to work in").action(withContext(signals, handleSwitchWorkspace));
|
|
19989
21531
|
declareCommandKind(auth.command("whoami"), "read").description("Show authentication status").action(withContext(signals, handleWhoami));
|
|
19990
21532
|
}
|
|
19991
21533
|
|
|
@@ -20035,11 +21577,11 @@ async function* batchMap(items, fn, size) {
|
|
|
20035
21577
|
}
|
|
20036
21578
|
|
|
20037
21579
|
// src/core/nodeModulesBins.ts
|
|
20038
|
-
import { join as
|
|
21580
|
+
import { join as join15 } from "node:path";
|
|
20039
21581
|
function nodeModulesBinCandidates(envDir, name, platform) {
|
|
20040
|
-
const binDir =
|
|
21582
|
+
const binDir = join15(envDir, "node_modules", ".bin");
|
|
20041
21583
|
const names = platform === "win32" ? [`${name}.cmd`, `${name}.exe`] : [name];
|
|
20042
|
-
return names.map((shim) =>
|
|
21584
|
+
return names.map((shim) => join15(binDir, shim));
|
|
20043
21585
|
}
|
|
20044
21586
|
function appiumCliCandidates(envDir, platform) {
|
|
20045
21587
|
return nodeModulesBinCandidates(envDir, "appium", platform);
|
|
@@ -20096,21 +21638,21 @@ async function checkUiautomator2(spawn, appiumBin, platform) {
|
|
|
20096
21638
|
}
|
|
20097
21639
|
|
|
20098
21640
|
// src/core/androidBins.ts
|
|
20099
|
-
import { join as
|
|
21641
|
+
import { join as join16 } from "node:path";
|
|
20100
21642
|
function withExeSuffix(name, platform) {
|
|
20101
21643
|
return platform === "win32" ? `${name}.exe` : name;
|
|
20102
21644
|
}
|
|
20103
21645
|
function emulatorBin(home, platform) {
|
|
20104
21646
|
const name = withExeSuffix("emulator", platform);
|
|
20105
|
-
return home ?
|
|
21647
|
+
return home ? join16(home, "emulator", name) : name;
|
|
20106
21648
|
}
|
|
20107
21649
|
function adbBin(home, platform) {
|
|
20108
21650
|
const name = withExeSuffix("adb", platform);
|
|
20109
|
-
return home ?
|
|
21651
|
+
return home ? join16(home, "platform-tools", name) : name;
|
|
20110
21652
|
}
|
|
20111
21653
|
function cmdlineToolsBin(home, name, platform) {
|
|
20112
21654
|
const file = platform === "win32" ? `${name}.bat` : name;
|
|
20113
|
-
return
|
|
21655
|
+
return join16(home, "cmdline-tools", "latest", "bin", file);
|
|
20114
21656
|
}
|
|
20115
21657
|
function sdkManagerBin(home, platform) {
|
|
20116
21658
|
return cmdlineToolsBin(home, "sdkmanager", platform);
|
|
@@ -20407,9 +21949,9 @@ async function checkNpmRegistry(deps) {
|
|
|
20407
21949
|
}
|
|
20408
21950
|
|
|
20409
21951
|
// src/core/playwrightCli.ts
|
|
20410
|
-
import { join as
|
|
21952
|
+
import { join as join17 } from "node:path";
|
|
20411
21953
|
function playwrightCliJsPath(envDir) {
|
|
20412
|
-
return
|
|
21954
|
+
return join17(envDir, "node_modules", "playwright", "cli.js");
|
|
20413
21955
|
}
|
|
20414
21956
|
function playwrightCliInvocation(args) {
|
|
20415
21957
|
return {
|
|
@@ -20559,11 +22101,11 @@ function renderResults(ui, results) {
|
|
|
20559
22101
|
}
|
|
20560
22102
|
|
|
20561
22103
|
// src/domains/flows/ensureDeps.ts
|
|
20562
|
-
import { dirname as dirname4, join as
|
|
22104
|
+
import { dirname as dirname4, join as join18 } from "node:path";
|
|
20563
22105
|
function findEnvDir(flowPath, fs) {
|
|
20564
22106
|
let dir = dirname4(flowPath);
|
|
20565
22107
|
while (true) {
|
|
20566
|
-
if (fs.existsSync(
|
|
22108
|
+
if (fs.existsSync(join18(dir, "package.json")))
|
|
20567
22109
|
return dir;
|
|
20568
22110
|
const parent = dirname4(dir);
|
|
20569
22111
|
if (parent === dir)
|
|
@@ -20589,7 +22131,7 @@ function resolveProjectDirSafe(files, fs) {
|
|
|
20589
22131
|
}
|
|
20590
22132
|
|
|
20591
22133
|
// src/domains/flows/expand.ts
|
|
20592
|
-
import { join as
|
|
22134
|
+
import { join as join19, resolve as resolve3 } from "node:path";
|
|
20593
22135
|
|
|
20594
22136
|
// node_modules/tinyglobby/dist/index.mjs
|
|
20595
22137
|
import { readdir, readdirSync, realpath, realpathSync, stat, statSync } from "fs";
|
|
@@ -21578,11 +23120,11 @@ function makePeekFlowMeta(fs) {
|
|
|
21578
23120
|
};
|
|
21579
23121
|
}
|
|
21580
23122
|
async function resolveGlobRoots(cwd, fs) {
|
|
21581
|
-
const qawolfPath =
|
|
23123
|
+
const qawolfPath = join19(cwd, ".qawolf");
|
|
21582
23124
|
let envDirs = [];
|
|
21583
23125
|
try {
|
|
21584
23126
|
const entries = await fs.readdirWithTypes(qawolfPath);
|
|
21585
|
-
envDirs = entries.filter((e) => e.isDirectory()).map((e) =>
|
|
23127
|
+
envDirs = entries.filter((e) => e.isDirectory()).map((e) => join19(qawolfPath, e.name));
|
|
21586
23128
|
} catch {}
|
|
21587
23129
|
return [cwd, ...envDirs];
|
|
21588
23130
|
}
|
|
@@ -21608,11 +23150,11 @@ async function expandPatterns(patterns, cwd, logger, fs) {
|
|
|
21608
23150
|
}
|
|
21609
23151
|
|
|
21610
23152
|
// src/domains/runtimeEnv/clearRuntimeEnv.ts
|
|
21611
|
-
import { join as
|
|
23153
|
+
import { join as join21 } from "node:path";
|
|
21612
23154
|
|
|
21613
23155
|
// src/domains/runtimeEnv/managedEnvDir.ts
|
|
21614
23156
|
import { createHash } from "node:crypto";
|
|
21615
|
-
import { join as
|
|
23157
|
+
import { join as join20, resolve as resolve4 } from "node:path";
|
|
21616
23158
|
|
|
21617
23159
|
// src/domains/runtimeEnv/pinnedPackages.ts
|
|
21618
23160
|
var pinnedPackages = [
|
|
@@ -21643,19 +23185,19 @@ function managedEnvBaseDir() {
|
|
|
21643
23185
|
const override = process.env["QAWOLF_RUNTIME_DIR"]?.trim();
|
|
21644
23186
|
if (override)
|
|
21645
23187
|
return resolve4(override);
|
|
21646
|
-
return
|
|
23188
|
+
return join20(getDataDir(), "runtime");
|
|
21647
23189
|
}
|
|
21648
23190
|
function runStagingRoot() {
|
|
21649
23191
|
return `${managedEnvBaseDir()}-runs`;
|
|
21650
23192
|
}
|
|
21651
23193
|
function managedEnvDir() {
|
|
21652
|
-
return
|
|
23194
|
+
return join20(managedEnvBaseDir(), managedEnvHash());
|
|
21653
23195
|
}
|
|
21654
23196
|
async function scaffoldManagedEnv(dir, fs) {
|
|
21655
23197
|
await fs.mkdir(dir, { recursive: true });
|
|
21656
23198
|
const dependencies = Object.fromEntries(pinnedPackages.map(({ name, version }) => [name, version]));
|
|
21657
|
-
await fs.writeFile(
|
|
21658
|
-
await fs.writeFile(
|
|
23199
|
+
await fs.writeFile(join20(dir, "package.json"), JSON.stringify({ name: "qawolf-runtime", private: true, dependencies }, undefined, 2));
|
|
23200
|
+
await fs.writeFile(join20(dir, ".npmrc"), `@qawolf:registry=https://registry.npmjs.org/
|
|
21659
23201
|
`);
|
|
21660
23202
|
}
|
|
21661
23203
|
|
|
@@ -21677,67 +23219,19 @@ async function isManagedRuntimeBase(dir, fs) {
|
|
|
21677
23219
|
for (const entry of entries) {
|
|
21678
23220
|
if (!entry.isDirectory())
|
|
21679
23221
|
return false;
|
|
21680
|
-
if (!await hasRuntimeSentinel(
|
|
23222
|
+
if (!await hasRuntimeSentinel(join21(dir, entry.name), fs))
|
|
21681
23223
|
return false;
|
|
21682
23224
|
}
|
|
21683
23225
|
return true;
|
|
21684
23226
|
}
|
|
21685
23227
|
async function hasRuntimeSentinel(hashDir, fs) {
|
|
21686
23228
|
try {
|
|
21687
|
-
const pkg = JSON.parse(await fs.readFile(
|
|
23229
|
+
const pkg = JSON.parse(await fs.readFile(join21(hashDir, "package.json")));
|
|
21688
23230
|
return pkg.name === runtimeSentinel;
|
|
21689
23231
|
} catch {
|
|
21690
23232
|
return false;
|
|
21691
23233
|
}
|
|
21692
23234
|
}
|
|
21693
|
-
// src/shell/spawn.ts
|
|
21694
|
-
import { spawn } from "node:child_process";
|
|
21695
|
-
|
|
21696
|
-
// src/core/cmdEscape.ts
|
|
21697
|
-
var metaChars = /([()\][%!^"`<>&|;, *?])/g;
|
|
21698
|
-
function escapeCommand(command) {
|
|
21699
|
-
return command.replace(metaChars, "^$1");
|
|
21700
|
-
}
|
|
21701
|
-
function escapeArgument(arg) {
|
|
21702
|
-
const escaped = arg.replace(/(?=(\\+?)?)\1"/g, "$1$1\\\"").replace(/(?=(\\+?)?)\1$/, "$1$1");
|
|
21703
|
-
return `"${escaped}"`.replace(metaChars, "^$1").replace(metaChars, "^$1");
|
|
21704
|
-
}
|
|
21705
|
-
|
|
21706
|
-
// src/shell/spawn.ts
|
|
21707
|
-
function buildSpawnCommand(cmd, args, platform, env) {
|
|
21708
|
-
const options = {};
|
|
21709
|
-
if (env)
|
|
21710
|
-
options.env = env;
|
|
21711
|
-
if (platform !== "win32" || !/\.(cmd|bat)$/i.test(cmd)) {
|
|
21712
|
-
return { cmd, args, options };
|
|
21713
|
-
}
|
|
21714
|
-
const line = [escapeCommand(cmd), ...args.map(escapeArgument)].join(" ");
|
|
21715
|
-
return {
|
|
21716
|
-
cmd: process.env["ComSpec"] ?? "cmd.exe",
|
|
21717
|
-
args: ["/d", "/s", "/c", `"${line}"`],
|
|
21718
|
-
options: { ...options, windowsVerbatimArguments: true }
|
|
21719
|
-
};
|
|
21720
|
-
}
|
|
21721
|
-
var defaultSpawn = (cmd, args, opts) => new Promise((resolve) => {
|
|
21722
|
-
const env = opts.env ? { ...process.env, ...opts.env } : undefined;
|
|
21723
|
-
const built = buildSpawnCommand(cmd, args, opts.platform, env);
|
|
21724
|
-
const child = spawn(built.cmd, built.args, built.options);
|
|
21725
|
-
let stdout = "";
|
|
21726
|
-
let stderr = "";
|
|
21727
|
-
child.stdout?.on("data", (chunk) => {
|
|
21728
|
-
stdout += String(chunk);
|
|
21729
|
-
});
|
|
21730
|
-
child.stderr?.on("data", (chunk) => {
|
|
21731
|
-
stderr += String(chunk);
|
|
21732
|
-
});
|
|
21733
|
-
if (opts?.stdin !== undefined) {
|
|
21734
|
-
child.stdin?.write(opts.stdin);
|
|
21735
|
-
child.stdin?.end();
|
|
21736
|
-
}
|
|
21737
|
-
child.on("error", (err) => resolve({ exitCode: -1, stdout, stderr: stderr || err.message }));
|
|
21738
|
-
child.on("close", (code) => resolve({ exitCode: code ?? -1, stdout, stderr }));
|
|
21739
|
-
});
|
|
21740
|
-
|
|
21741
23235
|
// src/domains/runtimeEnv/npmInstall.ts
|
|
21742
23236
|
function buildNpmInstallSpawn(cwd, platform) {
|
|
21743
23237
|
const built = buildSpawnCommand(resolveNpmCommand(platform), ["install", "--legacy-peer-deps"], platform, undefined);
|
|
@@ -21758,10 +23252,10 @@ function spawnNpmInstall(cwd, spawn2 = spawn) {
|
|
|
21758
23252
|
}
|
|
21759
23253
|
|
|
21760
23254
|
// src/domains/runtimeEnv/resolvePinned.ts
|
|
21761
|
-
import { join as
|
|
23255
|
+
import { join as join22 } from "node:path";
|
|
21762
23256
|
function readInstalledVersion(dir, pkgName, fs) {
|
|
21763
23257
|
try {
|
|
21764
|
-
const pkgPath =
|
|
23258
|
+
const pkgPath = join22(dir, "node_modules", ...pkgName.split("/"), "package.json");
|
|
21765
23259
|
const raw = JSON.parse(fs.readFileSync(pkgPath));
|
|
21766
23260
|
const { version } = raw;
|
|
21767
23261
|
return typeof version === "string" ? version : undefined;
|
|
@@ -21809,10 +23303,10 @@ function allPinnedResolved(dir, fs, platform) {
|
|
|
21809
23303
|
}
|
|
21810
23304
|
|
|
21811
23305
|
// src/domains/runtimeEnv/shimDeps.ts
|
|
21812
|
-
import { join as
|
|
23306
|
+
import { join as join24 } from "node:path";
|
|
21813
23307
|
|
|
21814
23308
|
// src/shell/resolveExport.ts
|
|
21815
|
-
import { join as
|
|
23309
|
+
import { join as join23 } from "node:path";
|
|
21816
23310
|
function pickPath(entry, preference) {
|
|
21817
23311
|
if (typeof entry === "string")
|
|
21818
23312
|
return entry;
|
|
@@ -21844,28 +23338,28 @@ function resolveFromEnvDir(envDir, specifier, preference = "esm", fs = makeDefau
|
|
|
21844
23338
|
const pkgName = parts.slice(0, pkgPartCount).join("/");
|
|
21845
23339
|
const rest = parts.slice(pkgPartCount);
|
|
21846
23340
|
const subpath = rest.length > 0 ? "./" + rest.join("/") : ".";
|
|
21847
|
-
const pkgDir =
|
|
23341
|
+
const pkgDir = join23(envDir, "node_modules", ...pkgName.split("/"));
|
|
21848
23342
|
let pkg;
|
|
21849
23343
|
try {
|
|
21850
|
-
pkg = JSON.parse(fs.readFileSync(
|
|
23344
|
+
pkg = JSON.parse(fs.readFileSync(join23(pkgDir, "package.json")));
|
|
21851
23345
|
} catch (err) {
|
|
21852
23346
|
if (isNoEntError(err))
|
|
21853
|
-
throw new Error(`Package '${pkgName}' not found in ${
|
|
23347
|
+
throw new Error(`Package '${pkgName}' not found in ${join23(envDir, "node_modules")}`, { cause: err });
|
|
21854
23348
|
throw err;
|
|
21855
23349
|
}
|
|
21856
23350
|
const exportsMap = normalizeExports(pkg.exports);
|
|
21857
23351
|
const entry = exportsMap?.[subpath];
|
|
21858
23352
|
const relative = pickPath(entry, preference) ?? (subpath === "." ? pkg.module ?? pkg.main : undefined);
|
|
21859
23353
|
if (!relative) {
|
|
21860
|
-
throw new Error(`No entry for "${subpath}" in exports of ${
|
|
23354
|
+
throw new Error(`No entry for "${subpath}" in exports of ${join23(pkgDir, "package.json")}`);
|
|
21861
23355
|
}
|
|
21862
|
-
return
|
|
23356
|
+
return join23(pkgDir, relative);
|
|
21863
23357
|
}
|
|
21864
23358
|
|
|
21865
23359
|
// src/domains/runtimeEnv/shimDeps.ts
|
|
21866
23360
|
function readShimMarker(shimDir, fs) {
|
|
21867
23361
|
try {
|
|
21868
|
-
const pkg = JSON.parse(fs.readFileSync(
|
|
23362
|
+
const pkg = JSON.parse(fs.readFileSync(join24(shimDir, "package.json")));
|
|
21869
23363
|
if (pkg._qawolf_format) {
|
|
21870
23364
|
return {
|
|
21871
23365
|
_qawolf_version: pkg._qawolf_version ?? "",
|
|
@@ -21881,11 +23375,11 @@ function resolveBunBuild(bunBuild) {
|
|
|
21881
23375
|
return bunBuild === false ? undefined : { build: bunBuild };
|
|
21882
23376
|
}
|
|
21883
23377
|
async function removeStaleShims(flowsDir, flowsDeps, fs) {
|
|
21884
|
-
const shimsDir =
|
|
23378
|
+
const shimsDir = join24(flowsDir, "node_modules");
|
|
21885
23379
|
if (!fs.existsSync(shimsDir))
|
|
21886
23380
|
return;
|
|
21887
23381
|
for (const dep of flowsDeps) {
|
|
21888
|
-
const shimDepDir =
|
|
23382
|
+
const shimDepDir = join24(shimsDir, ...dep.split("/"));
|
|
21889
23383
|
if (readShimMarker(shimDepDir, fs)) {
|
|
21890
23384
|
await fs.rm(shimDepDir, { recursive: true, force: true });
|
|
21891
23385
|
}
|
|
@@ -21894,17 +23388,17 @@ async function removeStaleShims(flowsDir, flowsDeps, fs) {
|
|
|
21894
23388
|
async function buildDepShim(args) {
|
|
21895
23389
|
const { envDir, flowsDir, dep, fs, build } = args;
|
|
21896
23390
|
const depParts = dep.split("/");
|
|
21897
|
-
const depDir =
|
|
23391
|
+
const depDir = join24(envDir, "node_modules", ...depParts);
|
|
21898
23392
|
if (!fs.existsSync(depDir))
|
|
21899
23393
|
return;
|
|
21900
23394
|
let depVersion;
|
|
21901
23395
|
try {
|
|
21902
|
-
const pkg = JSON.parse(fs.readFileSync(
|
|
23396
|
+
const pkg = JSON.parse(fs.readFileSync(join24(depDir, "package.json")));
|
|
21903
23397
|
depVersion = pkg.version ?? "unknown";
|
|
21904
23398
|
} catch {
|
|
21905
23399
|
depVersion = "unknown";
|
|
21906
23400
|
}
|
|
21907
|
-
const shimDir =
|
|
23401
|
+
const shimDir = join24(flowsDir, "node_modules", ...depParts);
|
|
21908
23402
|
if (fs.existsSync(shimDir)) {
|
|
21909
23403
|
const marker = readShimMarker(shimDir, fs);
|
|
21910
23404
|
if (!marker)
|
|
@@ -21931,20 +23425,20 @@ async function buildDepShim(args) {
|
|
|
21931
23425
|
}
|
|
21932
23426
|
const shimCode = await output.text();
|
|
21933
23427
|
await fs.mkdir(shimDir, { recursive: true });
|
|
21934
|
-
await fs.writeFile(
|
|
23428
|
+
await fs.writeFile(join24(shimDir, "package.json"), JSON.stringify({
|
|
21935
23429
|
name: dep,
|
|
21936
23430
|
_qawolf_version: depVersion,
|
|
21937
23431
|
_qawolf_format: "bun-build-v1"
|
|
21938
23432
|
}));
|
|
21939
|
-
await fs.writeFile(
|
|
23433
|
+
await fs.writeFile(join24(shimDir, "index.js"), shimCode);
|
|
21940
23434
|
}
|
|
21941
23435
|
async function shimFlowsDeps(envDir, fs = makeDefaultFs(), bunBuild) {
|
|
21942
|
-
const flowsDir =
|
|
23436
|
+
const flowsDir = join24(envDir, "node_modules", "@qawolf", "flows");
|
|
21943
23437
|
if (!fs.existsSync(flowsDir))
|
|
21944
23438
|
return;
|
|
21945
23439
|
let flowsDeps;
|
|
21946
23440
|
try {
|
|
21947
|
-
const flowsPkg = JSON.parse(fs.readFileSync(
|
|
23441
|
+
const flowsPkg = JSON.parse(fs.readFileSync(join24(flowsDir, "package.json")));
|
|
21948
23442
|
flowsDeps = Object.keys(flowsPkg.dependencies ?? {});
|
|
21949
23443
|
} catch {
|
|
21950
23444
|
return;
|
|
@@ -22125,11 +23619,11 @@ function collectValue(value, previous) {
|
|
|
22125
23619
|
}
|
|
22126
23620
|
|
|
22127
23621
|
// src/shell/manifest/pulledEnv.ts
|
|
22128
|
-
import { join as
|
|
23622
|
+
import { join as join26 } from "node:path";
|
|
22129
23623
|
|
|
22130
23624
|
// src/shell/manifest/io.ts
|
|
22131
23625
|
import { createHash as createHash2 } from "node:crypto";
|
|
22132
|
-
import { join as
|
|
23626
|
+
import { join as join25 } from "node:path";
|
|
22133
23627
|
var manifestFilename = ".manifest.json";
|
|
22134
23628
|
var flowEntrySchema = object({
|
|
22135
23629
|
path: string2(),
|
|
@@ -22151,7 +23645,7 @@ var manifestSchema = object({
|
|
|
22151
23645
|
async function readManifest(envDir, fs = makeDefaultFs()) {
|
|
22152
23646
|
let raw;
|
|
22153
23647
|
try {
|
|
22154
|
-
raw = await fs.readFile(
|
|
23648
|
+
raw = await fs.readFile(join25(envDir, manifestFilename));
|
|
22155
23649
|
} catch (err) {
|
|
22156
23650
|
if (isNoEntError(err))
|
|
22157
23651
|
return "missing";
|
|
@@ -22185,7 +23679,7 @@ async function readManifest(envDir, fs = makeDefaultFs()) {
|
|
|
22185
23679
|
}
|
|
22186
23680
|
async function writeManifest(envDir, manifest, fs = makeDefaultFs()) {
|
|
22187
23681
|
const body = JSON.stringify(manifest, undefined, 2);
|
|
22188
|
-
await fs.writeFile(
|
|
23682
|
+
await fs.writeFile(join25(envDir, manifestFilename), `${body}
|
|
22189
23683
|
`);
|
|
22190
23684
|
}
|
|
22191
23685
|
function hashFile(absPath, fs = makeDefaultFs()) {
|
|
@@ -22211,7 +23705,7 @@ async function findPulledEnv(ref, cwd, fs = makeDefaultFs()) {
|
|
|
22211
23705
|
return;
|
|
22212
23706
|
}
|
|
22213
23707
|
async function listPulledEnvDirs(cwd, fs = makeDefaultFs()) {
|
|
22214
|
-
const root =
|
|
23708
|
+
const root = join26(cwd, ".qawolf");
|
|
22215
23709
|
let entries;
|
|
22216
23710
|
try {
|
|
22217
23711
|
entries = await fs.readdirWithTypes(root);
|
|
@@ -22224,7 +23718,7 @@ async function listPulledEnvDirs(cwd, fs = makeDefaultFs()) {
|
|
|
22224
23718
|
for (const entry of entries) {
|
|
22225
23719
|
if (!entry.isDirectory())
|
|
22226
23720
|
continue;
|
|
22227
|
-
const envDir =
|
|
23721
|
+
const envDir = join26(root, entry.name);
|
|
22228
23722
|
const manifest = await readManifest(envDir, fs);
|
|
22229
23723
|
if (typeof manifest === "string")
|
|
22230
23724
|
continue;
|
|
@@ -22278,9 +23772,6 @@ async function readEnvLabels(files, readEnvLabel) {
|
|
|
22278
23772
|
}
|
|
22279
23773
|
|
|
22280
23774
|
// src/core/suggestNearMiss.ts
|
|
22281
|
-
function normalize3(value) {
|
|
22282
|
-
return value.toLowerCase().replace(/[-_\s]+/g, " ").trim();
|
|
22283
|
-
}
|
|
22284
23775
|
function editDistance(a, b) {
|
|
22285
23776
|
let row = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
22286
23777
|
for (let i = 1;i <= a.length; i += 1) {
|
|
@@ -22302,14 +23793,14 @@ function suggestNearMiss(input, candidates) {
|
|
|
22302
23793
|
if (candidates.includes(input))
|
|
22303
23794
|
return;
|
|
22304
23795
|
const sorted = [...candidates].sort();
|
|
22305
|
-
const normalizedInput =
|
|
22306
|
-
const presentationMatch = sorted.find((candidate) =>
|
|
23796
|
+
const normalizedInput = normalizeForSearch(input);
|
|
23797
|
+
const presentationMatch = sorted.find((candidate) => normalizeForSearch(candidate) === normalizedInput);
|
|
22307
23798
|
if (presentationMatch !== undefined)
|
|
22308
23799
|
return presentationMatch;
|
|
22309
23800
|
let best;
|
|
22310
23801
|
let bestDistance = Number.POSITIVE_INFINITY;
|
|
22311
23802
|
for (const candidate of sorted) {
|
|
22312
|
-
const distance = editDistance(normalizedInput,
|
|
23803
|
+
const distance = editDistance(normalizedInput, normalizeForSearch(candidate));
|
|
22313
23804
|
if (distance < bestDistance) {
|
|
22314
23805
|
bestDistance = distance;
|
|
22315
23806
|
best = candidate;
|
|
@@ -22619,7 +24110,7 @@ async function flowsListRemote(ctx, pattern, options) {
|
|
|
22619
24110
|
}
|
|
22620
24111
|
|
|
22621
24112
|
// src/domains/flows/pull/handler.ts
|
|
22622
|
-
import { dirname as dirname8, join as
|
|
24113
|
+
import { dirname as dirname8, join as join31, resolve as resolve8 } from "node:path";
|
|
22623
24114
|
|
|
22624
24115
|
// src/domains/flows/pull/fetchPhase.ts
|
|
22625
24116
|
async function fetchTags(ctx, envId) {
|
|
@@ -22763,7 +24254,7 @@ async function checkSafety(args) {
|
|
|
22763
24254
|
}
|
|
22764
24255
|
|
|
22765
24256
|
// src/domains/flows/pull/reportPull.ts
|
|
22766
|
-
import { join as
|
|
24257
|
+
import { join as join27 } from "node:path";
|
|
22767
24258
|
function reportPullResult(ui, args) {
|
|
22768
24259
|
if (ui.mode !== "json")
|
|
22769
24260
|
return;
|
|
@@ -22778,12 +24269,12 @@ function reportPullResult(ui, args) {
|
|
|
22778
24269
|
assetDownloadedCount: args.assets.downloadedCount,
|
|
22779
24270
|
assetReusedCount: args.assets.reusedCount,
|
|
22780
24271
|
assetSkippedCount: args.assets.skippedCount,
|
|
22781
|
-
manifestPath:
|
|
24272
|
+
manifestPath: join27(args.stage.envDir, manifestFilename)
|
|
22782
24273
|
}, "");
|
|
22783
24274
|
}
|
|
22784
24275
|
|
|
22785
24276
|
// src/domains/flows/pull/bundle.ts
|
|
22786
|
-
import { join as
|
|
24277
|
+
import { join as join28, relative as relative6 } from "node:path";
|
|
22787
24278
|
async function flattenSingleWrapper(dir, fs = makeDefaultFs()) {
|
|
22788
24279
|
const entries = await fs.readdir(dir);
|
|
22789
24280
|
if (entries.length !== 1)
|
|
@@ -22791,12 +24282,12 @@ async function flattenSingleWrapper(dir, fs = makeDefaultFs()) {
|
|
|
22791
24282
|
const innerName = entries[0];
|
|
22792
24283
|
if (!innerName)
|
|
22793
24284
|
return;
|
|
22794
|
-
const inner =
|
|
24285
|
+
const inner = join28(dir, innerName);
|
|
22795
24286
|
const innerStat = await fs.stat(inner);
|
|
22796
24287
|
if (!innerStat.isDirectory())
|
|
22797
24288
|
return;
|
|
22798
24289
|
for (const e of await fs.readdir(inner)) {
|
|
22799
|
-
await fs.rename(
|
|
24290
|
+
await fs.rename(join28(inner, e), join28(dir, e));
|
|
22800
24291
|
}
|
|
22801
24292
|
const leftovers = await fs.readdir(inner);
|
|
22802
24293
|
if (leftovers.length > 0) {
|
|
@@ -22815,7 +24306,7 @@ async function buildManifest(args, fs = makeDefaultFs()) {
|
|
|
22815
24306
|
const flowPaths = await walkForFlows(args.bundleDir, fs);
|
|
22816
24307
|
const flows = await Promise.all(flowPaths.map(async (rel) => ({
|
|
22817
24308
|
path: toPosix(rel),
|
|
22818
|
-
contentHash: await hashFile(
|
|
24309
|
+
contentHash: await hashFile(join28(args.bundleDir, rel), fs),
|
|
22819
24310
|
tags: args.tags?.byPath.get(toPosix(rel))
|
|
22820
24311
|
})));
|
|
22821
24312
|
return {
|
|
@@ -22839,7 +24330,7 @@ async function walkForFlows(root, fs) {
|
|
|
22839
24330
|
async function walk(current, root, out, fs) {
|
|
22840
24331
|
const entries = await fs.readdirWithTypes(current);
|
|
22841
24332
|
for (const e of entries) {
|
|
22842
|
-
const abs =
|
|
24333
|
+
const abs = join28(current, e.name);
|
|
22843
24334
|
if (e.isDirectory()) {
|
|
22844
24335
|
await walk(abs, root, out, fs);
|
|
22845
24336
|
} else if (e.isFile() && flowExtensions.some((ext) => e.name.endsWith(ext))) {
|
|
@@ -22852,11 +24343,11 @@ async function sampleQawolfCommittedAt(bundleDir, fs = makeDefaultFs()) {
|
|
|
22852
24343
|
const sample = flowPaths[0];
|
|
22853
24344
|
if (!sample)
|
|
22854
24345
|
return;
|
|
22855
|
-
return (await fs.stat(
|
|
24346
|
+
return (await fs.stat(join28(bundleDir, sample))).mtime.toISOString();
|
|
22856
24347
|
}
|
|
22857
24348
|
|
|
22858
24349
|
// src/domains/flows/pull/applyTeamStorageRewrite.ts
|
|
22859
|
-
import { join as
|
|
24350
|
+
import { join as join29, relative as relative7 } from "node:path";
|
|
22860
24351
|
|
|
22861
24352
|
// src/domains/flows/pull/rewriteTeamStorage.ts
|
|
22862
24353
|
var runnerMountPrefix = "/home/wolf/team-storage/";
|
|
@@ -22892,7 +24383,7 @@ function isFlowFile(name) {
|
|
|
22892
24383
|
async function walk2(dir, out, fs) {
|
|
22893
24384
|
const entries = await fs.readdirWithTypes(dir);
|
|
22894
24385
|
for (const e of entries) {
|
|
22895
|
-
const abs =
|
|
24386
|
+
const abs = join29(dir, e.name);
|
|
22896
24387
|
if (e.isDirectory()) {
|
|
22897
24388
|
await walk2(abs, out, fs);
|
|
22898
24389
|
} else if (e.isFile() && isSourceFile(e.name)) {
|
|
@@ -22920,7 +24411,7 @@ async function applyTeamStorageRewrite(rootDir, fs = makeDefaultFs()) {
|
|
|
22920
24411
|
}
|
|
22921
24412
|
|
|
22922
24413
|
// src/domains/flows/pull/envVars.ts
|
|
22923
|
-
import { join as
|
|
24414
|
+
import { join as join30 } from "node:path";
|
|
22924
24415
|
|
|
22925
24416
|
// src/core/dotenv.ts
|
|
22926
24417
|
var bareKeyPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -22985,7 +24476,7 @@ function unquote(escaped) {
|
|
|
22985
24476
|
async function writeEnvFile(envDir, vars, fs = makeDefaultFs()) {
|
|
22986
24477
|
if (Object.keys(vars).length === 0)
|
|
22987
24478
|
return;
|
|
22988
|
-
await fs.writeFile(
|
|
24479
|
+
await fs.writeFile(join30(envDir, ".env"), serializeDotenv(vars), {
|
|
22989
24480
|
mode: 384
|
|
22990
24481
|
});
|
|
22991
24482
|
}
|
|
@@ -23049,11 +24540,11 @@ var Ae = Symbol("flush");
|
|
|
23049
24540
|
var As = Symbol("flushChunk");
|
|
23050
24541
|
var z = Symbol("encoding");
|
|
23051
24542
|
var Mt = Symbol("decoder");
|
|
23052
|
-
var
|
|
24543
|
+
var g2 = Symbol("flowing");
|
|
23053
24544
|
var Qt = Symbol("paused");
|
|
23054
24545
|
var Bt = Symbol("resume");
|
|
23055
24546
|
var b = Symbol("buffer");
|
|
23056
|
-
var
|
|
24547
|
+
var N2 = Symbol("pipes");
|
|
23057
24548
|
var _ = Symbol("bufferLength");
|
|
23058
24549
|
var bi = Symbol("bufferPush");
|
|
23059
24550
|
var Ie = Symbol("bufferShift");
|
|
@@ -23101,9 +24592,9 @@ var Li = class extends Fe {
|
|
|
23101
24592
|
var Xr = (s) => !!s.objectMode;
|
|
23102
24593
|
var qr = (s) => !s.objectMode && !!s.encoding && s.encoding !== "buffer";
|
|
23103
24594
|
var A2 = class extends Di {
|
|
23104
|
-
[
|
|
24595
|
+
[g2] = false;
|
|
23105
24596
|
[Qt] = false;
|
|
23106
|
-
[
|
|
24597
|
+
[N2] = [];
|
|
23107
24598
|
[b] = [];
|
|
23108
24599
|
[L];
|
|
23109
24600
|
[z];
|
|
@@ -23126,7 +24617,7 @@ var A2 = class extends Di {
|
|
|
23126
24617
|
let e = t[0] || {};
|
|
23127
24618
|
if (super(), e.objectMode && typeof e.encoding == "string")
|
|
23128
24619
|
throw new TypeError("Encoding and objectMode may not be used together");
|
|
23129
|
-
Xr(e) ? (this[L] = true, this[z] = null) : qr(e) ? (this[z] = e.encoding, this[L] = false) : (this[L] = false, this[z] = null), this[Z] = !!e.async, this[Mt] = this[z] ? new Hr(this[z]) : null, e && e.debugExposeBuffer === true && Object.defineProperty(this, "buffer", { get: () => this[b] }), e && e.debugExposePipes === true && Object.defineProperty(this, "pipes", { get: () => this[
|
|
24620
|
+
Xr(e) ? (this[L] = true, this[z] = null) : qr(e) ? (this[z] = e.encoding, this[L] = false) : (this[L] = false, this[z] = null), this[Z] = !!e.async, this[Mt] = this[z] ? new Hr(this[z]) : null, e && e.debugExposeBuffer === true && Object.defineProperty(this, "buffer", { get: () => this[b] }), e && e.debugExposePipes === true && Object.defineProperty(this, "pipes", { get: () => this[N2] });
|
|
23130
24621
|
let { signal: i } = e;
|
|
23131
24622
|
i && (this[Jt] = i, i.aborted ? this[xi]() : i.addEventListener("abort", () => this[xi]()));
|
|
23132
24623
|
}
|
|
@@ -23178,7 +24669,7 @@ var A2 = class extends Di {
|
|
|
23178
24669
|
else if (typeof t != "string")
|
|
23179
24670
|
throw new Error("Non-contiguous data written to non-objectMode stream");
|
|
23180
24671
|
}
|
|
23181
|
-
return this[L] ? (this[
|
|
24672
|
+
return this[L] ? (this[g2] && this[_] !== 0 && this[Ae](true), this[g2] ? this.emit("data", t) : this[bi](t), this[_] !== 0 && this.emit("readable"), i && r(i), this[g2]) : t.length ? (typeof t == "string" && !(e === this[z] && !this[Mt]?.lastNeed) && (t = Buffer.from(t, e)), Buffer.isBuffer(t) && this[z] && (t = this[Mt].write(t)), this[g2] && this[_] !== 0 && this[Ae](true), this[g2] ? this.emit("data", t) : this[bi](t), this[_] !== 0 && this.emit("readable"), i && r(i), this[g2]) : (this[_] !== 0 && this.emit("readable"), i && r(i), this[g2]);
|
|
23182
24673
|
}
|
|
23183
24674
|
read(t) {
|
|
23184
24675
|
if (this[S])
|
|
@@ -23199,22 +24690,22 @@ var A2 = class extends Di {
|
|
|
23199
24690
|
return this.emit("data", e), !this[b].length && !this[Q] && this.emit("drain"), e;
|
|
23200
24691
|
}
|
|
23201
24692
|
end(t, e, i) {
|
|
23202
|
-
return typeof t == "function" && (i = t, t = undefined), typeof e == "function" && (i = e, e = "utf8"), t !== undefined && this.write(t, e), i && this.once("end", i), this[Q] = true, this.writable = false, (this[
|
|
24693
|
+
return typeof t == "function" && (i = t, t = undefined), typeof e == "function" && (i = e, e = "utf8"), t !== undefined && this.write(t, e), i && this.once("end", i), this[Q] = true, this.writable = false, (this[g2] || !this[Qt]) && this[J](), this;
|
|
23203
24694
|
}
|
|
23204
24695
|
[Bt]() {
|
|
23205
|
-
this[S] || (!this[Rt] && !this[
|
|
24696
|
+
this[S] || (!this[Rt] && !this[N2].length && (this[C2] = true), this[Qt] = false, this[g2] = true, this.emit("resume"), this[b].length ? this[Ae]() : this[Q] ? this[J]() : this.emit("drain"));
|
|
23206
24697
|
}
|
|
23207
24698
|
resume() {
|
|
23208
24699
|
return this[Bt]();
|
|
23209
24700
|
}
|
|
23210
24701
|
pause() {
|
|
23211
|
-
this[
|
|
24702
|
+
this[g2] = false, this[Qt] = true, this[C2] = false;
|
|
23212
24703
|
}
|
|
23213
24704
|
get destroyed() {
|
|
23214
24705
|
return this[S];
|
|
23215
24706
|
}
|
|
23216
24707
|
get flowing() {
|
|
23217
|
-
return this[
|
|
24708
|
+
return this[g2];
|
|
23218
24709
|
}
|
|
23219
24710
|
get paused() {
|
|
23220
24711
|
return this[Qt];
|
|
@@ -23232,18 +24723,18 @@ var A2 = class extends Di {
|
|
|
23232
24723
|
!t && !this[b].length && !this[Q] && this.emit("drain");
|
|
23233
24724
|
}
|
|
23234
24725
|
[As](t) {
|
|
23235
|
-
return this.emit("data", t), this[
|
|
24726
|
+
return this.emit("data", t), this[g2];
|
|
23236
24727
|
}
|
|
23237
24728
|
pipe(t, e) {
|
|
23238
24729
|
if (this[S])
|
|
23239
24730
|
return t;
|
|
23240
24731
|
this[C2] = false;
|
|
23241
24732
|
let i = this[nt];
|
|
23242
|
-
return e = e || {}, t === Ds.stdout || t === Ds.stderr ? e.end = false : e.end = e.end !== false, e.proxyErrors = !!e.proxyErrors, i ? e.end && t.end() : (this[
|
|
24733
|
+
return e = e || {}, t === Ds.stdout || t === Ds.stderr ? e.end = false : e.end = e.end !== false, e.proxyErrors = !!e.proxyErrors, i ? e.end && t.end() : (this[N2].push(e.proxyErrors ? new Li(this, t, e) : new Fe(this, t, e)), this[Z] ? jt(() => this[Bt]()) : this[Bt]()), t;
|
|
23243
24734
|
}
|
|
23244
24735
|
unpipe(t) {
|
|
23245
|
-
let e = this[
|
|
23246
|
-
e && (this[
|
|
24736
|
+
let e = this[N2].find((i) => i.dest === t);
|
|
24737
|
+
e && (this[N2].length === 1 ? (this[g2] && this[Rt] === 0 && (this[g2] = false), this[N2] = []) : this[N2].splice(this[N2].indexOf(e), 1), e.unpipe());
|
|
23247
24738
|
}
|
|
23248
24739
|
addListener(t, e) {
|
|
23249
24740
|
return this.on(t, e);
|
|
@@ -23251,7 +24742,7 @@ var A2 = class extends Di {
|
|
|
23251
24742
|
on(t, e) {
|
|
23252
24743
|
let i = super.on(t, e);
|
|
23253
24744
|
if (t === "data")
|
|
23254
|
-
this[C2] = false, this[Rt]++, !this[
|
|
24745
|
+
this[C2] = false, this[Rt]++, !this[N2].length && !this[g2] && this[Bt]();
|
|
23255
24746
|
else if (t === "readable" && this[_] !== 0)
|
|
23256
24747
|
super.emit("readable");
|
|
23257
24748
|
else if (Kr(t) && this[nt])
|
|
@@ -23267,11 +24758,11 @@ var A2 = class extends Di {
|
|
|
23267
24758
|
}
|
|
23268
24759
|
off(t, e) {
|
|
23269
24760
|
let i = super.off(t, e);
|
|
23270
|
-
return t === "data" && (this[Rt] = this.listeners("data").length, this[Rt] === 0 && !this[C2] && !this[
|
|
24761
|
+
return t === "data" && (this[Rt] = this.listeners("data").length, this[Rt] === 0 && !this[C2] && !this[N2].length && (this[g2] = false)), i;
|
|
23271
24762
|
}
|
|
23272
24763
|
removeAllListeners(t) {
|
|
23273
24764
|
let e = super.removeAllListeners(t);
|
|
23274
|
-
return (t === "data" || t === undefined) && (this[Rt] = 0, !this[C2] && !this[
|
|
24765
|
+
return (t === "data" || t === undefined) && (this[Rt] = 0, !this[C2] && !this[N2].length && (this[g2] = false)), e;
|
|
23275
24766
|
}
|
|
23276
24767
|
get emittedEnd() {
|
|
23277
24768
|
return this[nt];
|
|
@@ -23307,7 +24798,7 @@ var A2 = class extends Di {
|
|
|
23307
24798
|
return this[J](), r;
|
|
23308
24799
|
}
|
|
23309
24800
|
[Oi](t) {
|
|
23310
|
-
for (let i of this[
|
|
24801
|
+
for (let i of this[N2])
|
|
23311
24802
|
i.dest.write(t) === false && this.pause();
|
|
23312
24803
|
let e = this[C2] ? false : super.emit("data", t);
|
|
23313
24804
|
return this[J](), e;
|
|
@@ -23319,12 +24810,12 @@ var A2 = class extends Di {
|
|
|
23319
24810
|
if (this[Mt]) {
|
|
23320
24811
|
let e = this[Mt].end();
|
|
23321
24812
|
if (e) {
|
|
23322
|
-
for (let i of this[
|
|
24813
|
+
for (let i of this[N2])
|
|
23323
24814
|
i.dest.write(e);
|
|
23324
24815
|
this[C2] || super.emit("data", e);
|
|
23325
24816
|
}
|
|
23326
24817
|
}
|
|
23327
|
-
for (let e of this[
|
|
24818
|
+
for (let e of this[N2])
|
|
23328
24819
|
e.end();
|
|
23329
24820
|
let t = super.emit("end");
|
|
23330
24821
|
return this.removeAllListeners("end"), t;
|
|
@@ -23400,7 +24891,7 @@ var Jr = I.writev;
|
|
|
23400
24891
|
var ht = Symbol("_autoClose");
|
|
23401
24892
|
var H = Symbol("_close");
|
|
23402
24893
|
var te = Symbol("_ended");
|
|
23403
|
-
var
|
|
24894
|
+
var m3 = Symbol("_fd");
|
|
23404
24895
|
var Ni = Symbol("_finished");
|
|
23405
24896
|
var tt = Symbol("_flags");
|
|
23406
24897
|
var Ai = Symbol("_flush");
|
|
@@ -23427,7 +24918,7 @@ var Me = Symbol("_defaultFlag");
|
|
|
23427
24918
|
var bt = Symbol("_errored");
|
|
23428
24919
|
var _t = class extends A2 {
|
|
23429
24920
|
[bt] = false;
|
|
23430
|
-
[
|
|
24921
|
+
[m3];
|
|
23431
24922
|
[U2];
|
|
23432
24923
|
[Ci];
|
|
23433
24924
|
[j] = false;
|
|
@@ -23437,10 +24928,10 @@ var _t = class extends A2 {
|
|
|
23437
24928
|
constructor(t, e) {
|
|
23438
24929
|
if (e = e || {}, super(e), this.readable = true, this.writable = false, typeof t != "string")
|
|
23439
24930
|
throw new TypeError("path must be a string");
|
|
23440
|
-
this[bt] = false, this[
|
|
24931
|
+
this[bt] = false, this[m3] = typeof e.fd == "number" ? e.fd : undefined, this[U2] = t, this[Ci] = e.readSize || 16 * 1024 * 1024, this[j] = false, this[Fi] = typeof e.size == "number" ? e.size : 1 / 0, this[ee] = this[Fi], this[ht] = typeof e.autoClose == "boolean" ? e.autoClose : true, typeof this[m3] == "number" ? this[zt]() : this[at]();
|
|
23441
24932
|
}
|
|
23442
24933
|
get fd() {
|
|
23443
|
-
return this[
|
|
24934
|
+
return this[m3];
|
|
23444
24935
|
}
|
|
23445
24936
|
get path() {
|
|
23446
24937
|
return this[U2];
|
|
@@ -23455,7 +24946,7 @@ var _t = class extends A2 {
|
|
|
23455
24946
|
I.open(this[U2], "r", (t, e) => this[Ht](t, e));
|
|
23456
24947
|
}
|
|
23457
24948
|
[Ht](t, e) {
|
|
23458
|
-
t ? this[Ut](t) : (this[
|
|
24949
|
+
t ? this[Ut](t) : (this[m3] = e, this.emit("open", e), this[zt]());
|
|
23459
24950
|
}
|
|
23460
24951
|
[vi]() {
|
|
23461
24952
|
return Buffer.allocUnsafe(Math.min(this[Ci], this[ee]));
|
|
@@ -23466,16 +24957,16 @@ var _t = class extends A2 {
|
|
|
23466
24957
|
let t = this[vi]();
|
|
23467
24958
|
if (t.length === 0)
|
|
23468
24959
|
return process.nextTick(() => this[Ii](null, 0, t));
|
|
23469
|
-
I.read(this[
|
|
24960
|
+
I.read(this[m3], t, 0, t.length, null, (e, i, r) => this[Ii](e, i, r));
|
|
23470
24961
|
}
|
|
23471
24962
|
}
|
|
23472
24963
|
[Ii](t, e, i) {
|
|
23473
24964
|
this[j] = false, t ? this[Ut](t) : this[ki](e, i) && this[zt]();
|
|
23474
24965
|
}
|
|
23475
24966
|
[H]() {
|
|
23476
|
-
if (this[ht] && typeof this[
|
|
23477
|
-
let t = this[
|
|
23478
|
-
this[
|
|
24967
|
+
if (this[ht] && typeof this[m3] == "number") {
|
|
24968
|
+
let t = this[m3];
|
|
24969
|
+
this[m3] = undefined, I.close(t, (e) => e ? this.emit("error", e) : this.emit("close"));
|
|
23479
24970
|
}
|
|
23480
24971
|
}
|
|
23481
24972
|
[Ut](t) {
|
|
@@ -23491,7 +24982,7 @@ var _t = class extends A2 {
|
|
|
23491
24982
|
case "finish":
|
|
23492
24983
|
return false;
|
|
23493
24984
|
case "drain":
|
|
23494
|
-
return typeof this[
|
|
24985
|
+
return typeof this[m3] == "number" && this[zt](), false;
|
|
23495
24986
|
case "error":
|
|
23496
24987
|
return this[bt] ? false : (this[bt] = true, super.emit(t, ...e));
|
|
23497
24988
|
default:
|
|
@@ -23514,7 +25005,7 @@ var Be = class extends _t {
|
|
|
23514
25005
|
if (!this[j]) {
|
|
23515
25006
|
this[j] = true;
|
|
23516
25007
|
do {
|
|
23517
|
-
let e = this[vi](), i = e.length === 0 ? 0 : I.readSync(this[
|
|
25008
|
+
let e = this[vi](), i = e.length === 0 ? 0 : I.readSync(this[m3], e, 0, e.length, null);
|
|
23518
25009
|
if (!this[ki](i, e))
|
|
23519
25010
|
break;
|
|
23520
25011
|
} while (true);
|
|
@@ -23526,9 +25017,9 @@ var Be = class extends _t {
|
|
|
23526
25017
|
}
|
|
23527
25018
|
}
|
|
23528
25019
|
[H]() {
|
|
23529
|
-
if (this[ht] && typeof this[
|
|
23530
|
-
let t = this[
|
|
23531
|
-
this[
|
|
25020
|
+
if (this[ht] && typeof this[m3] == "number") {
|
|
25021
|
+
let t = this[m3];
|
|
25022
|
+
this[m3] = undefined, I.closeSync(t), this.emit("close");
|
|
23532
25023
|
}
|
|
23533
25024
|
}
|
|
23534
25025
|
};
|
|
@@ -23543,15 +25034,15 @@ var et = class extends Qr {
|
|
|
23543
25034
|
[U2];
|
|
23544
25035
|
[ie];
|
|
23545
25036
|
[ht];
|
|
23546
|
-
[
|
|
25037
|
+
[m3];
|
|
23547
25038
|
[Me];
|
|
23548
25039
|
[tt];
|
|
23549
25040
|
[Ni] = false;
|
|
23550
25041
|
[ot];
|
|
23551
25042
|
constructor(t, e) {
|
|
23552
|
-
e = e || {}, super(e), this[U2] = t, this[
|
|
25043
|
+
e = e || {}, super(e), this[U2] = t, this[m3] = typeof e.fd == "number" ? e.fd : undefined, this[ie] = e.mode === undefined ? 438 : e.mode, this[ot] = typeof e.start == "number" ? e.start : undefined, this[ht] = typeof e.autoClose == "boolean" ? e.autoClose : true;
|
|
23553
25044
|
let i = this[ot] !== undefined ? "r+" : "w";
|
|
23554
|
-
this[Me] = e.flags === undefined, this[tt] = e.flags === undefined ? i : e.flags, this[
|
|
25045
|
+
this[Me] = e.flags === undefined, this[tt] = e.flags === undefined ? i : e.flags, this[m3] === undefined && this[at]();
|
|
23555
25046
|
}
|
|
23556
25047
|
emit(t, ...e) {
|
|
23557
25048
|
if (t === "error") {
|
|
@@ -23562,7 +25053,7 @@ var et = class extends Qr {
|
|
|
23562
25053
|
return super.emit(t, ...e);
|
|
23563
25054
|
}
|
|
23564
25055
|
get fd() {
|
|
23565
|
-
return this[
|
|
25056
|
+
return this[m3];
|
|
23566
25057
|
}
|
|
23567
25058
|
get path() {
|
|
23568
25059
|
return this[U2];
|
|
@@ -23574,16 +25065,16 @@ var et = class extends Qr {
|
|
|
23574
25065
|
I.open(this[U2], this[tt], this[ie], (t, e) => this[Ht](t, e));
|
|
23575
25066
|
}
|
|
23576
25067
|
[Ht](t, e) {
|
|
23577
|
-
this[Me] && this[tt] === "r+" && t && t.code === "ENOENT" ? (this[tt] = "w", this[at]()) : t ? this[Ut](t) : (this[
|
|
25068
|
+
this[Me] && this[tt] === "r+" && t && t.code === "ENOENT" ? (this[tt] = "w", this[at]()) : t ? this[Ut](t) : (this[m3] = e, this.emit("open", e), this[gt] || this[Ai]());
|
|
23578
25069
|
}
|
|
23579
25070
|
end(t, e) {
|
|
23580
|
-
return t && this.write(t, e), this[te] = true, !this[gt] && !this[Y].length && typeof this[
|
|
25071
|
+
return t && this.write(t, e), this[te] = true, !this[gt] && !this[Y].length && typeof this[m3] == "number" && this[Pt](null, 0), this;
|
|
23581
25072
|
}
|
|
23582
25073
|
write(t, e) {
|
|
23583
|
-
return typeof t == "string" && (t = Buffer.from(t, e)), this[te] ? (this.emit("error", new Error("write() after end()")), false) : this[
|
|
25074
|
+
return typeof t == "string" && (t = Buffer.from(t, e)), this[te] ? (this.emit("error", new Error("write() after end()")), false) : this[m3] === undefined || this[gt] || this[Y].length ? (this[Y].push(t), this[ke] = true, false) : (this[gt] = true, this[ve](t), true);
|
|
23584
25075
|
}
|
|
23585
25076
|
[ve](t) {
|
|
23586
|
-
I.write(this[
|
|
25077
|
+
I.write(this[m3], t, 0, t.length, this[ot], (e, i) => this[Pt](e, i));
|
|
23587
25078
|
}
|
|
23588
25079
|
[Pt](t, e) {
|
|
23589
25080
|
t ? this[Ut](t) : (this[ot] !== undefined && typeof e == "number" && (this[ot] += e), this[Y].length ? this[Ai]() : (this[gt] = false, this[te] && !this[Ni] ? (this[Ni] = true, this[H](), this.emit("finish")) : this[ke] && (this[ke] = false, this.emit("drain"))));
|
|
@@ -23595,13 +25086,13 @@ var et = class extends Qr {
|
|
|
23595
25086
|
this[ve](this[Y].pop());
|
|
23596
25087
|
else {
|
|
23597
25088
|
let t = this[Y];
|
|
23598
|
-
this[Y] = [], Jr(this[
|
|
25089
|
+
this[Y] = [], Jr(this[m3], t, this[ot], (e, i) => this[Pt](e, i));
|
|
23599
25090
|
}
|
|
23600
25091
|
}
|
|
23601
25092
|
[H]() {
|
|
23602
|
-
if (this[ht] && typeof this[
|
|
23603
|
-
let t = this[
|
|
23604
|
-
this[
|
|
25093
|
+
if (this[ht] && typeof this[m3] == "number") {
|
|
25094
|
+
let t = this[m3];
|
|
25095
|
+
this[m3] = undefined, I.close(t, (e) => e ? this.emit("error", e) : this.emit("close"));
|
|
23605
25096
|
}
|
|
23606
25097
|
}
|
|
23607
25098
|
};
|
|
@@ -23621,15 +25112,15 @@ var Wt = class extends et {
|
|
|
23621
25112
|
this[Ht](null, t);
|
|
23622
25113
|
}
|
|
23623
25114
|
[H]() {
|
|
23624
|
-
if (this[ht] && typeof this[
|
|
23625
|
-
let t = this[
|
|
23626
|
-
this[
|
|
25115
|
+
if (this[ht] && typeof this[m3] == "number") {
|
|
25116
|
+
let t = this[m3];
|
|
25117
|
+
this[m3] = undefined, I.closeSync(t), this.emit("close");
|
|
23627
25118
|
}
|
|
23628
25119
|
}
|
|
23629
25120
|
[ve](t) {
|
|
23630
25121
|
let e = true;
|
|
23631
25122
|
try {
|
|
23632
|
-
this[Pt](null, I.writeSync(this[
|
|
25123
|
+
this[Pt](null, I.writeSync(this[m3], t, 0, t.length, this[ot])), e = false;
|
|
23633
25124
|
} finally {
|
|
23634
25125
|
if (e)
|
|
23635
25126
|
try {
|
|
@@ -25607,7 +27098,7 @@ var Dr = Symbol("onEntry");
|
|
|
25607
27098
|
var _s = Symbol("checkFs");
|
|
25608
27099
|
var Nr = Symbol("checkFs2");
|
|
25609
27100
|
var Os = Symbol("isReusable");
|
|
25610
|
-
var
|
|
27101
|
+
var P2 = Symbol("makeFs");
|
|
25611
27102
|
var Ts = Symbol("file");
|
|
25612
27103
|
var xs = Symbol("directory");
|
|
25613
27104
|
var gi = Symbol("link");
|
|
@@ -25895,23 +27386,23 @@ var Xt = class extends rt {
|
|
|
25895
27386
|
return;
|
|
25896
27387
|
}
|
|
25897
27388
|
if (h || this[Os](t, a))
|
|
25898
|
-
return this[
|
|
27389
|
+
return this[P2](null, t, i);
|
|
25899
27390
|
if (a.isDirectory()) {
|
|
25900
27391
|
if (t.type === "Directory") {
|
|
25901
|
-
let l = this.chmod && t.mode && (a.mode & 4095) !== t.mode, c = (d) => this[
|
|
27392
|
+
let l = this.chmod && t.mode && (a.mode & 4095) !== t.mode, c = (d) => this[P2](d ?? null, t, i);
|
|
25902
27393
|
return l ? u3.chmod(String(t.absolute), Number(t.mode), c) : c();
|
|
25903
27394
|
}
|
|
25904
27395
|
if (t.absolute !== this.cwd)
|
|
25905
|
-
return u3.rmdir(String(t.absolute), (l) => this[
|
|
27396
|
+
return u3.rmdir(String(t.absolute), (l) => this[P2](l ?? null, t, i));
|
|
25906
27397
|
}
|
|
25907
27398
|
if (t.absolute === this.cwd)
|
|
25908
|
-
return this[
|
|
25909
|
-
mo(String(t.absolute), (l) => this[
|
|
27399
|
+
return this[P2](null, t, i);
|
|
27400
|
+
mo(String(t.absolute), (l) => this[P2](l ?? null, t, i));
|
|
25910
27401
|
});
|
|
25911
27402
|
};
|
|
25912
27403
|
this[Oe] ? n() : r();
|
|
25913
27404
|
}
|
|
25914
|
-
[
|
|
27405
|
+
[P2](t, e, i) {
|
|
25915
27406
|
if (t) {
|
|
25916
27407
|
this[O](t, e), i();
|
|
25917
27408
|
return;
|
|
@@ -25945,8 +27436,8 @@ var ye = (s) => {
|
|
|
25945
27436
|
};
|
|
25946
27437
|
var xe = class extends Xt {
|
|
25947
27438
|
sync = true;
|
|
25948
|
-
[
|
|
25949
|
-
return super[
|
|
27439
|
+
[P2](t, e) {
|
|
27440
|
+
return super[P2](t, e, () => {});
|
|
25950
27441
|
}
|
|
25951
27442
|
[_s](t) {
|
|
25952
27443
|
if (!this[Oe]) {
|
|
@@ -25967,19 +27458,19 @@ var xe = class extends Xt {
|
|
|
25967
27458
|
if (i && (this.keep || this.newer && i.mtime > (t.mtime ?? i.mtime)))
|
|
25968
27459
|
return this[Ls](t);
|
|
25969
27460
|
if (e || this[Os](t, i))
|
|
25970
|
-
return this[
|
|
27461
|
+
return this[P2](null, t);
|
|
25971
27462
|
if (i.isDirectory()) {
|
|
25972
27463
|
if (t.type === "Directory") {
|
|
25973
27464
|
let o = this.chmod && t.mode && (i.mode & 4095) !== t.mode, [h] = o ? ye(() => {
|
|
25974
27465
|
u3.chmodSync(String(t.absolute), Number(t.mode));
|
|
25975
27466
|
}) : [];
|
|
25976
|
-
return this[
|
|
27467
|
+
return this[P2](h, t);
|
|
25977
27468
|
}
|
|
25978
27469
|
let [n] = ye(() => u3.rmdirSync(String(t.absolute)));
|
|
25979
|
-
this[
|
|
27470
|
+
this[P2](n, t);
|
|
25980
27471
|
}
|
|
25981
27472
|
let [r] = t.absolute === this.cwd ? [] : ye(() => po(String(t.absolute)));
|
|
25982
|
-
this[
|
|
27473
|
+
this[P2](r, t);
|
|
25983
27474
|
}
|
|
25984
27475
|
[Ts](t, e) {
|
|
25985
27476
|
let i = typeof t.mode == "number" ? t.mode & 4095 : this.fmode, r = (h) => {
|
|
@@ -26427,8 +27918,8 @@ async function handleFlowsPull(ctx, opts, deps) {
|
|
|
26427
27918
|
ctx.ui.error(validation.error);
|
|
26428
27919
|
return { error: validation.error };
|
|
26429
27920
|
}
|
|
26430
|
-
const destAbs = resolve8(opts.out ??
|
|
26431
|
-
const assetsAbs =
|
|
27921
|
+
const destAbs = resolve8(opts.out ?? join31(".qawolf", opts.env));
|
|
27922
|
+
const assetsAbs = join31(dirname8(destAbs), "assets");
|
|
26432
27923
|
await resolvedDeps.fs.mkdir(assetsAbs, { recursive: true });
|
|
26433
27924
|
const yes = opts.yes ?? false;
|
|
26434
27925
|
let archive;
|
|
@@ -27303,15 +28794,15 @@ async function defaultRunWebFlowDeps(envDir = process.cwd(), signals) {
|
|
|
27303
28794
|
|
|
27304
28795
|
// src/domains/runtimeEnv/prepareRunDir.ts
|
|
27305
28796
|
import { createHash as createHash4 } from "node:crypto";
|
|
27306
|
-
import { join as
|
|
28797
|
+
import { join as join39, resolve as resolve9 } from "node:path";
|
|
27307
28798
|
|
|
27308
28799
|
// src/domains/runtimeEnv/execSubpathImports.ts
|
|
27309
|
-
import { join as
|
|
28800
|
+
import { join as join32 } from "node:path";
|
|
27310
28801
|
var flowSubpathImports = { "#playwright": "playwright" };
|
|
27311
28802
|
var packageJsonSchema = looseObject({ imports: record(string2(), unknown()).catch({}) }).catch({ imports: {} });
|
|
27312
28803
|
async function writeExecSubpathImports(args) {
|
|
27313
28804
|
const { execDir, fs } = args;
|
|
27314
|
-
const pkgPath =
|
|
28805
|
+
const pkgPath = join32(execDir, "package.json");
|
|
27315
28806
|
const pkg = packageJsonSchema.parse(await readPackageJson(pkgPath, fs));
|
|
27316
28807
|
const merged = { ...pkg, imports: { ...pkg.imports, ...flowSubpathImports } };
|
|
27317
28808
|
await fs.writeFile(pkgPath, JSON.stringify(merged, undefined, 2));
|
|
@@ -27333,10 +28824,10 @@ async function readPackageJson(pkgPath, fs) {
|
|
|
27333
28824
|
}
|
|
27334
28825
|
|
|
27335
28826
|
// src/domains/runtimeEnv/innerHop.ts
|
|
27336
|
-
import { join as
|
|
28827
|
+
import { join as join34 } from "node:path";
|
|
27337
28828
|
|
|
27338
28829
|
// src/domains/runtimeEnv/linkPinnedPackages.ts
|
|
27339
|
-
import { dirname as dirname9, join as
|
|
28830
|
+
import { dirname as dirname9, join as join33 } from "node:path";
|
|
27340
28831
|
|
|
27341
28832
|
// src/domains/runtimeEnv/symlinkDir.ts
|
|
27342
28833
|
import { symlink } from "node:fs/promises";
|
|
@@ -27348,16 +28839,16 @@ async function createDirSymlink(source, target) {
|
|
|
27348
28839
|
// src/domains/runtimeEnv/linkPinnedPackages.ts
|
|
27349
28840
|
async function linkPinnedPackages(args) {
|
|
27350
28841
|
const { depsRoot, nodeModulesDir, fs } = args;
|
|
27351
|
-
const managedModules =
|
|
28842
|
+
const managedModules = join33(depsRoot, "node_modules");
|
|
27352
28843
|
await fs.mkdir(nodeModulesDir, { recursive: true });
|
|
27353
28844
|
for (const { name } of pinnedPackages) {
|
|
27354
28845
|
const segments = name.split("/");
|
|
27355
|
-
const target =
|
|
28846
|
+
const target = join33(nodeModulesDir, ...segments);
|
|
27356
28847
|
if (segments.length > 1) {
|
|
27357
28848
|
await fs.mkdir(dirname9(target), { recursive: true });
|
|
27358
28849
|
}
|
|
27359
28850
|
await fs.rm(target, { recursive: true, force: true });
|
|
27360
|
-
await createDirSymlink(
|
|
28851
|
+
await createDirSymlink(join33(managedModules, ...segments), target);
|
|
27361
28852
|
}
|
|
27362
28853
|
}
|
|
27363
28854
|
|
|
@@ -27366,18 +28857,18 @@ async function populateInnerHop(args) {
|
|
|
27366
28857
|
const { depsRoot, execDir, fs } = args;
|
|
27367
28858
|
await linkPinnedPackages({
|
|
27368
28859
|
depsRoot,
|
|
27369
|
-
nodeModulesDir:
|
|
28860
|
+
nodeModulesDir: join34(execDir, "node_modules"),
|
|
27370
28861
|
fs
|
|
27371
28862
|
});
|
|
27372
28863
|
}
|
|
27373
28864
|
|
|
27374
28865
|
// src/domains/runtimeEnv/outerHop.ts
|
|
27375
28866
|
import { lstat as lstat2 } from "node:fs/promises";
|
|
27376
|
-
import { dirname as dirname11, join as
|
|
28867
|
+
import { dirname as dirname11, join as join36 } from "node:path";
|
|
27377
28868
|
|
|
27378
28869
|
// src/domains/runtimeEnv/carryOverPackages.ts
|
|
27379
28870
|
import { lstat } from "node:fs/promises";
|
|
27380
|
-
import { dirname as dirname10, join as
|
|
28871
|
+
import { dirname as dirname10, join as join35 } from "node:path";
|
|
27381
28872
|
|
|
27382
28873
|
// src/domains/runtimeEnv/carryOverPlan.ts
|
|
27383
28874
|
var executorPackageNames = new Set(pinnedPackages.map((p) => p.name));
|
|
@@ -27399,12 +28890,12 @@ async function carryOverPackages(args) {
|
|
|
27399
28890
|
const linked = [];
|
|
27400
28891
|
for (const name of names) {
|
|
27401
28892
|
const segments = name.split("/");
|
|
27402
|
-
const target =
|
|
28893
|
+
const target = join35(nodeModulesDir, ...segments);
|
|
27403
28894
|
if (await pathOccupied(target))
|
|
27404
28895
|
continue;
|
|
27405
28896
|
if (segments.length > 1)
|
|
27406
28897
|
await fs.mkdir(dirname10(target), { recursive: true });
|
|
27407
|
-
await createDirSymlink(
|
|
28898
|
+
await createDirSymlink(join35(projectModulesDir, ...segments), target);
|
|
27408
28899
|
linked.push(name);
|
|
27409
28900
|
}
|
|
27410
28901
|
return linked;
|
|
@@ -27427,18 +28918,18 @@ async function listPackageNames(dir, fs) {
|
|
|
27427
28918
|
const names = [];
|
|
27428
28919
|
for (const entry of entries) {
|
|
27429
28920
|
if (!entry.startsWith("@")) {
|
|
27430
|
-
if (fs.existsSync(
|
|
28921
|
+
if (fs.existsSync(join35(dir, entry, "package.json")))
|
|
27431
28922
|
names.push(entry);
|
|
27432
28923
|
continue;
|
|
27433
28924
|
}
|
|
27434
28925
|
let scoped;
|
|
27435
28926
|
try {
|
|
27436
|
-
scoped = await fs.readdir(
|
|
28927
|
+
scoped = await fs.readdir(join35(dir, entry));
|
|
27437
28928
|
} catch {
|
|
27438
28929
|
continue;
|
|
27439
28930
|
}
|
|
27440
28931
|
for (const inner of scoped) {
|
|
27441
|
-
if (fs.existsSync(
|
|
28932
|
+
if (fs.existsSync(join35(dir, entry, inner, "package.json"))) {
|
|
27442
28933
|
names.push(`${entry}/${inner}`);
|
|
27443
28934
|
}
|
|
27444
28935
|
}
|
|
@@ -27456,7 +28947,7 @@ async function populateOuterHop(args) {
|
|
|
27456
28947
|
const depNames = Object.keys(installableDeps);
|
|
27457
28948
|
const { satisfying, rejected } = await findSatisfyingNodeModulesDir(projectDir, depNames, fs);
|
|
27458
28949
|
if (satisfying !== undefined) {
|
|
27459
|
-
await createDirSymlink(satisfying,
|
|
28950
|
+
await createDirSymlink(satisfying, join36(runDir, "node_modules"));
|
|
27460
28951
|
return { mode: "symlink", nodeModulesDir: satisfying };
|
|
27461
28952
|
}
|
|
27462
28953
|
if (depNames.length === 0)
|
|
@@ -27465,12 +28956,12 @@ async function populateOuterHop(args) {
|
|
|
27465
28956
|
await installOuterDeps(runDir, installableDeps, fs, args.install ?? spawnNpmInstall);
|
|
27466
28957
|
await linkPinnedPackages({
|
|
27467
28958
|
depsRoot: args.depsRoot,
|
|
27468
|
-
nodeModulesDir:
|
|
28959
|
+
nodeModulesDir: join36(runDir, "node_modules"),
|
|
27469
28960
|
fs
|
|
27470
28961
|
});
|
|
27471
28962
|
const carriedOver = await carryOverPackages({
|
|
27472
|
-
projectModulesDir:
|
|
27473
|
-
nodeModulesDir:
|
|
28963
|
+
projectModulesDir: join36(projectDir, "node_modules"),
|
|
28964
|
+
nodeModulesDir: join36(runDir, "node_modules"),
|
|
27474
28965
|
fs
|
|
27475
28966
|
});
|
|
27476
28967
|
return { mode: "install", depCount: depNames.length, rejected, carriedOver };
|
|
@@ -27479,10 +28970,10 @@ async function findSatisfyingNodeModulesDir(startDir, depNames, fs) {
|
|
|
27479
28970
|
const rejected = [];
|
|
27480
28971
|
let dir = startDir;
|
|
27481
28972
|
while (true) {
|
|
27482
|
-
const candidate =
|
|
28973
|
+
const candidate = join36(dir, "node_modules");
|
|
27483
28974
|
const stats = await lstatSafe(candidate);
|
|
27484
28975
|
if (stats !== undefined && stats.isDirectory() && !stats.isSymbolicLink()) {
|
|
27485
|
-
const missing = depNames.filter((name) => !fs.existsSync(
|
|
28976
|
+
const missing = depNames.filter((name) => !fs.existsSync(join36(candidate, name, "package.json")));
|
|
27486
28977
|
if (missing.length === 0)
|
|
27487
28978
|
return { satisfying: candidate, rejected };
|
|
27488
28979
|
rejected.push({ dir: candidate, missing });
|
|
@@ -27503,7 +28994,7 @@ async function lstatSafe(path) {
|
|
|
27503
28994
|
async function readInstallableDeps(projectDir, fs) {
|
|
27504
28995
|
let content;
|
|
27505
28996
|
try {
|
|
27506
|
-
content = await fs.readFile(
|
|
28997
|
+
content = await fs.readFile(join36(projectDir, "package.json"));
|
|
27507
28998
|
} catch {
|
|
27508
28999
|
return {};
|
|
27509
29000
|
}
|
|
@@ -27521,8 +29012,8 @@ async function readInstallableDeps(projectDir, fs) {
|
|
|
27521
29012
|
return Object.fromEntries(Object.entries(rawDeps).filter(([name]) => !executorPackageNames2.has(name)).filter((entry) => typeof entry[1] === "string"));
|
|
27522
29013
|
}
|
|
27523
29014
|
async function installOuterDeps(runDir, deps, fs, install) {
|
|
27524
|
-
await fs.writeFile(
|
|
27525
|
-
await fs.writeFile(
|
|
29015
|
+
await fs.writeFile(join36(runDir, "package.json"), JSON.stringify({ name: "qawolf-run", private: true, dependencies: deps }, undefined, 2));
|
|
29016
|
+
await fs.writeFile(join36(runDir, ".npmrc"), `@qawolf:registry=https://registry.npmjs.org/
|
|
27526
29017
|
`);
|
|
27527
29018
|
const result = await install(runDir);
|
|
27528
29019
|
if (result.exitCode !== 0) {
|
|
@@ -27532,14 +29023,14 @@ async function installOuterDeps(runDir, deps, fs, install) {
|
|
|
27532
29023
|
|
|
27533
29024
|
// src/domains/runtimeEnv/stageFlowFiles.ts
|
|
27534
29025
|
import { createHash as createHash3 } from "node:crypto";
|
|
27535
|
-
import { basename as basename6, dirname as dirname12, join as
|
|
29026
|
+
import { basename as basename6, dirname as dirname12, join as join38, sep as sep4 } from "node:path";
|
|
27536
29027
|
|
|
27537
29028
|
// src/shell/copyDir.ts
|
|
27538
29029
|
import { cp, readdir as readdir2 } from "node:fs/promises";
|
|
27539
|
-
import { basename as basename5, join as
|
|
29030
|
+
import { basename as basename5, join as join37 } from "node:path";
|
|
27540
29031
|
async function copyDirExcluding(source, destination, excludedNames) {
|
|
27541
29032
|
const entries = await readdir2(source, { withFileTypes: true });
|
|
27542
|
-
await Promise.all(entries.filter((entry) => !excludedNames.has(entry.name)).map((entry) => cp(
|
|
29033
|
+
await Promise.all(entries.filter((entry) => !excludedNames.has(entry.name)).map((entry) => cp(join37(source, entry.name), join37(destination, entry.name), {
|
|
27543
29034
|
recursive: true,
|
|
27544
29035
|
filter: (path) => !excludedNames.has(basename5(path))
|
|
27545
29036
|
})));
|
|
@@ -27556,14 +29047,14 @@ async function stageFlowFiles(args) {
|
|
|
27556
29047
|
if (files.length > 1) {
|
|
27557
29048
|
return Promise.all(files.map((f) => stageOneFile(f, execDir, fs)));
|
|
27558
29049
|
}
|
|
27559
|
-
await Promise.all(files.map((f) => fs.copyFile(f,
|
|
27560
|
-
return files.map((f) =>
|
|
29050
|
+
await Promise.all(files.map((f) => fs.copyFile(f, join38(execDir, basename6(f)))));
|
|
29051
|
+
return files.map((f) => join38(execDir, basename6(f)));
|
|
27561
29052
|
}
|
|
27562
29053
|
async function stageOneFile(file, execDir, fs) {
|
|
27563
29054
|
const dirHash = createHash3("sha256").update(dirname12(file)).digest("hex").slice(0, 8);
|
|
27564
|
-
const subDir =
|
|
29055
|
+
const subDir = join38(execDir, dirHash);
|
|
27565
29056
|
await fs.mkdir(subDir, { recursive: true });
|
|
27566
|
-
const dest =
|
|
29057
|
+
const dest = join38(subDir, basename6(file));
|
|
27567
29058
|
await fs.copyFile(file, dest);
|
|
27568
29059
|
return dest;
|
|
27569
29060
|
}
|
|
@@ -27571,7 +29062,7 @@ function remapPath(file, projectDir, execDir) {
|
|
|
27571
29062
|
if (file === projectDir)
|
|
27572
29063
|
return execDir;
|
|
27573
29064
|
if (file.startsWith(projectDir + sep4)) {
|
|
27574
|
-
return
|
|
29065
|
+
return join38(execDir, file.slice(projectDir.length + 1));
|
|
27575
29066
|
}
|
|
27576
29067
|
return;
|
|
27577
29068
|
}
|
|
@@ -27581,10 +29072,10 @@ async function prepareRunDir(args) {
|
|
|
27581
29072
|
const { files, projectDir, depsRoot, runRoot } = args;
|
|
27582
29073
|
const fs = args.fs ?? makeDefaultFs();
|
|
27583
29074
|
const runId = buildRunId(projectDir, files);
|
|
27584
|
-
const runDir =
|
|
29075
|
+
const runDir = join39(runRoot, runId);
|
|
27585
29076
|
await fs.rm(runDir, { recursive: true, force: true });
|
|
27586
29077
|
await fs.mkdir(runDir, { recursive: true });
|
|
27587
|
-
const execDir =
|
|
29078
|
+
const execDir = join39(runDir, "exec");
|
|
27588
29079
|
await fs.mkdir(execDir, { recursive: true });
|
|
27589
29080
|
await populateInnerHop({ depsRoot, execDir, fs });
|
|
27590
29081
|
const stagedFiles = await stageFlowFiles({ files, projectDir, execDir, fs });
|
|
@@ -27615,17 +29106,17 @@ function buildRunId(projectDir, files) {
|
|
|
27615
29106
|
}
|
|
27616
29107
|
|
|
27617
29108
|
// src/shell/testkit.ts
|
|
27618
|
-
import { join as
|
|
29109
|
+
import { join as join40 } from "node:path";
|
|
27619
29110
|
function notAvailableLocally(name) {
|
|
27620
29111
|
throw new Error(runnerMessages.notAvailableLocally(name));
|
|
27621
29112
|
}
|
|
27622
29113
|
async function loadSdkDeps(cwd) {
|
|
27623
|
-
const testkitDir =
|
|
29114
|
+
const testkitDir = join40(cwd, "node_modules", "@qawolf", "testkit");
|
|
27624
29115
|
try {
|
|
27625
29116
|
const clientMod = await importFromPath(resolveFromEnvDir(cwd, "@qawolf/testkit/client"));
|
|
27626
29117
|
if (typeof clientMod.createTestkitClient !== "function")
|
|
27627
29118
|
throw new Error("createTestkitClient is not a function");
|
|
27628
|
-
const scopeMod = await importFromPath(
|
|
29119
|
+
const scopeMod = await importFromPath(join40(testkitDir, "dist", "clientScope.js"));
|
|
27629
29120
|
if (typeof scopeMod.configureTestkitClient !== "function")
|
|
27630
29121
|
throw new Error("configureTestkitClient is not a function");
|
|
27631
29122
|
return {
|
|
@@ -27683,9 +29174,9 @@ async function registerLazyEmailsClient(getInbox, cwd, deps) {
|
|
|
27683
29174
|
}
|
|
27684
29175
|
|
|
27685
29176
|
// src/commands/flows/envVarDeps.ts
|
|
27686
|
-
import { join as
|
|
29177
|
+
import { join as join41 } from "node:path";
|
|
27687
29178
|
function envFilePath(envDir) {
|
|
27688
|
-
return
|
|
29179
|
+
return join41(envDir, ".env");
|
|
27689
29180
|
}
|
|
27690
29181
|
async function readEnv(envDir, fs) {
|
|
27691
29182
|
try {
|
|
@@ -27809,7 +29300,7 @@ async function selectRunByTag(args) {
|
|
|
27809
29300
|
}
|
|
27810
29301
|
|
|
27811
29302
|
// src/commands/flows/runStagedFlows.ts
|
|
27812
|
-
import { join as
|
|
29303
|
+
import { join as join45 } from "node:path";
|
|
27813
29304
|
|
|
27814
29305
|
// src/shell/appium/createAppiumServer.ts
|
|
27815
29306
|
import { existsSync as existsSync2 } from "node:fs";
|
|
@@ -29115,14 +30606,14 @@ async function runWebFlow({
|
|
|
29115
30606
|
|
|
29116
30607
|
// src/shell/embeddedWorkerCli.ts
|
|
29117
30608
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
29118
|
-
import { basename as basename7, join as
|
|
30609
|
+
import { basename as basename7, join as join42 } from "node:path";
|
|
29119
30610
|
var embeddedCliPathEnv = "QAWOLF_EMBEDDED_CLI_PATH";
|
|
29120
30611
|
function extractEmbeddedWorkerCli() {
|
|
29121
30612
|
const assetPath = process.env[embeddedCliPathEnv];
|
|
29122
30613
|
if (assetPath === undefined || assetPath === "")
|
|
29123
30614
|
return;
|
|
29124
|
-
const dir =
|
|
29125
|
-
const dest =
|
|
30615
|
+
const dir = join42(getDataDir(), "worker");
|
|
30616
|
+
const dest = join42(dir, basename7(assetPath));
|
|
29126
30617
|
if (existsSync3(dest))
|
|
29127
30618
|
return dest;
|
|
29128
30619
|
mkdirSync3(dir, { recursive: true });
|
|
@@ -29360,7 +30851,7 @@ ${styleText3("dim", "─".repeat(width))}
|
|
|
29360
30851
|
};
|
|
29361
30852
|
}
|
|
29362
30853
|
// src/shell/reporter/createJUnitReporter.ts
|
|
29363
|
-
import { join as
|
|
30854
|
+
import { join as join43 } from "node:path";
|
|
29364
30855
|
|
|
29365
30856
|
// src/shell/reporter/junitXml.ts
|
|
29366
30857
|
function escapeXml(str) {
|
|
@@ -29399,7 +30890,7 @@ ${suites}`;
|
|
|
29399
30890
|
|
|
29400
30891
|
// src/shell/reporter/createJUnitReporter.ts
|
|
29401
30892
|
function resolveJUnitOutputPath(junit, outputDir) {
|
|
29402
|
-
return typeof junit === "string" && junit.trim() !== "" ? junit :
|
|
30893
|
+
return typeof junit === "string" && junit.trim() !== "" ? junit : join43(outputDir, "junit-report.xml");
|
|
29403
30894
|
}
|
|
29404
30895
|
function createJUnitReporter(deps) {
|
|
29405
30896
|
const flows = [];
|
|
@@ -29490,11 +30981,11 @@ function buildFlowsRunDeps(args) {
|
|
|
29490
30981
|
|
|
29491
30982
|
// src/commands/flows/loadEnvFile.ts
|
|
29492
30983
|
import { readFile } from "node:fs/promises";
|
|
29493
|
-
import { join as
|
|
30984
|
+
import { join as join44 } from "node:path";
|
|
29494
30985
|
async function loadEnvFile(envDir) {
|
|
29495
30986
|
let content;
|
|
29496
30987
|
try {
|
|
29497
|
-
content = await readFile(
|
|
30988
|
+
content = await readFile(join44(envDir, ".env"), "utf8");
|
|
29498
30989
|
} catch (err) {
|
|
29499
30990
|
if (isNoEntError(err))
|
|
29500
30991
|
return;
|
|
@@ -29539,7 +31030,7 @@ async function runStagedFlows(args) {
|
|
|
29539
31030
|
for (const candidate of staged.outerHop.rejected) {
|
|
29540
31031
|
log.debug(runnerMessages.outerHopCandidateRejected(candidate.dir, candidate.missing));
|
|
29541
31032
|
}
|
|
29542
|
-
const ownModules = projectDir === undefined ? undefined :
|
|
31033
|
+
const ownModules = projectDir === undefined ? undefined : join45(projectDir, "node_modules");
|
|
29543
31034
|
const own = staged.outerHop.rejected.find((c) => c.dir === ownModules);
|
|
29544
31035
|
if (own !== undefined) {
|
|
29545
31036
|
ctx.ui.warn(runnerMessages.outerHopFallbackNotice(own.dir, own.missing));
|
|
@@ -29574,7 +31065,7 @@ async function runStagedFlows(args) {
|
|
|
29574
31065
|
}
|
|
29575
31066
|
|
|
29576
31067
|
// src/commands/flows/runDefaults.ts
|
|
29577
|
-
function
|
|
31068
|
+
function makeDefaultDeps3(fs) {
|
|
29578
31069
|
return {
|
|
29579
31070
|
expandPatterns: (patterns, cwd, logger) => expandPatterns(patterns, cwd, logger, fs),
|
|
29580
31071
|
resolveDepsRoot: (args) => resolveDepsRoot({ ...args, fs }),
|
|
@@ -29586,7 +31077,7 @@ function makeDefaultDeps2(fs) {
|
|
|
29586
31077
|
};
|
|
29587
31078
|
}
|
|
29588
31079
|
async function handleFlowsRun(ctx, pattern, flags, deps, selectors = { tags: [] }, allEnvs = false) {
|
|
29589
|
-
const resolvedDeps = deps ??
|
|
31080
|
+
const resolvedDeps = deps ?? makeDefaultDeps3(ctx.fs);
|
|
29590
31081
|
const cwd = process.cwd();
|
|
29591
31082
|
const expandedFiles = await resolvedDeps.expandPatterns(buildPatternArgs(pattern), cwd, ctx.log("flows"));
|
|
29592
31083
|
ctx.log("flows").debug(`discovered ${pluralize(expandedFiles.length, "flow")}`);
|
|
@@ -29635,7 +31126,7 @@ async function chooseEnv(ctx, files, allEnvs) {
|
|
|
29635
31126
|
}
|
|
29636
31127
|
|
|
29637
31128
|
// src/commands/flows/hybridRunDefaults.ts
|
|
29638
|
-
import { join as
|
|
31129
|
+
import { join as join46, resolve as resolve10 } from "node:path";
|
|
29639
31130
|
|
|
29640
31131
|
// src/core/selectFlowFiles.ts
|
|
29641
31132
|
function selectFlowFiles(args) {
|
|
@@ -29740,7 +31231,7 @@ async function handleHybridFlowsRun(ctx, pattern, flags, options = {}) {
|
|
|
29740
31231
|
if (validation !== "ok") {
|
|
29741
31232
|
return { error: validation.error, exitCode: 2 };
|
|
29742
31233
|
}
|
|
29743
|
-
const envDir = resolve10(
|
|
31234
|
+
const envDir = resolve10(join46(".qawolf", flags.env));
|
|
29744
31235
|
const patternArgs = buildPatternArgs(pattern);
|
|
29745
31236
|
const globFlows = () => resolvedDeps.expandPatterns(patternArgs, envDir, ctx.log("flows"));
|
|
29746
31237
|
let files = await globFlows();
|
|
@@ -29936,12 +31427,12 @@ function registerFlowsCommand(program, signals, deps = { withResolvedEnv }) {
|
|
|
29936
31427
|
}
|
|
29937
31428
|
|
|
29938
31429
|
// src/domains/init/init.ts
|
|
29939
|
-
import { dirname as dirname14, join as
|
|
31430
|
+
import { dirname as dirname14, join as join48, relative as relative9 } from "node:path";
|
|
29940
31431
|
|
|
29941
31432
|
// src/domains/init/ensurePackageJson.ts
|
|
29942
|
-
import { join as
|
|
31433
|
+
import { join as join47 } from "node:path";
|
|
29943
31434
|
async function ensurePackageJson(ctx, yes, deps) {
|
|
29944
|
-
const pkgPath =
|
|
31435
|
+
const pkgPath = join47(deps.cwd, "package.json");
|
|
29945
31436
|
if (!await deps.fs.pathExists(pkgPath)) {
|
|
29946
31437
|
const confirmed = await ctx.ui.confirm(initMessages.createPackageJsonPrompt, { yes });
|
|
29947
31438
|
if (!confirmed.ok || !confirmed.value) {
|
|
@@ -30067,9 +31558,9 @@ function makeDefaultInitDeps() {
|
|
|
30067
31558
|
async function handleInit(ctx, opts, deps = makeDefaultInitDeps()) {
|
|
30068
31559
|
ctx.ui.gap();
|
|
30069
31560
|
ctx.ui.intro(initMessages.title);
|
|
30070
|
-
const configPath =
|
|
30071
|
-
const flowPath =
|
|
30072
|
-
const gitignorePath =
|
|
31561
|
+
const configPath = join48(deps.cwd, "qawolf.config.ts");
|
|
31562
|
+
const flowPath = join48(deps.cwd, "src", "flows", "example.flow.ts");
|
|
31563
|
+
const gitignorePath = join48(deps.cwd, ".qawolf", ".gitignore");
|
|
30073
31564
|
await writeWithPrompt(ctx, configPath, qawolfConfigTs, opts.yes, deps);
|
|
30074
31565
|
await writeWithPrompt(ctx, flowPath, exampleFlowTs, opts.yes, deps);
|
|
30075
31566
|
await writeWithPrompt(ctx, gitignorePath, qawolfGitignore, opts.yes, deps);
|
|
@@ -30107,7 +31598,7 @@ Examples:
|
|
|
30107
31598
|
import { parseExecutionTarget as parseExecutionTarget4 } from "@qawolf/flow-targets";
|
|
30108
31599
|
|
|
30109
31600
|
// src/domains/install/android/avd.ts
|
|
30110
|
-
import { join as
|
|
31601
|
+
import { join as join49 } from "node:path";
|
|
30111
31602
|
async function installAvds(ctx, specs, deps) {
|
|
30112
31603
|
const sdkManagerPath = sdkManagerBin(deps.androidHome, deps.platform);
|
|
30113
31604
|
const avdManagerPath = avdManagerBin(deps.androidHome, deps.platform);
|
|
@@ -30117,7 +31608,7 @@ async function installAvds(ctx, specs, deps) {
|
|
|
30117
31608
|
if (versionResult.exitCode !== 0) {
|
|
30118
31609
|
throw new Error(installMessages.android.sdkmanagerNotFound(sdkManagerPath));
|
|
30119
31610
|
}
|
|
30120
|
-
const licenseFile =
|
|
31611
|
+
const licenseFile = join49(deps.androidHome, "licenses", "android-sdk-license");
|
|
30121
31612
|
if (deps.checkExists(licenseFile)) {
|
|
30122
31613
|
ctx.ui.info(installMessages.android.licensesAlreadyAccepted);
|
|
30123
31614
|
} else {
|
|
@@ -30132,7 +31623,7 @@ async function installAvds(ctx, specs, deps) {
|
|
|
30132
31623
|
for (const spec of specs) {
|
|
30133
31624
|
if (installedImages.has(spec.systemImage))
|
|
30134
31625
|
continue;
|
|
30135
|
-
const systemImg =
|
|
31626
|
+
const systemImg = join49(deps.androidHome, ...spec.systemImage.split(";"), "system.img");
|
|
30136
31627
|
if (deps.checkExists(systemImg)) {
|
|
30137
31628
|
ctx.ui.info(installMessages.android.systemImageAlreadyInstalled(spec.systemImage));
|
|
30138
31629
|
installedImages.add(spec.systemImage);
|
|
@@ -30430,42 +31921,6 @@ Examples:
|
|
|
30430
31921
|
});
|
|
30431
31922
|
}
|
|
30432
31923
|
|
|
30433
|
-
// src/core/publicApi/flagKind.ts
|
|
30434
|
-
function flagKind(schema) {
|
|
30435
|
-
if (schema.type === "string")
|
|
30436
|
-
return { ok: true, kind: "string" };
|
|
30437
|
-
if (schema.type === "number" || schema.type === "integer") {
|
|
30438
|
-
return { ok: true, kind: "number" };
|
|
30439
|
-
}
|
|
30440
|
-
if (schema.type === "boolean")
|
|
30441
|
-
return { ok: true, kind: "boolean" };
|
|
30442
|
-
if (schema.type === "array") {
|
|
30443
|
-
if (schema.items?.type !== "string") {
|
|
30444
|
-
return {
|
|
30445
|
-
ok: false,
|
|
30446
|
-
reason: "only string arrays can be expressed as flags"
|
|
30447
|
-
};
|
|
30448
|
-
}
|
|
30449
|
-
return { ok: true, kind: "string-array" };
|
|
30450
|
-
}
|
|
30451
|
-
if (schema.type === "object") {
|
|
30452
|
-
if (schema.properties) {
|
|
30453
|
-
return {
|
|
30454
|
-
ok: false,
|
|
30455
|
-
reason: "nested objects cannot be expressed as flags"
|
|
30456
|
-
};
|
|
30457
|
-
}
|
|
30458
|
-
if (typeof schema.additionalProperties === "object" && schema.additionalProperties.type === "string") {
|
|
30459
|
-
return { ok: true, kind: "key-value-record" };
|
|
30460
|
-
}
|
|
30461
|
-
return { ok: false, reason: "nested objects cannot be expressed as flags" };
|
|
30462
|
-
}
|
|
30463
|
-
return {
|
|
30464
|
-
ok: false,
|
|
30465
|
-
reason: `type ${schema.type ?? "unknown"} cannot be expressed as a flag`
|
|
30466
|
-
};
|
|
30467
|
-
}
|
|
30468
|
-
|
|
30469
31924
|
// src/core/publicApi/flagNames.ts
|
|
30470
31925
|
var kebabCase = (segment) => segment.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
|
|
30471
31926
|
var capitalize = (segment) => `${segment.slice(0, 1).toUpperCase()}${segment.slice(1)}`;
|
|
@@ -30484,108 +31939,6 @@ function flagUsage(path, kind) {
|
|
|
30484
31939
|
return `${name} <value>`;
|
|
30485
31940
|
}
|
|
30486
31941
|
|
|
30487
|
-
// src/core/publicApi/objectShape.ts
|
|
30488
|
-
var asObjectShape = (schema) => schema.type === "object" && schema.properties ? { properties: schema.properties, required: new Set(schema.required) } : undefined;
|
|
30489
|
-
function mergeIntersection(members) {
|
|
30490
|
-
const shape = { properties: {}, required: new Set };
|
|
30491
|
-
for (const member of members) {
|
|
30492
|
-
const memberShape = asObjectShape(member);
|
|
30493
|
-
if (!memberShape) {
|
|
30494
|
-
return {
|
|
30495
|
-
ok: false,
|
|
30496
|
-
field: "",
|
|
30497
|
-
reason: "intersection members must be object schemas"
|
|
30498
|
-
};
|
|
30499
|
-
}
|
|
30500
|
-
for (const [field, fieldSchema] of Object.entries(memberShape.properties)) {
|
|
30501
|
-
if (field in shape.properties) {
|
|
30502
|
-
return {
|
|
30503
|
-
ok: false,
|
|
30504
|
-
field,
|
|
30505
|
-
reason: "field appears in multiple intersection members"
|
|
30506
|
-
};
|
|
30507
|
-
}
|
|
30508
|
-
shape.properties[field] = fieldSchema;
|
|
30509
|
-
if (memberShape.required.has(field))
|
|
30510
|
-
shape.required.add(field);
|
|
30511
|
-
}
|
|
30512
|
-
}
|
|
30513
|
-
return { ok: true, shape };
|
|
30514
|
-
}
|
|
30515
|
-
function mergeUnion(branches) {
|
|
30516
|
-
const shapes = [];
|
|
30517
|
-
for (const branch of branches) {
|
|
30518
|
-
const branchShape = asObjectShape(branch);
|
|
30519
|
-
if (!branchShape) {
|
|
30520
|
-
return {
|
|
30521
|
-
ok: false,
|
|
30522
|
-
field: "",
|
|
30523
|
-
reason: "union branches must be object schemas"
|
|
30524
|
-
};
|
|
30525
|
-
}
|
|
30526
|
-
shapes.push(branchShape);
|
|
30527
|
-
}
|
|
30528
|
-
const shape = { properties: {}, required: new Set };
|
|
30529
|
-
for (const branchShape of shapes) {
|
|
30530
|
-
for (const [field, fieldSchema] of Object.entries(branchShape.properties)) {
|
|
30531
|
-
const existing = shape.properties[field];
|
|
30532
|
-
if (!existing) {
|
|
30533
|
-
shape.properties[field] = { ...fieldSchema };
|
|
30534
|
-
continue;
|
|
30535
|
-
}
|
|
30536
|
-
const kinds = [flagKind(existing), flagKind(fieldSchema)];
|
|
30537
|
-
if (kinds[0]?.ok && kinds[1]?.ok) {
|
|
30538
|
-
if (kinds[0].kind !== kinds[1].kind) {
|
|
30539
|
-
return {
|
|
30540
|
-
ok: false,
|
|
30541
|
-
field,
|
|
30542
|
-
reason: "field has conflicting types across union branches"
|
|
30543
|
-
};
|
|
30544
|
-
}
|
|
30545
|
-
} else if (JSON.stringify({ ...existing, description: undefined }) !== JSON.stringify({ ...fieldSchema, description: undefined })) {
|
|
30546
|
-
return {
|
|
30547
|
-
ok: false,
|
|
30548
|
-
field,
|
|
30549
|
-
reason: "field has conflicting object schemas across union branches"
|
|
30550
|
-
};
|
|
30551
|
-
}
|
|
30552
|
-
if (!existing.description && fieldSchema.description) {
|
|
30553
|
-
existing.description = fieldSchema.description;
|
|
30554
|
-
}
|
|
30555
|
-
}
|
|
30556
|
-
}
|
|
30557
|
-
const discriminator = Object.keys(shape.properties).find((field) => {
|
|
30558
|
-
const values = shapes.map((branch) => branch.properties[field]?.const);
|
|
30559
|
-
return values.every((value) => typeof value === "string") && new Set(values).size === shapes.length && shapes.every((branch) => branch.required.has(field));
|
|
30560
|
-
});
|
|
30561
|
-
for (const [field, fieldSchema] of Object.entries(shape.properties)) {
|
|
30562
|
-
const occurrences = shapes.filter((branch) => (field in branch.properties));
|
|
30563
|
-
if (occurrences.length === shapes.length && occurrences.every((branch) => branch.required.has(field))) {
|
|
30564
|
-
shape.required.add(field);
|
|
30565
|
-
}
|
|
30566
|
-
if (field === discriminator) {
|
|
30567
|
-
const values = shapes.map((branch) => branch.properties[field]?.const);
|
|
30568
|
-
fieldSchema.description = `One of: ${values.join(", ")}`;
|
|
30569
|
-
}
|
|
30570
|
-
}
|
|
30571
|
-
return { ok: true, shape };
|
|
30572
|
-
}
|
|
30573
|
-
function toObjectShape(schema) {
|
|
30574
|
-
if (schema.allOf)
|
|
30575
|
-
return mergeIntersection(schema.allOf);
|
|
30576
|
-
const branches = schema.oneOf ?? schema.anyOf;
|
|
30577
|
-
if (branches)
|
|
30578
|
-
return mergeUnion(branches);
|
|
30579
|
-
const shape = asObjectShape(schema);
|
|
30580
|
-
if (shape)
|
|
30581
|
-
return { ok: true, shape };
|
|
30582
|
-
return {
|
|
30583
|
-
ok: false,
|
|
30584
|
-
field: "",
|
|
30585
|
-
reason: "contract input must be an object schema"
|
|
30586
|
-
};
|
|
30587
|
-
}
|
|
30588
|
-
|
|
30589
31942
|
// src/core/publicApi/flagSpecs.ts
|
|
30590
31943
|
function describeFlag(schema) {
|
|
30591
31944
|
const description = schema.description ?? "";
|
|
@@ -31039,7 +32392,7 @@ function describeFailure(failureReason) {
|
|
|
31039
32392
|
}
|
|
31040
32393
|
|
|
31041
32394
|
// src/shell/interactiveRunner/collectRunFiles.ts
|
|
31042
|
-
import { join as
|
|
32395
|
+
import { join as join51 } from "node:path";
|
|
31043
32396
|
|
|
31044
32397
|
// src/core/interactiveRunner/getImports.ts
|
|
31045
32398
|
function getImports(options) {
|
|
@@ -31078,7 +32431,7 @@ function isPathAlias(importPath, paths) {
|
|
|
31078
32431
|
}
|
|
31079
32432
|
|
|
31080
32433
|
// src/core/interactiveRunner/resolveImportPath.ts
|
|
31081
|
-
import { dirname as dirname15, join as
|
|
32434
|
+
import { dirname as dirname15, join as join50, normalize as normalize3 } from "node:path/posix";
|
|
31082
32435
|
|
|
31083
32436
|
// src/core/interactiveRunner/tsconfigPaths.ts
|
|
31084
32437
|
function isRecord4(value) {
|
|
@@ -31131,7 +32484,7 @@ function candidatesForExplicitExtension(options) {
|
|
|
31131
32484
|
}
|
|
31132
32485
|
function resolveImportPath(options) {
|
|
31133
32486
|
const aliasTarget = resolvePathAlias(options.importPath, options.tsconfigPaths);
|
|
31134
|
-
const resolvedPath = aliasTarget === undefined ?
|
|
32487
|
+
const resolvedPath = aliasTarget === undefined ? normalize3(join50(dirname15(options.importingFilePath), options.importPath)) : normalize3(aliasTarget);
|
|
31135
32488
|
const hasExplicitExtension = supportedExtensions.some((extension) => options.importPath.endsWith(extension));
|
|
31136
32489
|
const candidates = hasExplicitExtension ? candidatesForExplicitExtension({
|
|
31137
32490
|
importPath: options.importPath,
|
|
@@ -31155,7 +32508,7 @@ function resolveImportPath(options) {
|
|
|
31155
32508
|
var tsconfigPath = "tsconfig.json";
|
|
31156
32509
|
async function collectRunFiles(options) {
|
|
31157
32510
|
const held = await listShippablePaths(options);
|
|
31158
|
-
const readFile = (path) => options.fs.readFile(
|
|
32511
|
+
const readFile = (path) => options.fs.readFile(join51(options.cwd, path));
|
|
31159
32512
|
const tsconfigContent = held.has(tsconfigPath) ? await readFile(tsconfigPath).catch(() => {
|
|
31160
32513
|
return;
|
|
31161
32514
|
}) : undefined;
|
|
@@ -31232,13 +32585,13 @@ async function walkImportGraph(options) {
|
|
|
31232
32585
|
}
|
|
31233
32586
|
|
|
31234
32587
|
// src/shell/interactiveRunner/makeRunnerId.ts
|
|
31235
|
-
import { randomUUID } from "node:crypto";
|
|
32588
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
31236
32589
|
function makeRunnerId() {
|
|
31237
|
-
return `cli-${
|
|
32590
|
+
return `cli-${randomUUID2().replaceAll("-", "").slice(0, 12)}`;
|
|
31238
32591
|
}
|
|
31239
32592
|
|
|
31240
32593
|
// src/shell/interactiveRunner/runFilesManifest.ts
|
|
31241
|
-
import { join as
|
|
32594
|
+
import { join as join52 } from "node:path";
|
|
31242
32595
|
var manifestFileName = "runner-files.json";
|
|
31243
32596
|
var manifestSchema2 = object({
|
|
31244
32597
|
files: array(object({ contentHash: string2(), path: string2() })),
|
|
@@ -31246,8 +32599,8 @@ var manifestSchema2 = object({
|
|
|
31246
32599
|
version: literal(1)
|
|
31247
32600
|
});
|
|
31248
32601
|
function makeRunFilesManifestStore(options) {
|
|
31249
|
-
const directory =
|
|
31250
|
-
const path =
|
|
32602
|
+
const directory = join52(options.cwd, qawolfDir);
|
|
32603
|
+
const path = join52(directory, manifestFileName);
|
|
31251
32604
|
let pendingWrites = 0;
|
|
31252
32605
|
return {
|
|
31253
32606
|
async read() {
|
|
@@ -31277,7 +32630,7 @@ function parseJson(text) {
|
|
|
31277
32630
|
}
|
|
31278
32631
|
|
|
31279
32632
|
// src/shell/interactiveRunner/runnerStore.ts
|
|
31280
|
-
import { join as
|
|
32633
|
+
import { join as join53 } from "node:path";
|
|
31281
32634
|
var storeFileName = "runner.json";
|
|
31282
32635
|
var runnersDirName = "runners";
|
|
31283
32636
|
var storedRunnerSchema = object({
|
|
@@ -31296,11 +32649,11 @@ function parseJson2(text) {
|
|
|
31296
32649
|
}
|
|
31297
32650
|
var pendingWrites = 0;
|
|
31298
32651
|
function makeRunnerStore(options) {
|
|
31299
|
-
const directory =
|
|
31300
|
-
const path =
|
|
31301
|
-
const runnersDir =
|
|
32652
|
+
const directory = join53(options.cwd, qawolfDir);
|
|
32653
|
+
const path = join53(directory, storeFileName);
|
|
32654
|
+
const runnersDir = join53(directory, runnersDirName);
|
|
31302
32655
|
const nextPendingPath = (target) => `${target}.${process.pid}.${++pendingWrites}.tmp`;
|
|
31303
|
-
const runnerPath = (runnerId) =>
|
|
32656
|
+
const runnerPath = (runnerId) => join53(runnersDir, `${encodeURIComponent(runnerId)}.json`);
|
|
31304
32657
|
const writeAtomically = async (target, contents) => {
|
|
31305
32658
|
const pendingPath = nextPendingPath(target);
|
|
31306
32659
|
await options.fs.writeFile(pendingPath, `${JSON.stringify(contents, undefined, 2)}
|
|
@@ -31337,7 +32690,7 @@ function makeRunnerStore(options) {
|
|
|
31337
32690
|
readDefaultRunnerId,
|
|
31338
32691
|
async readRunners() {
|
|
31339
32692
|
const runners = await Promise.all((await readRunnerFileNames()).map(async (name) => {
|
|
31340
|
-
const contents = await options.fs.readFile(
|
|
32693
|
+
const contents = await options.fs.readFile(join53(runnersDir, name)).catch(() => {
|
|
31341
32694
|
return;
|
|
31342
32695
|
});
|
|
31343
32696
|
if (contents === undefined)
|
|
@@ -31356,7 +32709,7 @@ function makeRunnerStore(options) {
|
|
|
31356
32709
|
await Promise.all(runnerIds.map((runnerId) => options.fs.rm(runnerPath(runnerId), { force: true })));
|
|
31357
32710
|
const names = await readRunnerFileNames();
|
|
31358
32711
|
await Promise.all(names.map(async (name) => {
|
|
31359
|
-
const runnerFile =
|
|
32712
|
+
const runnerFile = join53(runnersDir, name);
|
|
31360
32713
|
const contents = await options.fs.readFile(runnerFile).catch(() => {
|
|
31361
32714
|
return;
|
|
31362
32715
|
});
|
|
@@ -31440,7 +32793,7 @@ function registerRunnerHighlightSelectorCommand(runner, signals) {
|
|
|
31440
32793
|
}
|
|
31441
32794
|
|
|
31442
32795
|
// src/domains/interactiveRunner/importPackage.ts
|
|
31443
|
-
import { join as
|
|
32796
|
+
import { join as join54 } from "node:path";
|
|
31444
32797
|
|
|
31445
32798
|
// src/core/interactiveRunner/npmDependencies.ts
|
|
31446
32799
|
var sectionsInPrecedenceOrder = ["dependencies", "devDependencies"];
|
|
@@ -31481,7 +32834,7 @@ function readNpmDependencies(packageJsonContent) {
|
|
|
31481
32834
|
// src/domains/interactiveRunner/importPackage.ts
|
|
31482
32835
|
var defaultPackageVersion = "latest";
|
|
31483
32836
|
async function handleRunnerImportPackage(ctx, options, deps) {
|
|
31484
|
-
const content = await deps.readFile(
|
|
32837
|
+
const content = await deps.readFile(join54(deps.cwd, runPackageJsonPath)).catch(() => {
|
|
31485
32838
|
return;
|
|
31486
32839
|
});
|
|
31487
32840
|
if (content === undefined) {
|
|
@@ -33205,4 +34558,4 @@ createProgram({ signals }).parseAsync().catch(() => {
|
|
|
33205
34558
|
process.exitCode = 1;
|
|
33206
34559
|
}).finally(() => flushAndExit(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
33207
34560
|
|
|
33208
|
-
//# debugId=
|
|
34561
|
+
//# debugId=DA8D4A9E373CFE5C64756E2164756E21
|