@qawolf/cli 1.26.0 → 1.28.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 +1061 -266
- package/dist/runner-sdk.js +715 -29
- package/dist/types/runnerSdk/index.d.ts +1 -1
- package/dist/types/runnerSdk/types.d.ts +7 -0
- package/package.json +2 -2
- package/skills/qawolf-cli/SKILL.md +19 -4
- package/skills/qawolf-cli/references/runner.md +20 -5
package/dist/runner-sdk.js
CHANGED
|
@@ -6998,6 +6998,72 @@ var makeEmailAddressResourceSchema = () => resource({
|
|
|
6998
6998
|
isDefault: boolean2().describe("Whether this is the workspace's default inbox address.")
|
|
6999
6999
|
}, { urlFieldDescription: emailUrlFieldDescription });
|
|
7000
7000
|
|
|
7001
|
+
// node_modules/@qawolf/api-contracts/dist/v1/file/path.js
|
|
7002
|
+
var uploadedFilePrefix = "uploads";
|
|
7003
|
+
var controlOrBackslash = /[\p{Cc}\\]/u;
|
|
7004
|
+
var shellMetacharacter = /["'`$;|&<>]/u;
|
|
7005
|
+
var segmentsOf = (path) => path.split("/");
|
|
7006
|
+
var teamStoragePathSchema = string2().min(1).max(200).refine((path) => !controlOrBackslash.test(path), "A path cannot carry control characters or a backslash.").refine((path) => !shellMetacharacter.test(path), "A path cannot carry a quote, a backtick, or any of $ ; | & < >. A reader passes the path to a shell, where those change what runs.").refine((path) => segmentsOf(path).every((segment) => segment.length > 0), "A path cannot start or end with a slash, or carry an empty segment.").refine((path) => segmentsOf(path).every((segment) => segment !== "." && segment !== ".."), "A path cannot climb out of the team's storage.").refine((path) => segmentsOf(path).every((segment) => segment.trim() === segment), "A path cannot have leading or trailing whitespace in a segment.");
|
|
7007
|
+
var uploadedFilePath = (fileName) => `${uploadedFilePrefix}/${fileName}`;
|
|
7008
|
+
var uploadedFileNameSchema = teamStoragePathSchema.refine((fileName) => teamStoragePathSchema.safeParse(uploadedFilePath(fileName)).success, `A name has to still be a valid path once it sits under \`${uploadedFilePrefix}/\`, which every other endpoint reads it back as.`);
|
|
7009
|
+
|
|
7010
|
+
// node_modules/@qawolf/api-contracts/dist/v1/file/requestDownload.js
|
|
7011
|
+
var makeRequestFileDownloadContract = (ids) => {
|
|
7012
|
+
const input = object({
|
|
7013
|
+
filePath: teamStoragePathSchema.describe("The file's path in team storage, as file.requestUpload answered with."),
|
|
7014
|
+
workspaceId: ids.workspace.optional().describe("The workspace the file belongs to. Required when authenticating with an organization or user API key.")
|
|
7015
|
+
});
|
|
7016
|
+
const output = object({
|
|
7017
|
+
expiresAt: exports_iso.datetime().describe("When readUrl stops working. Request another one after it."),
|
|
7018
|
+
path: string2().describe("The file's path in team storage."),
|
|
7019
|
+
readUrl: string2().describe('Fetch the file\'s bytes from here, for example `curl -o journeys.csv "<readUrl>"`. Write it to a file and read that file, rather than printing the contents, so a large file costs one line of output instead of all of it.')
|
|
7020
|
+
});
|
|
7021
|
+
return {
|
|
7022
|
+
annotations: {
|
|
7023
|
+
destructiveHint: false,
|
|
7024
|
+
openWorldHint: false,
|
|
7025
|
+
readOnlyHint: true
|
|
7026
|
+
},
|
|
7027
|
+
description: "Get a URL for reading a file out of the caller's team storage. Answers 404 when nothing is stored at that path.",
|
|
7028
|
+
input,
|
|
7029
|
+
kind: "read",
|
|
7030
|
+
name: "file.requestDownload",
|
|
7031
|
+
output
|
|
7032
|
+
};
|
|
7033
|
+
};
|
|
7034
|
+
|
|
7035
|
+
// node_modules/@qawolf/api-contracts/dist/v1/file/requestUpload.js
|
|
7036
|
+
var makeRequestFileUploadContract = (ids) => {
|
|
7037
|
+
const input = object({
|
|
7038
|
+
fileName: uploadedFileNameSchema.describe("What to call the file, such as `journeys.csv` or `q3/journeys.csv`. Spaces and non-ASCII are fine; backslashes, leading slashes and `..` segments are refused. The same name replaces the file."),
|
|
7039
|
+
workspaceId: ids.workspace.optional().describe("The workspace to upload into. Required when authenticating with an organization or user API key.")
|
|
7040
|
+
});
|
|
7041
|
+
const output = object({
|
|
7042
|
+
contentType: string2().describe("Send this as the PUT's `Content-Type` header, exactly. The URL is signed for it and refuses any other value."),
|
|
7043
|
+
expiresAt: exports_iso.datetime().describe("When uploadUrl stops working. Request another one after it."),
|
|
7044
|
+
path: string2().describe("Where the file lives in team storage. Send this to agent.send as a filePath, and the AI fetches it from there."),
|
|
7045
|
+
uploadUrl: string2().describe(`Send the file's bytes here with a single HTTP PUT carrying the returned contentType, for example \`curl -H 'Content-Type: application/octet-stream' --upload-file "journeys.csv" "<uploadUrl>"\`. Upload the bytes from the shell rather than through this API, so a large file never has to be written out as text.`)
|
|
7046
|
+
});
|
|
7047
|
+
return {
|
|
7048
|
+
annotations: {
|
|
7049
|
+
destructiveHint: true,
|
|
7050
|
+
openWorldHint: false,
|
|
7051
|
+
readOnlyHint: false
|
|
7052
|
+
},
|
|
7053
|
+
description: "Get a URL to put a file into team storage: a spreadsheet of journeys, anything too large to paste. PUT with the returned contentType, then name the path in filePaths.",
|
|
7054
|
+
input,
|
|
7055
|
+
kind: "write",
|
|
7056
|
+
name: "file.requestUpload",
|
|
7057
|
+
output
|
|
7058
|
+
};
|
|
7059
|
+
};
|
|
7060
|
+
|
|
7061
|
+
// node_modules/@qawolf/api-contracts/dist/v1/file/index.js
|
|
7062
|
+
var makeFileContracts = (ids) => ({
|
|
7063
|
+
requestDownload: makeRequestFileDownloadContract(ids),
|
|
7064
|
+
requestUpload: makeRequestFileUploadContract(ids)
|
|
7065
|
+
});
|
|
7066
|
+
|
|
7001
7067
|
// node_modules/@qawolf/api-contracts/dist/v1/identity/organization.js
|
|
7002
7068
|
var identityOrganization = object({
|
|
7003
7069
|
id: string2(),
|
|
@@ -7054,6 +7120,7 @@ var defaultIdSchemas = {
|
|
|
7054
7120
|
flow: string2().min(1).describe("The id of the flow."),
|
|
7055
7121
|
issue: string2().min(1).describe("The id of the issue."),
|
|
7056
7122
|
run: string2().min(1).describe("The id of the run."),
|
|
7123
|
+
trigger: string2().min(1).describe("The id of the trigger."),
|
|
7057
7124
|
workspace: string2().min(1).describe("The id of the workspace.")
|
|
7058
7125
|
};
|
|
7059
7126
|
|
|
@@ -7089,6 +7156,11 @@ var makeCreateRunContract = (ids) => {
|
|
|
7089
7156
|
tracking: _enum(["registered", "failed", "not-requested"]).describe('Whether the conversation named by aiTaskId or chatSessionId will receive run status updates: "registered" when it will, "failed" when the run was created but the registration failed, "not-requested" when neither id was given or the AI task has no conversation to notify.')
|
|
7090
7157
|
}, { urlFieldDescription: "Absolute URL of the run page." });
|
|
7091
7158
|
return {
|
|
7159
|
+
annotations: {
|
|
7160
|
+
destructiveHint: true,
|
|
7161
|
+
openWorldHint: true,
|
|
7162
|
+
readOnlyHint: false
|
|
7163
|
+
},
|
|
7092
7164
|
description: "Create a run for the selected flows and/or tags in an environment.",
|
|
7093
7165
|
input,
|
|
7094
7166
|
kind: "write",
|
|
@@ -7227,7 +7299,8 @@ var runnerIdSchema = string2().min(1).max(63).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9
|
|
|
7227
7299
|
var makeRunnerSchema = () => object({
|
|
7228
7300
|
gpuAccelerated: boolean2().describe("Whether the runner was placed on GPU hardware. Chosen by QA Wolf from the team's configuration and what the fleet can provide, not requested."),
|
|
7229
7301
|
id: runnerIdSchema.describe("The runner's id, as supplied when launching it."),
|
|
7230
|
-
runnerName: runnerNameSchema.describe("The runner family requested when the runner was launched. QA Wolf may place it on faster hardware, reported in gpuAccelerated.")
|
|
7302
|
+
runnerName: runnerNameSchema.describe("The runner family requested when the runner was launched. QA Wolf may place it on faster hardware, reported in gpuAccelerated."),
|
|
7303
|
+
url: url().describe("A QA Wolf page showing what the runner is doing right now, where the person who launched it can watch and take over with their own mouse and keyboard. Opening it requires being signed in to QA Wolf.")
|
|
7231
7304
|
});
|
|
7232
7305
|
|
|
7233
7306
|
// node_modules/@qawolf/api-contracts/dist/v1/runner/unreachable.js
|
|
@@ -7273,7 +7346,12 @@ var makeInspectOnRunnerContract = (ids) => {
|
|
|
7273
7346
|
})
|
|
7274
7347
|
]);
|
|
7275
7348
|
return {
|
|
7276
|
-
|
|
7349
|
+
annotations: {
|
|
7350
|
+
destructiveHint: false,
|
|
7351
|
+
openWorldHint: false,
|
|
7352
|
+
readOnlyHint: false
|
|
7353
|
+
},
|
|
7354
|
+
description: "Inspect one thing on an interactive runner: an element's HTML, the page's HTML simplified for a model, or a top-level variable's value as JSON. This refreshes the inactivity timer and can extend the runner's billed lifetime. `nothing-to-inspect` means the runner had nothing to answer with: no live page, no element matching the selector, or no variable under that name. A runner cannot tell those apart, so it reports the one reason and puts whatever it did say in `errorMessage`. `runner-is-not-a-browser` on a mobile runner — call `runner.inspectMobile` for its equivalent surface instead. " + retryableRunnerUnreachableDescription,
|
|
7277
7355
|
input,
|
|
7278
7356
|
kind: "read",
|
|
7279
7357
|
name: "runner.inspect",
|
|
@@ -7334,6 +7412,30 @@ function makeRunnerFailureSchema(reasons) {
|
|
|
7334
7412
|
|
|
7335
7413
|
// node_modules/@qawolf/api-contracts/dist/v1/runner/inspectMobile.js
|
|
7336
7414
|
var maxElementTextLength = 500;
|
|
7415
|
+
var selectorStrategySchema = _enum(["ios-predicate", "shadow", "xpath"]);
|
|
7416
|
+
var elementsRequestSchema = discriminatedUnion("by", [
|
|
7417
|
+
object({
|
|
7418
|
+
by: literal("point"),
|
|
7419
|
+
context: string2().min(1).optional(),
|
|
7420
|
+
what: literal("elements"),
|
|
7421
|
+
x: int().min(0).describe("Whole pixels on the device's own screen."),
|
|
7422
|
+
y: int().min(0).describe("Whole pixels on the device's own screen.")
|
|
7423
|
+
}),
|
|
7424
|
+
object({
|
|
7425
|
+
by: literal("text"),
|
|
7426
|
+
context: string2().min(1).optional(),
|
|
7427
|
+
partial: boolean2().optional().describe("Match text containing this, rather than exactly this."),
|
|
7428
|
+
text: string2().min(1).max(maxElementTextLength),
|
|
7429
|
+
what: literal("elements")
|
|
7430
|
+
}),
|
|
7431
|
+
object({
|
|
7432
|
+
by: literal("selector"),
|
|
7433
|
+
context: string2().min(1).optional(),
|
|
7434
|
+
selector: string2().min(1).max(maxSelectorLength).describe("Resolved the same way a screen object's own selector is."),
|
|
7435
|
+
strategy: selectorStrategySchema.default("xpath"),
|
|
7436
|
+
what: literal("elements")
|
|
7437
|
+
})
|
|
7438
|
+
]).describe("Elements at a screen point, elements carrying some text, or the elements a selector resolves to.");
|
|
7337
7439
|
var inspectMobileRequestSchema = discriminatedUnion("what", [
|
|
7338
7440
|
object({
|
|
7339
7441
|
what: literal("session").describe("The status of the Appium session driving the device: ready and what it is, or why not.")
|
|
@@ -7345,22 +7447,7 @@ var inspectMobileRequestSchema = discriminatedUnion("what", [
|
|
|
7345
7447
|
context: string2().min(1).optional().describe("Read this context instead of whichever is current."),
|
|
7346
7448
|
what: literal("page").describe("The page source of the device's current context, as a tree.")
|
|
7347
7449
|
}),
|
|
7348
|
-
|
|
7349
|
-
object({
|
|
7350
|
-
by: literal("point"),
|
|
7351
|
-
context: string2().min(1).optional(),
|
|
7352
|
-
what: literal("elements"),
|
|
7353
|
-
x: int().min(0).describe("Whole pixels on the device's own screen."),
|
|
7354
|
-
y: int().min(0).describe("Whole pixels on the device's own screen.")
|
|
7355
|
-
}),
|
|
7356
|
-
object({
|
|
7357
|
-
by: literal("text"),
|
|
7358
|
-
context: string2().min(1).optional(),
|
|
7359
|
-
partial: boolean2().optional().describe("Match text containing this, rather than exactly this."),
|
|
7360
|
-
text: string2().min(1).max(maxElementTextLength),
|
|
7361
|
-
what: literal("elements")
|
|
7362
|
-
})
|
|
7363
|
-
]).describe("Elements at a screen point, or elements carrying some text — never both at once.")
|
|
7450
|
+
elementsRequestSchema
|
|
7364
7451
|
]);
|
|
7365
7452
|
var inspectMobileAnswerSchema = discriminatedUnion("what", [
|
|
7366
7453
|
object({
|
|
@@ -7412,6 +7499,7 @@ var makeInspectMobileOnRunnerContract = (ids) => {
|
|
|
7412
7499
|
const output = discriminatedUnion("outcome", [
|
|
7413
7500
|
inspectMobileAnswerSchema,
|
|
7414
7501
|
makeRunnerFailureSchema([
|
|
7502
|
+
"invalid-selector",
|
|
7415
7503
|
"runner-is-not-mobile",
|
|
7416
7504
|
"screen-needs-a-run",
|
|
7417
7505
|
"screen-not-ready",
|
|
@@ -7419,7 +7507,12 @@ var makeInspectMobileOnRunnerContract = (ids) => {
|
|
|
7419
7507
|
])
|
|
7420
7508
|
]);
|
|
7421
7509
|
return {
|
|
7422
|
-
|
|
7510
|
+
annotations: {
|
|
7511
|
+
destructiveHint: false,
|
|
7512
|
+
openWorldHint: false,
|
|
7513
|
+
readOnlyHint: true
|
|
7514
|
+
},
|
|
7515
|
+
description: `Inspect one thing on a mobile interactive runner: the Appium session's status, the WebView contexts available, the current context's page source, or the elements at a point, carrying some text, or matching a selector. This does not refresh the runner's inactivity timer. Mobile only — a browser runner answers \`runner-is-not-mobile\`; call \`runner.inspect\` for a browser's equivalent surface instead. \`what: "session"\` always answers with the session's own status rather than \`screen-needs-a-run\`, since that is the question it exists to answer; the other three request kinds need a live session first and answer the same \`screen-needs-a-run\` or \`screen-not-ready\` outcomes \`runner.performAction\` and \`runner.takeScreenshot\` use, instead of reading anything when there is none. \`screen-needs-a-run\` means no Appium session has started on this runner yet — call \`runner.runFlow\` with a flow that opens one, then inspect again. \`screen-not-ready\` means the runner's Appium session exists but did not answer this instant, or more than one is somehow live — retry once; if it persists, relaunch the runner. \`runner-is-not-mobile\` means there is nothing here to inspect, and retrying will never help — launch an \`android\` or \`ios\` runner instead. \`invalid-selector\` (elements by selector only) means the selector itself could not be parsed under the given \`strategy\` — distinct from a selector that parsed fine but matched nothing, which answers \`matches: []\` instead. ${retryableRunnerUnreachableDescription}`,
|
|
7423
7516
|
input,
|
|
7424
7517
|
kind: "read",
|
|
7425
7518
|
name: "runner.inspectMobile",
|
|
@@ -7529,6 +7622,11 @@ var makePerformActionOnRunnerContract = (ids) => {
|
|
|
7529
7622
|
failure
|
|
7530
7623
|
]);
|
|
7531
7624
|
return {
|
|
7625
|
+
annotations: {
|
|
7626
|
+
destructiveHint: true,
|
|
7627
|
+
openWorldHint: true,
|
|
7628
|
+
readOnlyHint: false
|
|
7629
|
+
},
|
|
7532
7630
|
description: `Perform one raw browser action on an interactive runner: click, double_click, move, drag, scroll, keypress, type, or navigate. Coordinates are whole pixels on the runner's virtual desktop, in the same space as \`runner.takeScreenshot\`. One action per request, and the runner serves one at a time. The action shapes follow the computer-use vocabulary, minus \`screenshot\` (use \`runner.takeScreenshot\`) and \`wait\` (delay on the caller's side). A success means the action took effect. \`action-failed\`, with a reason, if it reached the runner and did not take effect. On a runner image with a browser, the first action on a runner that has never run anything starts its browser and waits for it, so it can take up to a minute to answer — no \`runner.runFlow\` is needed before acting; if the browser is still starting when the wait runs out, the answer is \`screen-not-ready\` and retrying converges. On a mobile runner, the same \`screen-needs-a-run\` and \`screen-not-ready\` outcomes mean no Appium session has started yet, or it did not answer this instant; \`runner.runFlow\` is what starts one, same as a browser. \`screen-needs-a-run\` if the browser could not be started that way — usually a runner whose runs all finished without starting its desktop; call \`runner.runFlow\` with a flow that opens a browser. ${screenNotReadyDescription} A \`navigate\` does not go through the screen, so a screen that is not ready does not stop it. ${runnerHasNoScreenDescription} ${notSupportedOnMobileDescription} ${withScreenshotDescription} ${unreachableDescription}`,
|
|
7533
7631
|
input,
|
|
7534
7632
|
kind: "write",
|
|
@@ -7546,20 +7644,90 @@ var runSelectionSchema = object({
|
|
|
7546
7644
|
error: "A selection's startLine must not be after its endLine.",
|
|
7547
7645
|
path: ["startLine"]
|
|
7548
7646
|
});
|
|
7647
|
+
// node_modules/@qawolf/api-contracts/dist/v1/trigger/configuration.js
|
|
7648
|
+
var isTimezone = (value) => {
|
|
7649
|
+
try {
|
|
7650
|
+
Intl.DateTimeFormat("en-US", { timeZone: value });
|
|
7651
|
+
return true;
|
|
7652
|
+
} catch {
|
|
7653
|
+
return false;
|
|
7654
|
+
}
|
|
7655
|
+
};
|
|
7656
|
+
var triggerCadenceSchema = _enum(["hourly", "daily"]).describe("How often the schedule fires.");
|
|
7657
|
+
var triggerActionKindSchema = _enum(["createSuite", "generativeSuite"]).describe("createSuite runs the flows named by flowIds and tagNames. generativeSuite lets QA Wolf choose the flows from the deployment's changes, and is not available to a schedule.");
|
|
7658
|
+
var makeTriggerActionSchema = (ids) => object({
|
|
7659
|
+
flowIds: array(ids.flow).default([]).describe("Flows to run. Combined with tagNames."),
|
|
7660
|
+
instructions: string2().min(1).optional().describe("Guidance for QA Wolf. Applies to generativeSuite only."),
|
|
7661
|
+
investigateFailures: boolean2().optional().describe("Whether QA Wolf investigates failures in the resulting runs. Defaults to true."),
|
|
7662
|
+
kind: triggerActionKindSchema.default("createSuite"),
|
|
7663
|
+
tagNames: array(string2().min(1)).default([]).describe("Tags naming the flows to run. Combined with flowIds.")
|
|
7664
|
+
}).describe("What the trigger runs when it fires.");
|
|
7665
|
+
var makeTriggerScheduleFields = (ids) => ({
|
|
7666
|
+
action: makeTriggerActionSchema(ids),
|
|
7667
|
+
cadence: triggerCadenceSchema,
|
|
7668
|
+
environmentId: ids.environmentId.describe("The environment the scheduled runs happen in."),
|
|
7669
|
+
minuteOfHour: number2().int().min(0).max(59).optional().describe("Minutes past the hour an hourly schedule fires. Defaults to 0."),
|
|
7670
|
+
timeOfDay: string2().regex(/^([01]\d|2[0-3]):[0-5]\d$/).optional().describe('The wall clock time a daily schedule fires, as "HH:mm". Required when cadence is daily.'),
|
|
7671
|
+
timezoneId: string2().min(1).refine(isTimezone, "Expected an IANA timezone, such as America/New_York.").optional().describe("The IANA timezone that timeOfDay is read in, such as America/New_York. Required when cadence is daily.")
|
|
7672
|
+
});
|
|
7673
|
+
var makeTriggerDeploymentFields = (ids) => ({
|
|
7674
|
+
action: makeTriggerActionSchema(ids),
|
|
7675
|
+
branchPattern: string2().min(1).optional().describe("Only fire for deployments of a branch matching this pattern."),
|
|
7676
|
+
deployTargetPattern: string2().min(1).optional().describe("Only fire for deployments of an app matching this pattern. A deploy target names one app within an environment."),
|
|
7677
|
+
environmentIds: array(ids.environment).default([]).describe("Only fire for deployments to these environments. Mutually exclusive with environmentPattern."),
|
|
7678
|
+
environmentPattern: string2().min(1).optional().describe("Only fire for deployments to environments matching this pattern. Mutually exclusive with environmentIds.")
|
|
7679
|
+
});
|
|
7680
|
+
|
|
7681
|
+
// node_modules/@qawolf/api-contracts/dist/v1/trigger/resource.js
|
|
7682
|
+
var makeTriggerConfigurationSchema = (ids) => discriminatedUnion("kind", [
|
|
7683
|
+
object({
|
|
7684
|
+
...makeTriggerScheduleFields({
|
|
7685
|
+
environmentId: ids.environment,
|
|
7686
|
+
flow: ids.flow
|
|
7687
|
+
}),
|
|
7688
|
+
kind: literal("schedule")
|
|
7689
|
+
}),
|
|
7690
|
+
object({
|
|
7691
|
+
...makeTriggerDeploymentFields(ids),
|
|
7692
|
+
kind: literal("deployment")
|
|
7693
|
+
}),
|
|
7694
|
+
object({
|
|
7695
|
+
actionCount: number2().int().describe("How many actions it runs."),
|
|
7696
|
+
kind: literal("advanced"),
|
|
7697
|
+
whenCount: number2().int().describe("How many separate match conditions it has.")
|
|
7698
|
+
})
|
|
7699
|
+
]);
|
|
7700
|
+
var makeTriggerResourceSchema = (ids) => resource({
|
|
7701
|
+
configuration: makeTriggerConfigurationSchema(ids),
|
|
7702
|
+
createdAt: exports_iso.datetime(),
|
|
7703
|
+
id: ids.trigger,
|
|
7704
|
+
isPaused: boolean2().describe("A paused trigger never fires, on any path."),
|
|
7705
|
+
name: string2(),
|
|
7706
|
+
nextScheduledAt: exports_iso.datetime().optional().describe("When a schedule trigger next fires. Absent for a deployment trigger, and while a schedule trigger is paused."),
|
|
7707
|
+
pausedAt: exports_iso.datetime().optional().describe("When it was paused."),
|
|
7708
|
+
updatedAt: exports_iso.datetime()
|
|
7709
|
+
}, { urlFieldDescription: "Absolute URL of the team's triggers page." });
|
|
7549
7710
|
// node_modules/@qawolf/api-contracts/dist/v1/agent/get.js
|
|
7550
7711
|
var makeAgentGetContract = (ids) => {
|
|
7551
7712
|
const input = object({
|
|
7713
|
+
cursor: string2().min(1).optional().describe("Opaque cursor copied from this same session's previous nextCursor. Omit to read from its first reply."),
|
|
7552
7714
|
sessionId: ids.chatSession.describe("The id agent.send answered with.")
|
|
7553
7715
|
});
|
|
7554
7716
|
const output = resource({
|
|
7555
|
-
|
|
7717
|
+
nextCursor: string2().min(1).describe("Send back as cursor on the next check to read only what follows. Always present, even with no replies. Belongs to this session alone."),
|
|
7718
|
+
replies: array(agentReplySchema).describe("What the AI has said since the cursor, oldest first. A reply still being written returns again, longer. A reply carrying choices is a question the work is blocked on."),
|
|
7556
7719
|
sessionId: ids.chatSession,
|
|
7557
7720
|
status: agentSessionStatusSchema
|
|
7558
7721
|
}, {
|
|
7559
7722
|
urlFieldDescription: "Absolute URL of the live session in the QA Wolf app."
|
|
7560
7723
|
});
|
|
7561
7724
|
return {
|
|
7562
|
-
|
|
7725
|
+
annotations: {
|
|
7726
|
+
destructiveHint: false,
|
|
7727
|
+
openWorldHint: false,
|
|
7728
|
+
readOnlyHint: true
|
|
7729
|
+
},
|
|
7730
|
+
description: 'Monitor a QA Wolf AI session by reading its status and replies. After agent.send, share the returned session URL before monitoring. Wait 30 to 60 seconds between checks; do not call this in a tight loop. Pass the nextCursor from one response as the cursor on the next check; it then reads only what is new, and only for the session that minted it. Continue monitoring silently when the status is unchanged and no replies come back; do not narrate waiting, announce the next check, or ask whether to keep monitoring. Report only substantive new progress, questions, blockers, or the final outcome. A status of "waiting-for-you" means the last reply is a question the work is blocked on, and answering it with agent.send is what unblocks it. Surface an explicit request for user input even if the status still says "working". Include the session URL when reporting a blocker or final outcome. On "completed", stop status checks and verify the requested result before claiming success. For new flows, validation, publication in the target environment, and readiness are separate checks; a Git push or final reply does not prove the flow is active. If every requested result is verified but status remains "working", report the mismatch and stop monitoring. Stop on "failed" or "cancelled" and report any confirmed partial result.',
|
|
7563
7731
|
input,
|
|
7564
7732
|
kind: "read",
|
|
7565
7733
|
name: "agent.get",
|
|
@@ -7571,6 +7739,7 @@ var makeAgentGetContract = (ids) => {
|
|
|
7571
7739
|
var makeAgentSendContract = (ids) => {
|
|
7572
7740
|
const input = object({
|
|
7573
7741
|
environmentId: ids.environmentRef.optional().describe("The environment to work in. Omit to use the team's default environment. Ignored when sessionId is given, because a session keeps the environment it opened in."),
|
|
7742
|
+
filePaths: array(teamStoragePathSchema).max(20).optional().describe("Paths of files this request is about, from file.requestUpload. The AI reads them from storage rather than the message, so a plan of hundreds of journeys costs nothing to send."),
|
|
7574
7743
|
message: string2().trim().min(1).max(1e4).describe("What you want QA Wolf to do, in plain language. Name the journey, the part of the app it covers, and anything the AI cannot discover for itself, such as a test account, a feature flag, or how to reach a staging environment. When answering a question from agent.get, send the answer here."),
|
|
7575
7744
|
sessionId: ids.chatSession.optional().describe("Continue the session with this id instead of opening a new one. Omit to start fresh. Send this to answer a question or to add context to work already running."),
|
|
7576
7745
|
workspaceId: ids.workspace.optional().describe("The workspace to work in. Required when authenticating with an organization or user API key.")
|
|
@@ -7582,6 +7751,11 @@ var makeAgentSendContract = (ids) => {
|
|
|
7582
7751
|
urlFieldDescription: "Absolute URL of the live session in the QA Wolf app."
|
|
7583
7752
|
});
|
|
7584
7753
|
return {
|
|
7754
|
+
annotations: {
|
|
7755
|
+
destructiveHint: true,
|
|
7756
|
+
openWorldHint: true,
|
|
7757
|
+
readOnlyHint: false
|
|
7758
|
+
},
|
|
7585
7759
|
description: "Start or continue work with the QA Wolf AI and return a live session URL to share with the user. Use it to cover a user journey, investigate a failing run, or fix a broken flow. This is the one verb that starts work from nothing: every other write acts on a flow, run or issue that already exists. Returns sessionId, status, and url as soon as the request is accepted; work can take minutes to tens of minutes. After each send, make the next action a normal user-visible assistant message containing the exact returned url, before any tool call or wait. Tool output and internal reasoning do not count as sharing the link. Do not run a timer or monitoring call alongside this send. Acceptance does not mean the work is complete. Then monitor the session with agent.get, reporting new progress, blockers, and the final outcome rather than unchanged status. Send here again to answer a question or add context to the same session.",
|
|
7586
7760
|
input,
|
|
7587
7761
|
kind: "write",
|
|
@@ -7600,6 +7774,11 @@ var makeAutomateContract = (ids) => {
|
|
|
7600
7774
|
});
|
|
7601
7775
|
const output = resource({ automationId: ids.automation }, { urlFieldDescription: "Absolute URL of the automation review page." });
|
|
7602
7776
|
return {
|
|
7777
|
+
annotations: {
|
|
7778
|
+
destructiveHint: true,
|
|
7779
|
+
openWorldHint: true,
|
|
7780
|
+
readOnlyHint: false
|
|
7781
|
+
},
|
|
7603
7782
|
description: "Request automation for draft flows. First create a named local .flow.ts draft for every requested journey that does not already have a matching draft; never reuse a generic starter or placeholder. Each new draft must start with a JSDoc Goal: description, import flow from @qawolf/flows/web, and use export default flow(...); a comment-only file or direct test(...) call is not a valid draft. Commit and push all changes with Git to publish them, then list remote drafts to resolve every selected ID. Do not use patch to create or rename a selected flow. Finally make one automation request containing all requested flow IDs.",
|
|
7604
7783
|
input,
|
|
7605
7784
|
kind: "write",
|
|
@@ -7631,6 +7810,11 @@ var makeFindEmailsContract = (ids) => {
|
|
|
7631
7810
|
nextCursor: nextCursorSchema
|
|
7632
7811
|
});
|
|
7633
7812
|
return {
|
|
7813
|
+
annotations: {
|
|
7814
|
+
destructiveHint: false,
|
|
7815
|
+
openWorldHint: false,
|
|
7816
|
+
readOnlyHint: true
|
|
7817
|
+
},
|
|
7634
7818
|
description: "List the workspace's inbox, or its sent mail, newest first. Read a message body with email.get.",
|
|
7635
7819
|
input,
|
|
7636
7820
|
kind: "read",
|
|
@@ -7647,6 +7831,11 @@ var makeGetEmailContract = (ids) => {
|
|
|
7647
7831
|
});
|
|
7648
7832
|
const output = makeEmailResourceSchema();
|
|
7649
7833
|
return {
|
|
7834
|
+
annotations: {
|
|
7835
|
+
destructiveHint: false,
|
|
7836
|
+
openWorldHint: false,
|
|
7837
|
+
readOnlyHint: true
|
|
7838
|
+
},
|
|
7650
7839
|
description: "Read one email of the workspace, with its plain text and HTML bodies. Use it to pull a sign-in code or a verification link out of a message.",
|
|
7651
7840
|
input,
|
|
7652
7841
|
kind: "read",
|
|
@@ -7670,6 +7859,11 @@ var makeGetEmailAttachmentContract = (ids) => {
|
|
|
7670
7859
|
type: string2().optional().describe("The MIME type.")
|
|
7671
7860
|
}, { urlFieldDescription: emailUrlFieldDescription });
|
|
7672
7861
|
return {
|
|
7862
|
+
annotations: {
|
|
7863
|
+
destructiveHint: false,
|
|
7864
|
+
openWorldHint: false,
|
|
7865
|
+
readOnlyHint: true
|
|
7866
|
+
},
|
|
7673
7867
|
description: "Read one attachment of a workspace email as base64 content, by file name or by position. email.get lists both.",
|
|
7674
7868
|
input,
|
|
7675
7869
|
kind: "read",
|
|
@@ -7689,6 +7883,11 @@ var makeListEmailAddressesContract = (ids) => {
|
|
|
7689
7883
|
nextCursor: nextCursorSchema
|
|
7690
7884
|
});
|
|
7691
7885
|
return {
|
|
7886
|
+
annotations: {
|
|
7887
|
+
destructiveHint: false,
|
|
7888
|
+
openWorldHint: false,
|
|
7889
|
+
readOnlyHint: true
|
|
7890
|
+
},
|
|
7692
7891
|
description: "List the workspace's inbox addresses, alphabetical. A flow can sign up with a plus-suffixed form of any of them, and email.find reads what arrives.",
|
|
7693
7892
|
input,
|
|
7694
7893
|
kind: "read",
|
|
@@ -7711,6 +7910,11 @@ var makeRegisterEmailAddressContract = (ids) => {
|
|
|
7711
7910
|
});
|
|
7712
7911
|
const output = makeEmailAddressResourceSchema();
|
|
7713
7912
|
return {
|
|
7913
|
+
annotations: {
|
|
7914
|
+
destructiveHint: false,
|
|
7915
|
+
openWorldHint: false,
|
|
7916
|
+
readOnlyHint: false
|
|
7917
|
+
},
|
|
7714
7918
|
description: "Register an inbox address for the workspace. Registering an address the workspace already has changes nothing. A refusal names the domains the workspace can use.",
|
|
7715
7919
|
input,
|
|
7716
7920
|
kind: "write",
|
|
@@ -7744,6 +7948,11 @@ var makeSendEmailContract = (ids) => {
|
|
|
7744
7948
|
urlFieldDescription: emailUrlFieldDescription
|
|
7745
7949
|
});
|
|
7746
7950
|
return {
|
|
7951
|
+
annotations: {
|
|
7952
|
+
destructiveHint: true,
|
|
7953
|
+
openWorldHint: true,
|
|
7954
|
+
readOnlyHint: false
|
|
7955
|
+
},
|
|
7747
7956
|
description: "Send an email from one of the workspace's inbox addresses, for example to exercise a flow that reacts to incoming mail. Returns the sent email; read it back with email.get.",
|
|
7748
7957
|
input,
|
|
7749
7958
|
kind: "write",
|
|
@@ -7762,6 +7971,11 @@ var makeDeleteEnvironmentVariableContract = (ids) => {
|
|
|
7762
7971
|
name: string2().describe("The canonicalized name that was removed. Returned even when the environment had no such variable.")
|
|
7763
7972
|
});
|
|
7764
7973
|
return {
|
|
7974
|
+
annotations: {
|
|
7975
|
+
destructiveHint: true,
|
|
7976
|
+
openWorldHint: false,
|
|
7977
|
+
readOnlyHint: false
|
|
7978
|
+
},
|
|
7765
7979
|
description: "Remove one environment variable by name. Succeeds whether or not the variable existed.",
|
|
7766
7980
|
input,
|
|
7767
7981
|
kind: "write",
|
|
@@ -7807,6 +8021,11 @@ var makeFindEnvironmentsContract = (ids) => {
|
|
|
7807
8021
|
nextCursor: nextCursorSchema
|
|
7808
8022
|
});
|
|
7809
8023
|
return {
|
|
8024
|
+
annotations: {
|
|
8025
|
+
destructiveHint: false,
|
|
8026
|
+
openWorldHint: false,
|
|
8027
|
+
readOnlyHint: true
|
|
8028
|
+
},
|
|
7810
8029
|
description: "List the team's environments, newest first.",
|
|
7811
8030
|
input,
|
|
7812
8031
|
kind: "read",
|
|
@@ -7829,6 +8048,11 @@ var makeGetEnvironmentVariableContract = (ids) => {
|
|
|
7829
8048
|
})).describe("The found variables, sorted by name.")
|
|
7830
8049
|
});
|
|
7831
8050
|
return {
|
|
8051
|
+
annotations: {
|
|
8052
|
+
destructiveHint: false,
|
|
8053
|
+
openWorldHint: false,
|
|
8054
|
+
readOnlyHint: true
|
|
8055
|
+
},
|
|
7832
8056
|
description: "Read the values of named environment variables in one call. Values are secrets. Names that do not exist go to missingNames and do not fail the call.",
|
|
7833
8057
|
input,
|
|
7834
8058
|
kind: "read",
|
|
@@ -7844,6 +8068,11 @@ var makeGetEnvironmentContract = (ids) => {
|
|
|
7844
8068
|
});
|
|
7845
8069
|
const output = makeEnvironmentResourceSchema(ids);
|
|
7846
8070
|
return {
|
|
8071
|
+
annotations: {
|
|
8072
|
+
destructiveHint: false,
|
|
8073
|
+
openWorldHint: false,
|
|
8074
|
+
readOnlyHint: true
|
|
8075
|
+
},
|
|
7847
8076
|
description: "Read a single environment's name, kind, standing run health, flow-code branch and reconciliation state, run concurrency limit, and termination state. If flowCodeBranch exists, use its syncStatus for Git reconciliation and read lastSyncedCommitHash only when syncStatus is reconciled.",
|
|
7848
8077
|
input,
|
|
7849
8078
|
kind: "read",
|
|
@@ -7859,6 +8088,11 @@ var makeListEnvironmentVariableNamesContract = (ids) => {
|
|
|
7859
8088
|
variableNames: array(string2()).describe("Names of the environment's variables, sorted alphabetically. Values are never returned.")
|
|
7860
8089
|
});
|
|
7861
8090
|
return {
|
|
8091
|
+
annotations: {
|
|
8092
|
+
destructiveHint: false,
|
|
8093
|
+
openWorldHint: false,
|
|
8094
|
+
readOnlyHint: true
|
|
8095
|
+
},
|
|
7862
8096
|
description: "Use this to answer which QA Wolf environment variables are available to test code. Returns names only; values never leave the server.",
|
|
7863
8097
|
input,
|
|
7864
8098
|
kind: "read",
|
|
@@ -7876,6 +8110,11 @@ var makeSetEnvironmentVariableContract = (ids) => {
|
|
|
7876
8110
|
name: string2().describe("The stored variable name after whitespace is replaced with underscores and letters are uppercased.")
|
|
7877
8111
|
});
|
|
7878
8112
|
return {
|
|
8113
|
+
annotations: {
|
|
8114
|
+
destructiveHint: true,
|
|
8115
|
+
openWorldHint: false,
|
|
8116
|
+
readOnlyHint: false
|
|
8117
|
+
},
|
|
7879
8118
|
description: 'Create or replace an environment variable. If the user asks to create one for "my email" without naming it, use DEFAULT_EMAIL. The value is never returned.',
|
|
7880
8119
|
input,
|
|
7881
8120
|
kind: "write",
|
|
@@ -7890,7 +8129,12 @@ var makeCreateEnvironmentContract = (ids) => {
|
|
|
7890
8129
|
});
|
|
7891
8130
|
const output = makeEnvironmentResourceSchema(ids);
|
|
7892
8131
|
return {
|
|
7893
|
-
|
|
8132
|
+
annotations: {
|
|
8133
|
+
destructiveHint: false,
|
|
8134
|
+
openWorldHint: true,
|
|
8135
|
+
readOnlyHint: false
|
|
8136
|
+
},
|
|
8137
|
+
description: "Create an environment on the caller's team and return it in the environment.get shape. This can also create a branch on the team's connected Git provider.",
|
|
7894
8138
|
input,
|
|
7895
8139
|
kind: "write",
|
|
7896
8140
|
name: "environment.create",
|
|
@@ -7911,6 +8155,11 @@ var makeUpdateEnvironmentContract = (ids) => {
|
|
|
7911
8155
|
});
|
|
7912
8156
|
const output = makeEnvironmentResourceSchema(ids);
|
|
7913
8157
|
return {
|
|
8158
|
+
annotations: {
|
|
8159
|
+
destructiveHint: true,
|
|
8160
|
+
openWorldHint: false,
|
|
8161
|
+
readOnlyHint: false
|
|
8162
|
+
},
|
|
7914
8163
|
description: "Update an environment owned by the caller's team and return it in the environment.get shape. Omitted fields remain unchanged.",
|
|
7915
8164
|
input,
|
|
7916
8165
|
kind: "write",
|
|
@@ -7933,6 +8182,11 @@ var makeCreateTagContract = (ids) => {
|
|
|
7933
8182
|
});
|
|
7934
8183
|
const output = makeTagResourceSchema();
|
|
7935
8184
|
return {
|
|
8185
|
+
annotations: {
|
|
8186
|
+
destructiveHint: false,
|
|
8187
|
+
openWorldHint: false,
|
|
8188
|
+
readOnlyHint: false
|
|
8189
|
+
},
|
|
7936
8190
|
description: "Create a tag on the caller's team. Tags select flows in run.create.",
|
|
7937
8191
|
input,
|
|
7938
8192
|
kind: "write",
|
|
@@ -7961,6 +8215,11 @@ var makeAddTagToFlowsContract = (ids) => {
|
|
|
7961
8215
|
})
|
|
7962
8216
|
});
|
|
7963
8217
|
return {
|
|
8218
|
+
annotations: {
|
|
8219
|
+
destructiveHint: false,
|
|
8220
|
+
openWorldHint: false,
|
|
8221
|
+
readOnlyHint: false
|
|
8222
|
+
},
|
|
7964
8223
|
description: "Assign an existing tag to the selected flows. Create tags with tag.create. Flows that already carry the tag are reported in skippedFlows.",
|
|
7965
8224
|
input,
|
|
7966
8225
|
kind: "write",
|
|
@@ -7993,6 +8252,11 @@ var makeListFlowsContract = (ids) => {
|
|
|
7993
8252
|
}))
|
|
7994
8253
|
});
|
|
7995
8254
|
return {
|
|
8255
|
+
annotations: {
|
|
8256
|
+
destructiveHint: false,
|
|
8257
|
+
openWorldHint: false,
|
|
8258
|
+
readOnlyHint: true
|
|
8259
|
+
},
|
|
7996
8260
|
description: "List the flows of an environment at its latest reconciled commit, or, when an AI task is given, the flows on that task's branch.",
|
|
7997
8261
|
input,
|
|
7998
8262
|
kind: "read",
|
|
@@ -8014,6 +8278,11 @@ var makeRemoveTagFromFlowsContract = (ids) => {
|
|
|
8014
8278
|
})
|
|
8015
8279
|
});
|
|
8016
8280
|
return {
|
|
8281
|
+
annotations: {
|
|
8282
|
+
destructiveHint: true,
|
|
8283
|
+
openWorldHint: false,
|
|
8284
|
+
readOnlyHint: false
|
|
8285
|
+
},
|
|
8017
8286
|
description: "Remove a tag from the selected flows. Succeeds whether or not each flow carried the tag; the flows that did not are reported in skippedFlows.",
|
|
8018
8287
|
input,
|
|
8019
8288
|
kind: "write",
|
|
@@ -8038,6 +8307,11 @@ var makeUpdateFlowContract = (ids) => {
|
|
|
8038
8307
|
})
|
|
8039
8308
|
});
|
|
8040
8309
|
return {
|
|
8310
|
+
annotations: {
|
|
8311
|
+
destructiveHint: true,
|
|
8312
|
+
openWorldHint: false,
|
|
8313
|
+
readOnlyHint: false
|
|
8314
|
+
},
|
|
8041
8315
|
description: "Move a flow between draft and active readiness. The other statuses shown in the app are derived and cannot be set.",
|
|
8042
8316
|
input,
|
|
8043
8317
|
kind: "write",
|
|
@@ -8094,6 +8368,11 @@ var makeFindIssuesContract = (ids) => {
|
|
|
8094
8368
|
nextCursor: nextCursorSchema
|
|
8095
8369
|
});
|
|
8096
8370
|
return {
|
|
8371
|
+
annotations: {
|
|
8372
|
+
destructiveHint: false,
|
|
8373
|
+
openWorldHint: false,
|
|
8374
|
+
readOnlyHint: true
|
|
8375
|
+
},
|
|
8097
8376
|
description: "List the team's bug reports, maintenance reports, or coverage requests, newest first.",
|
|
8098
8377
|
input,
|
|
8099
8378
|
kind: "read",
|
|
@@ -8109,6 +8388,11 @@ var makeGetIssueContract = (ids) => {
|
|
|
8109
8388
|
issue: makeIssueResourceSchema(ids)
|
|
8110
8389
|
});
|
|
8111
8390
|
return {
|
|
8391
|
+
annotations: {
|
|
8392
|
+
destructiveHint: false,
|
|
8393
|
+
openWorldHint: false,
|
|
8394
|
+
readOnlyHint: true
|
|
8395
|
+
},
|
|
8112
8396
|
description: "Get an issue by id.",
|
|
8113
8397
|
input,
|
|
8114
8398
|
kind: "read",
|
|
@@ -8127,6 +8411,11 @@ var makeAddFlowsToIssueContract = (ids) => {
|
|
|
8127
8411
|
issue: makeIssueResourceSchema(ids)
|
|
8128
8412
|
});
|
|
8129
8413
|
return {
|
|
8414
|
+
annotations: {
|
|
8415
|
+
destructiveHint: false,
|
|
8416
|
+
openWorldHint: false,
|
|
8417
|
+
readOnlyHint: false
|
|
8418
|
+
},
|
|
8130
8419
|
description: "Add flows to a coverage request owned by the caller's team. " + "Flows already covered stay covered. " + "Bug and maintenance reports link to flows through the runs that reproduce them; use run.diagnose to record one.",
|
|
8131
8420
|
input,
|
|
8132
8421
|
kind: "write",
|
|
@@ -8158,6 +8447,11 @@ var makeCreateIssueContract = (ids) => {
|
|
|
8158
8447
|
issue: makeIssueResourceSchema(ids)
|
|
8159
8448
|
});
|
|
8160
8449
|
return {
|
|
8450
|
+
annotations: {
|
|
8451
|
+
destructiveHint: true,
|
|
8452
|
+
openWorldHint: true,
|
|
8453
|
+
readOnlyHint: false
|
|
8454
|
+
},
|
|
8161
8455
|
description: "Create a bug or coverage request issue for the caller's team. " + "Maintenance issues cannot be created through the public API.",
|
|
8162
8456
|
input,
|
|
8163
8457
|
kind: "write",
|
|
@@ -8176,6 +8470,11 @@ var makeRemoveFlowsFromIssueContract = (ids) => {
|
|
|
8176
8470
|
issue: makeIssueResourceSchema(ids)
|
|
8177
8471
|
});
|
|
8178
8472
|
return {
|
|
8473
|
+
annotations: {
|
|
8474
|
+
destructiveHint: true,
|
|
8475
|
+
openWorldHint: false,
|
|
8476
|
+
readOnlyHint: false
|
|
8477
|
+
},
|
|
8179
8478
|
description: "Remove flows from a coverage request owned by the caller's team. " + "Flows the request does not cover are left alone. " + "Bug and maintenance reports link to flows through the runs that reproduce them, so their flows cannot be set directly.",
|
|
8180
8479
|
input,
|
|
8181
8480
|
kind: "write",
|
|
@@ -8201,6 +8500,11 @@ var makeUpdateIssueContract = (ids) => {
|
|
|
8201
8500
|
issue: makeIssueResourceSchema(ids)
|
|
8202
8501
|
});
|
|
8203
8502
|
return {
|
|
8503
|
+
annotations: {
|
|
8504
|
+
destructiveHint: true,
|
|
8505
|
+
openWorldHint: true,
|
|
8506
|
+
readOnlyHint: false
|
|
8507
|
+
},
|
|
8204
8508
|
description: "Update an issue owned by the caller's team. Omitted fields remain unchanged.",
|
|
8205
8509
|
input,
|
|
8206
8510
|
kind: "write",
|
|
@@ -8220,6 +8524,11 @@ var makeDiagnoseRunContract = (ids) => {
|
|
|
8220
8524
|
issue: makeIssueResourceSchema(ids)
|
|
8221
8525
|
});
|
|
8222
8526
|
return {
|
|
8527
|
+
annotations: {
|
|
8528
|
+
destructiveHint: true,
|
|
8529
|
+
openWorldHint: true,
|
|
8530
|
+
readOnlyHint: false
|
|
8531
|
+
},
|
|
8223
8532
|
description: "Diagnose failed flows in a run as reproductions of a bug or maintenance report owned by the caller's team. " + "The issue's type selects the diagnosis. " + "Each flow must have failed in the run. " + "A flow that is already diagnosed moves to this issue. " + "The diagnosis appears on the run, and the reproduction appears under the issue's reproductions. " + "Coverage requests cannot be diagnosed; use issue.addFlows to cover flows instead.",
|
|
8224
8533
|
input,
|
|
8225
8534
|
kind: "write",
|
|
@@ -8256,6 +8565,11 @@ var makeFindRunsContract = (ids) => {
|
|
|
8256
8565
|
})).describe("The environment's runs, newest first. Per-flow results are available via run.get.")
|
|
8257
8566
|
});
|
|
8258
8567
|
return {
|
|
8568
|
+
annotations: {
|
|
8569
|
+
destructiveHint: false,
|
|
8570
|
+
openWorldHint: false,
|
|
8571
|
+
readOnlyHint: true
|
|
8572
|
+
},
|
|
8259
8573
|
description: "List an environment's recent runs, newest first.",
|
|
8260
8574
|
input,
|
|
8261
8575
|
kind: "read",
|
|
@@ -8332,6 +8646,11 @@ var makeGetRunContract = (ids) => {
|
|
|
8332
8646
|
runId: ids.run.describe("The run this response describes. Treat it as canonical: it can differ from the id you asked for. A deploy notification returns a run id before the run exists, and if a second notification for the same commit is folded into an earlier run, that id resolves to the earlier run instead.")
|
|
8333
8647
|
}, { urlFieldDescription: "Absolute URL of the run page." });
|
|
8334
8648
|
return {
|
|
8649
|
+
annotations: {
|
|
8650
|
+
destructiveHint: false,
|
|
8651
|
+
openWorldHint: false,
|
|
8652
|
+
readOnlyHint: true
|
|
8653
|
+
},
|
|
8335
8654
|
description: "Get a run's status, per-flow results, and links.",
|
|
8336
8655
|
input,
|
|
8337
8656
|
kind: "read",
|
|
@@ -8351,6 +8670,11 @@ var makeReattemptRunContract = (ids) => {
|
|
|
8351
8670
|
runId: ids.run
|
|
8352
8671
|
}, { urlFieldDescription: "Absolute URL of the run page." });
|
|
8353
8672
|
return {
|
|
8673
|
+
annotations: {
|
|
8674
|
+
destructiveHint: true,
|
|
8675
|
+
openWorldHint: true,
|
|
8676
|
+
readOnlyHint: false
|
|
8677
|
+
},
|
|
8354
8678
|
description: "Request new attempts for a run's flows, in the same run. " + "A flow is eligible once its result is failed or canceled and QA Wolf's " + "automatic retries have finished. " + "A fully investigated run no longer accepts reattempts. " + "Attempts run with the latest flow code. Poll run.get for results.",
|
|
8355
8679
|
input,
|
|
8356
8680
|
kind: "write",
|
|
@@ -8367,7 +8691,12 @@ var makeStopRunContract = (ids) => {
|
|
|
8367
8691
|
status: _enum(["accepted", "already-finished", "execution-not-found"]).describe('"accepted" means stopping was requested; poll run.get for the final result. "already-finished" means the run has already finished and its result is unchanged. "execution-not-found" means the run exists but no execution was found to stop; it may still be starting or may no longer be available. No stop request was accepted in that case.')
|
|
8368
8692
|
}, { urlFieldDescription: "Absolute URL of the run page." });
|
|
8369
8693
|
return {
|
|
8370
|
-
|
|
8694
|
+
annotations: {
|
|
8695
|
+
destructiveHint: true,
|
|
8696
|
+
openWorldHint: true,
|
|
8697
|
+
readOnlyHint: false
|
|
8698
|
+
},
|
|
8699
|
+
description: "Stop a run, including its queued flows and automatic retries. Stopping is asynchronous and can update run-status messages and commit statuses in connected integrations. Repeated requests are safe, and finished runs keep their results. A run that is still being created returns not found; retry once run.get returns the run. If run.get returns a different runId, use that ID. Poll run.get for results.",
|
|
8371
8700
|
input,
|
|
8372
8701
|
kind: "write",
|
|
8373
8702
|
name: "run.stop",
|
|
@@ -8400,6 +8729,11 @@ var makeEvaluateSnippetOnRunnerContract = (ids) => {
|
|
|
8400
8729
|
])
|
|
8401
8730
|
]);
|
|
8402
8731
|
return {
|
|
8732
|
+
annotations: {
|
|
8733
|
+
destructiveHint: true,
|
|
8734
|
+
openWorldHint: true,
|
|
8735
|
+
readOnlyHint: false
|
|
8736
|
+
},
|
|
8403
8737
|
description: "Evaluate a snippet against whatever the runner's browser is showing right now. Answers whether the snippet ran, and its error if it threw — not the value it evaluated to, so read anything you want back out of the runner's journal (a snippet's `console.log` lands in the `console` stream). A snippet starts no run and leaves no run-scoped journal entries of its own. `runner-cannot-evaluate-snippets` on a runner with nothing attached to serve one — which will never clear, so check that the runner you launched is one that runs a browser or app before retrying. `runner-unreachable` if the runner could not be reached: it may still be starting, it may have terminated after inactivity, or it may be too busy to answer. Neither is proof the snippet did not run: a snippet that outlives the answer window is still executing when you read this, so do not blindly resubmit one that mutates what the page is looking at.",
|
|
8404
8738
|
input,
|
|
8405
8739
|
kind: "write",
|
|
@@ -8420,6 +8754,11 @@ var makeGetRunnerContract = (ids) => {
|
|
|
8420
8754
|
running: boolean2().describe("False when no runner is running under this id: it was never launched, it was terminated, or it terminated on its own after inactivity. These are not distinguished, because the run system keeps no record of a runner once it is gone.")
|
|
8421
8755
|
});
|
|
8422
8756
|
return {
|
|
8757
|
+
annotations: {
|
|
8758
|
+
destructiveHint: false,
|
|
8759
|
+
openWorldHint: false,
|
|
8760
|
+
readOnlyHint: true
|
|
8761
|
+
},
|
|
8423
8762
|
description: "Report whether a runner is running under this id on the caller's team. This is a lookup: it never starts a runner, and it does not reset a runner's inactivity clock the way reading its journal does. An id that is not running is a success with `running: false` rather than an error, so this is how to check a runner is still there before addressing it.",
|
|
8424
8763
|
input,
|
|
8425
8764
|
kind: "read",
|
|
@@ -8458,6 +8797,11 @@ var makeHighlightSelectorOnRunnerContract = (ids) => {
|
|
|
8458
8797
|
})
|
|
8459
8798
|
]);
|
|
8460
8799
|
return {
|
|
8800
|
+
annotations: {
|
|
8801
|
+
destructiveHint: false,
|
|
8802
|
+
openWorldHint: false,
|
|
8803
|
+
readOnlyHint: false
|
|
8804
|
+
},
|
|
8461
8805
|
description: "Highlight the elements a selector matches on an interactive runner's live page, and answer how many it matched. The highlight stays until it is replaced or cleared, so it is visible in the next `runner.takeScreenshot` — which is the point, since a caller cannot see the runner's screen otherwise. Send an empty selector to clear, which answers `cleared`. `status` tells a selector that matched nothing (`empty`) from one the page could not parse (`invalid`), so a caller can tell a bad locator from a locator pointing at nothing. `no-answer` if the page did not answer in time: the highlight runs inside the page, so a page that is gone or mid-navigation does not answer slowly, it does not answer at all. `runner-cannot-highlight-selectors` on a runner with no browser to draw on. `runner-unreachable` if the runner could not be reached: it may still be starting, or it may have terminated after inactivity.",
|
|
8462
8806
|
input,
|
|
8463
8807
|
kind: "write",
|
|
@@ -8486,6 +8830,11 @@ var makeImportPackageOnRunnerContract = (ids) => {
|
|
|
8486
8830
|
})
|
|
8487
8831
|
]);
|
|
8488
8832
|
return {
|
|
8833
|
+
annotations: {
|
|
8834
|
+
destructiveHint: true,
|
|
8835
|
+
openWorldHint: true,
|
|
8836
|
+
readOnlyHint: false
|
|
8837
|
+
},
|
|
8489
8838
|
description: "Install a package into an interactive runner's live run and import it, so a snippet or a selection can use it without a full run to reinstall dependencies. An `install-failed` failure carries npm's reason in `errorMessage`. `runner-unreachable` if the runner could not be reached: it may still be starting, it may have terminated after inactivity, or it may be too busy to answer. The install may still have landed, but installing the same version again does nothing, so retrying is safe.",
|
|
8490
8839
|
input,
|
|
8491
8840
|
kind: "write",
|
|
@@ -8506,6 +8855,11 @@ var makeLaunchRunnerContract = (ids) => {
|
|
|
8506
8855
|
outcome: literal("success")
|
|
8507
8856
|
});
|
|
8508
8857
|
return {
|
|
8858
|
+
annotations: {
|
|
8859
|
+
destructiveHint: true,
|
|
8860
|
+
openWorldHint: false,
|
|
8861
|
+
readOnlyHint: false
|
|
8862
|
+
},
|
|
8509
8863
|
description: "Launch an interactive runner on the caller's team under an id the caller chooses. Launching the same id again returns the runner already running rather than starting a second one, and the same id with a different runnerName is refused. A runner is not permanent: it terminates on its own after a period of inactivity, and launching the same id after that starts and bills a new runner — so read `alreadyRunning` to tell which happened.",
|
|
8510
8864
|
input,
|
|
8511
8865
|
kind: "write",
|
|
@@ -8524,6 +8878,11 @@ var makeTerminateRunnerContract = (ids) => {
|
|
|
8524
8878
|
wasRunning: boolean2().describe("False when no running runner had this id: it was already terminated, was never launched, or terminated on its own after inactivity. These are not distinguished, because the run system keeps no record of a runner once it is gone. Not an error, and a retry needs no special handling.")
|
|
8525
8879
|
});
|
|
8526
8880
|
return {
|
|
8881
|
+
annotations: {
|
|
8882
|
+
destructiveHint: true,
|
|
8883
|
+
openWorldHint: false,
|
|
8884
|
+
readOnlyHint: false
|
|
8885
|
+
},
|
|
8527
8886
|
description: "End an interactive runner on the caller's team, and the pod it runs on with it. Terminating a runner that is not running succeeds and reports `wasRunning: false`. This ends the runner: use `runner.stopRun` to stop what a runner is currently executing while leaving the runner up.",
|
|
8528
8887
|
input,
|
|
8529
8888
|
kind: "write",
|
|
@@ -8542,6 +8901,11 @@ var makeListRunnersContract = (ids) => {
|
|
|
8542
8901
|
runners: array(makeRunnerSchema()).describe("The runners running right now, in no particular order. Each entry carries the same fields a launch reports, so any of them can be addressed like a runner you launched yourself.")
|
|
8543
8902
|
});
|
|
8544
8903
|
return {
|
|
8904
|
+
annotations: {
|
|
8905
|
+
destructiveHint: false,
|
|
8906
|
+
openWorldHint: false,
|
|
8907
|
+
readOnlyHint: true
|
|
8908
|
+
},
|
|
8545
8909
|
description: "List the runners running on the caller's team right now. A team API key already names the team and sends nothing; a credential bound to no single workspace names one in `workspaceId`. A runner that was terminated, or that terminated on its own after inactivity, is not listed, because the run system keeps no record of a runner once it is gone. This is a lookup: it never starts a runner, and it does not reset a runner's inactivity clock the way reading its journal does. It is how to find a runner launched from another machine or in an earlier session, when the id it was launched under is no longer at hand.",
|
|
8546
8910
|
input,
|
|
8547
8911
|
kind: "read",
|
|
@@ -8571,6 +8935,11 @@ var makePromoteSnapshotOnRunnerContract = (ids) => {
|
|
|
8571
8935
|
})
|
|
8572
8936
|
]);
|
|
8573
8937
|
return {
|
|
8938
|
+
annotations: {
|
|
8939
|
+
destructiveHint: true,
|
|
8940
|
+
openWorldHint: false,
|
|
8941
|
+
readOnlyHint: false
|
|
8942
|
+
},
|
|
8574
8943
|
description: "Accept a run's screenshot as the new baseline for an image diff, on the runner that produced it. The two paths are the ones the diff reported, which reach a caller as an `image-diff-artifact` entry on the runner's `run-events` journal stream. `snapshot-not-found` if the run wrote no screenshot at that path, which usually means the paths were not taken from a diff this run produced; nothing is changed, so correcting the path and repeating is safe. `runner-cannot-promote-snapshots` on a runner that stores no screenshots. `runner-unreachable` if the runner could not be reached: it may still be starting, or it may have terminated after inactivity. A promotion that lands is not undone by promoting again, so a retry after an unreachable answer is safe.",
|
|
8575
8944
|
input,
|
|
8576
8945
|
kind: "write",
|
|
@@ -8591,6 +8960,11 @@ var makeReadRunnerJournalContract = (ids) => {
|
|
|
8591
8960
|
makeRunnerFailureSchema([runnerUnreachableFailureReason])
|
|
8592
8961
|
]);
|
|
8593
8962
|
return {
|
|
8963
|
+
annotations: {
|
|
8964
|
+
destructiveHint: false,
|
|
8965
|
+
openWorldHint: false,
|
|
8966
|
+
readOnlyHint: false
|
|
8967
|
+
},
|
|
8594
8968
|
description: `Read a window of one of an interactive runner's journal streams — the newest few, everything after a cursor, or everything belonging to one run. This is how a flow run's outcome and output are followed: \`run-status\` settles it, \`run-logs\` and \`run-events\` carry what it produced, and \`recorder\` carries the browser actions the runner recorded. A read counts as activity, so working through history does not get the runner reaped underneath you. ${retryableRunnerUnreachableDescription}`,
|
|
8595
8969
|
input,
|
|
8596
8970
|
kind: "read",
|
|
@@ -8663,6 +9037,11 @@ var makeRunFlowOnRunnerContract = (ids) => {
|
|
|
8663
9037
|
failure
|
|
8664
9038
|
]);
|
|
8665
9039
|
return {
|
|
9040
|
+
annotations: {
|
|
9041
|
+
destructiveHint: true,
|
|
9042
|
+
openWorldHint: true,
|
|
9043
|
+
readOnlyHint: false
|
|
9044
|
+
},
|
|
8666
9045
|
description: "Run a flow on an interactive runner. When `selection` is given the lines run against the browser as it stands, so nothing is re-navigated and nothing is signed in again; without it the whole entry point runs from a fresh browser. A runner with no live browser starts one before a selection and says so with `bootstrappedRunner`, which means those lines ran against a fresh page rather than the one an earlier run left. A selection produces no `runStarted` event, so follow it by its run id on `run-status` like any other run. Send `unchangedFiles` to ship only what changed since an earlier run on this runner; a `needs-full-sync` failure names the paths it does not hold, and the way to recover is the same run again with every file in `files`. Answers as soon as the run is accepted, with the id to follow it by — nothing waits for the run to finish. Which browser or device the run needs is read from the flow file's own execution target, so it is not supplied here; when it does not match what the runner is, the call fails with `runner-target-mismatch` rather than failing partway through the run. `runner-unreachable` means the answer did not arrive, which is NOT the same as the run not having started: the runner may have accepted it and been too slow to say so, and resubmitting would start a second run that is billed and journalled alongside the first. Read the runner's `run-status` journal stream before resubmitting, and use the newest run id there if one appeared.",
|
|
8667
9046
|
input,
|
|
8668
9047
|
kind: "write",
|
|
@@ -8685,6 +9064,11 @@ var makeStopRunOnRunnerContract = (ids) => {
|
|
|
8685
9064
|
makeRunnerFailureSchema([runnerUnreachableFailureReason])
|
|
8686
9065
|
]);
|
|
8687
9066
|
return {
|
|
9067
|
+
annotations: {
|
|
9068
|
+
destructiveHint: true,
|
|
9069
|
+
openWorldHint: false,
|
|
9070
|
+
readOnlyHint: false
|
|
9071
|
+
},
|
|
8688
9072
|
description: "Stop what a runner is currently executing, leaving the runner up and its browser on whatever page the run reached. Succeeds whether or not anything was running, and `wasRunning` says which. This is the counterpart of `runner.terminate`, which ends the runner itself. The run stops where it is, so the journal's `run-status` settles it as stopped rather than passed or failed. `runner-unreachable` if the runner could not be reached: it may still be starting, it may have terminated after inactivity, or it may be too busy to answer. The stop may still have landed, but stopping a runner that is already idle does nothing, so retrying is safe.",
|
|
8689
9073
|
input,
|
|
8690
9074
|
kind: "write",
|
|
@@ -8710,7 +9094,12 @@ var makeTakeScreenshotOnRunnerContract = (ids) => {
|
|
|
8710
9094
|
])
|
|
8711
9095
|
]);
|
|
8712
9096
|
return {
|
|
8713
|
-
|
|
9097
|
+
annotations: {
|
|
9098
|
+
destructiveHint: false,
|
|
9099
|
+
openWorldHint: false,
|
|
9100
|
+
readOnlyHint: false
|
|
9101
|
+
},
|
|
9102
|
+
description: `Take one screenshot of an interactive runner's screen. On a runner with a browser the image is the whole virtual desktop, browser window and all; this refreshes the inactivity timer and can extend the runner's billed lifetime. On a mobile runner it is the device's own screen, re-encoded to JPEG on the pod so this contract reads one image format regardless of runner family. ${screenNeedsARunDescription} ${screenNotReadyDescription} ${runnerHasNoScreenDescription} ${retryableRunnerUnreachableDescription}`,
|
|
8714
9103
|
input,
|
|
8715
9104
|
kind: "read",
|
|
8716
9105
|
name: "runner.takeScreenshot",
|
|
@@ -8733,6 +9122,11 @@ var makeListTagsContract = (ids) => {
|
|
|
8733
9122
|
})).describe("The team's tags, alphabetical by name.")
|
|
8734
9123
|
});
|
|
8735
9124
|
return {
|
|
9125
|
+
annotations: {
|
|
9126
|
+
destructiveHint: false,
|
|
9127
|
+
openWorldHint: false,
|
|
9128
|
+
readOnlyHint: true
|
|
9129
|
+
},
|
|
8736
9130
|
description: "List the team's tags, alphabetical by name. Tag names select flows in run.create.",
|
|
8737
9131
|
input,
|
|
8738
9132
|
kind: "read",
|
|
@@ -8741,6 +9135,250 @@ var makeListTagsContract = (ids) => {
|
|
|
8741
9135
|
};
|
|
8742
9136
|
};
|
|
8743
9137
|
|
|
9138
|
+
// node_modules/@qawolf/api-contracts/dist/v1/trigger/configurationRules.js
|
|
9139
|
+
var checkAction = (action, ctx) => {
|
|
9140
|
+
const namesFlows = action.flowIds.length + action.tagNames.length > 0;
|
|
9141
|
+
if (action.kind === "generativeSuite") {
|
|
9142
|
+
if (namesFlows) {
|
|
9143
|
+
ctx.addIssue({
|
|
9144
|
+
code: "custom",
|
|
9145
|
+
message: "flowIds and tagNames do not apply when the action is generativeSuite.",
|
|
9146
|
+
path: ["action", "flowIds"]
|
|
9147
|
+
});
|
|
9148
|
+
}
|
|
9149
|
+
return;
|
|
9150
|
+
}
|
|
9151
|
+
if (action.instructions !== undefined) {
|
|
9152
|
+
ctx.addIssue({
|
|
9153
|
+
code: "custom",
|
|
9154
|
+
message: "instructions apply to a generativeSuite action only.",
|
|
9155
|
+
path: ["action", "instructions"]
|
|
9156
|
+
});
|
|
9157
|
+
}
|
|
9158
|
+
if (!namesFlows) {
|
|
9159
|
+
ctx.addIssue({
|
|
9160
|
+
code: "custom",
|
|
9161
|
+
message: "At least one flow or tag is required.",
|
|
9162
|
+
path: ["action", "flowIds"]
|
|
9163
|
+
});
|
|
9164
|
+
}
|
|
9165
|
+
};
|
|
9166
|
+
var checkSchedule = (value, ctx) => {
|
|
9167
|
+
if (value.cadence === "daily") {
|
|
9168
|
+
for (const field of ["timeOfDay", "timezoneId"]) {
|
|
9169
|
+
if (value[field] === undefined) {
|
|
9170
|
+
ctx.addIssue({
|
|
9171
|
+
code: "custom",
|
|
9172
|
+
message: `${field} is required when cadence is daily.`,
|
|
9173
|
+
path: [field]
|
|
9174
|
+
});
|
|
9175
|
+
}
|
|
9176
|
+
}
|
|
9177
|
+
if (value.minuteOfHour !== undefined) {
|
|
9178
|
+
ctx.addIssue({
|
|
9179
|
+
code: "custom",
|
|
9180
|
+
message: "minuteOfHour applies to an hourly cadence only.",
|
|
9181
|
+
path: ["minuteOfHour"]
|
|
9182
|
+
});
|
|
9183
|
+
}
|
|
9184
|
+
} else {
|
|
9185
|
+
for (const field of ["timeOfDay", "timezoneId"]) {
|
|
9186
|
+
if (value[field] !== undefined) {
|
|
9187
|
+
ctx.addIssue({
|
|
9188
|
+
code: "custom",
|
|
9189
|
+
message: `${field} applies to a daily cadence only.`,
|
|
9190
|
+
path: [field]
|
|
9191
|
+
});
|
|
9192
|
+
}
|
|
9193
|
+
}
|
|
9194
|
+
}
|
|
9195
|
+
if (value.action.kind === "generativeSuite") {
|
|
9196
|
+
ctx.addIssue({
|
|
9197
|
+
code: "custom",
|
|
9198
|
+
message: "A schedule trigger cannot use a generativeSuite action.",
|
|
9199
|
+
path: ["action", "kind"]
|
|
9200
|
+
});
|
|
9201
|
+
return;
|
|
9202
|
+
}
|
|
9203
|
+
checkAction(value.action, ctx);
|
|
9204
|
+
};
|
|
9205
|
+
var checkDeployment = (value, ctx) => {
|
|
9206
|
+
if (value.environmentPattern !== undefined && value.environmentIds.length > 0) {
|
|
9207
|
+
ctx.addIssue({
|
|
9208
|
+
code: "custom",
|
|
9209
|
+
message: "Supply environmentIds or environmentPattern, not both.",
|
|
9210
|
+
path: ["environmentPattern"]
|
|
9211
|
+
});
|
|
9212
|
+
}
|
|
9213
|
+
checkAction(value.action, ctx);
|
|
9214
|
+
};
|
|
9215
|
+
var checkTriggerConfiguration = (value, ctx) => value.kind === "schedule" ? checkSchedule(value, ctx) : checkDeployment(value, ctx);
|
|
9216
|
+
|
|
9217
|
+
// node_modules/@qawolf/api-contracts/dist/v1/trigger/create.js
|
|
9218
|
+
var makeCreateTriggerContract = (ids) => {
|
|
9219
|
+
const commonFields = {
|
|
9220
|
+
name: string2().trim().min(1).max(255),
|
|
9221
|
+
workspaceId: ids.workspace.optional().describe("The workspace to create the trigger in. Required when authenticating with an organization or user API key.")
|
|
9222
|
+
};
|
|
9223
|
+
const input = discriminatedUnion("kind", [
|
|
9224
|
+
object({
|
|
9225
|
+
...commonFields,
|
|
9226
|
+
...makeTriggerScheduleFields({
|
|
9227
|
+
environmentId: ids.environmentRef,
|
|
9228
|
+
flow: ids.flow
|
|
9229
|
+
}),
|
|
9230
|
+
kind: literal("schedule")
|
|
9231
|
+
}),
|
|
9232
|
+
object({
|
|
9233
|
+
...commonFields,
|
|
9234
|
+
...makeTriggerDeploymentFields(ids),
|
|
9235
|
+
kind: literal("deployment")
|
|
9236
|
+
})
|
|
9237
|
+
]).superRefine(checkTriggerConfiguration);
|
|
9238
|
+
const output = object({ trigger: makeTriggerResourceSchema(ids) });
|
|
9239
|
+
return {
|
|
9240
|
+
annotations: {
|
|
9241
|
+
destructiveHint: true,
|
|
9242
|
+
openWorldHint: true,
|
|
9243
|
+
readOnlyHint: false
|
|
9244
|
+
},
|
|
9245
|
+
description: "Create a trigger. A schedule trigger runs a named set of flows on a cadence; " + "a deployment trigger runs when a matching deployment is reported.",
|
|
9246
|
+
input,
|
|
9247
|
+
kind: "write",
|
|
9248
|
+
name: "trigger.create",
|
|
9249
|
+
output
|
|
9250
|
+
};
|
|
9251
|
+
};
|
|
9252
|
+
|
|
9253
|
+
// node_modules/@qawolf/api-contracts/dist/v1/trigger/find.js
|
|
9254
|
+
var makeFindTriggersContract = (ids) => {
|
|
9255
|
+
const input = object({
|
|
9256
|
+
isPaused: boolean2().optional().describe("Only list paused, or only unpaused, triggers. Omit for both."),
|
|
9257
|
+
workspaceId: ids.workspace.optional().describe("The workspace to list triggers from. Required when authenticating with an organization or user API key.")
|
|
9258
|
+
});
|
|
9259
|
+
const output = object({
|
|
9260
|
+
triggers: array(makeTriggerResourceSchema(ids)).describe("The team's triggers, newest first.")
|
|
9261
|
+
});
|
|
9262
|
+
return {
|
|
9263
|
+
annotations: {
|
|
9264
|
+
destructiveHint: false,
|
|
9265
|
+
openWorldHint: false,
|
|
9266
|
+
readOnlyHint: true
|
|
9267
|
+
},
|
|
9268
|
+
description: "List the team's triggers, newest first.",
|
|
9269
|
+
input,
|
|
9270
|
+
kind: "read",
|
|
9271
|
+
name: "trigger.find",
|
|
9272
|
+
output
|
|
9273
|
+
};
|
|
9274
|
+
};
|
|
9275
|
+
|
|
9276
|
+
// node_modules/@qawolf/api-contracts/dist/v1/trigger/get.js
|
|
9277
|
+
var makeGetTriggerContract = (ids) => {
|
|
9278
|
+
const input = object({ triggerId: ids.trigger });
|
|
9279
|
+
const output = object({ trigger: makeTriggerResourceSchema(ids) });
|
|
9280
|
+
return {
|
|
9281
|
+
annotations: {
|
|
9282
|
+
destructiveHint: false,
|
|
9283
|
+
openWorldHint: false,
|
|
9284
|
+
readOnlyHint: true
|
|
9285
|
+
},
|
|
9286
|
+
description: "Get one trigger by id.",
|
|
9287
|
+
input,
|
|
9288
|
+
kind: "read",
|
|
9289
|
+
name: "trigger.get",
|
|
9290
|
+
output
|
|
9291
|
+
};
|
|
9292
|
+
};
|
|
9293
|
+
|
|
9294
|
+
// node_modules/@qawolf/api-contracts/dist/v1/trigger/lifecycle.js
|
|
9295
|
+
var makePauseTriggerContract = (ids) => {
|
|
9296
|
+
const input = object({ triggerId: ids.trigger });
|
|
9297
|
+
const output = object({ trigger: makeTriggerResourceSchema(ids) });
|
|
9298
|
+
return {
|
|
9299
|
+
annotations: {
|
|
9300
|
+
destructiveHint: true,
|
|
9301
|
+
openWorldHint: false,
|
|
9302
|
+
readOnlyHint: false
|
|
9303
|
+
},
|
|
9304
|
+
description: "Pause a trigger so it stops firing. Pausing is idempotent. A team whose " + "triggers are all paused reports no trigger activity at all.",
|
|
9305
|
+
input,
|
|
9306
|
+
kind: "write",
|
|
9307
|
+
name: "trigger.pause",
|
|
9308
|
+
output
|
|
9309
|
+
};
|
|
9310
|
+
};
|
|
9311
|
+
var makeResumeTriggerContract = (ids) => {
|
|
9312
|
+
const input = object({ triggerId: ids.trigger });
|
|
9313
|
+
const output = object({ trigger: makeTriggerResourceSchema(ids) });
|
|
9314
|
+
return {
|
|
9315
|
+
annotations: {
|
|
9316
|
+
destructiveHint: true,
|
|
9317
|
+
openWorldHint: true,
|
|
9318
|
+
readOnlyHint: false
|
|
9319
|
+
},
|
|
9320
|
+
description: "Resume a paused trigger. A schedule trigger restarts from the next " + "upcoming slot: the slots it missed while paused do not run.",
|
|
9321
|
+
input,
|
|
9322
|
+
kind: "write",
|
|
9323
|
+
name: "trigger.resume",
|
|
9324
|
+
output
|
|
9325
|
+
};
|
|
9326
|
+
};
|
|
9327
|
+
var makeDeleteTriggerContract = (ids) => {
|
|
9328
|
+
const input = object({ triggerId: ids.trigger });
|
|
9329
|
+
const output = object({
|
|
9330
|
+
triggerId: ids.trigger.describe("The id of the deleted trigger.")
|
|
9331
|
+
});
|
|
9332
|
+
return {
|
|
9333
|
+
annotations: {
|
|
9334
|
+
destructiveHint: true,
|
|
9335
|
+
openWorldHint: false,
|
|
9336
|
+
readOnlyHint: false
|
|
9337
|
+
},
|
|
9338
|
+
description: "Delete a trigger permanently. The runs it already created are kept. " + "To stop a trigger without losing it, use trigger.pause.",
|
|
9339
|
+
input,
|
|
9340
|
+
kind: "write",
|
|
9341
|
+
name: "trigger.delete",
|
|
9342
|
+
output
|
|
9343
|
+
};
|
|
9344
|
+
};
|
|
9345
|
+
|
|
9346
|
+
// node_modules/@qawolf/api-contracts/dist/v1/trigger/update.js
|
|
9347
|
+
var makeUpdateTriggerContract = (ids) => {
|
|
9348
|
+
const commonFields = {
|
|
9349
|
+
name: string2().trim().min(1).max(255),
|
|
9350
|
+
triggerId: ids.trigger
|
|
9351
|
+
};
|
|
9352
|
+
const input = discriminatedUnion("kind", [
|
|
9353
|
+
object({
|
|
9354
|
+
...commonFields,
|
|
9355
|
+
...makeTriggerScheduleFields({
|
|
9356
|
+
environmentId: ids.environmentRef,
|
|
9357
|
+
flow: ids.flow
|
|
9358
|
+
}),
|
|
9359
|
+
kind: literal("schedule")
|
|
9360
|
+
}),
|
|
9361
|
+
object({
|
|
9362
|
+
...commonFields,
|
|
9363
|
+
...makeTriggerDeploymentFields(ids),
|
|
9364
|
+
kind: literal("deployment")
|
|
9365
|
+
})
|
|
9366
|
+
]).superRefine(checkTriggerConfiguration);
|
|
9367
|
+
const output = object({ trigger: makeTriggerResourceSchema(ids) });
|
|
9368
|
+
return {
|
|
9369
|
+
annotations: {
|
|
9370
|
+
destructiveHint: true,
|
|
9371
|
+
openWorldHint: true,
|
|
9372
|
+
readOnlyHint: false
|
|
9373
|
+
},
|
|
9374
|
+
description: "Replace a trigger's configuration. Every field is written, so read the " + "trigger first and send its configuration back with your changes applied. " + "Pausing is separate: use trigger.pause and trigger.resume.",
|
|
9375
|
+
input,
|
|
9376
|
+
kind: "write",
|
|
9377
|
+
name: "trigger.update",
|
|
9378
|
+
output
|
|
9379
|
+
};
|
|
9380
|
+
};
|
|
9381
|
+
|
|
8744
9382
|
// node_modules/@qawolf/api-contracts/dist/v1/index.js
|
|
8745
9383
|
var makeContractsV1 = (ids) => {
|
|
8746
9384
|
const resolvedIds = { ...defaultIdSchemas, ...ids };
|
|
@@ -8768,6 +9406,7 @@ var makeContractsV1 = (ids) => {
|
|
|
8768
9406
|
setVariable: makeSetEnvironmentVariableContract(resolvedIds),
|
|
8769
9407
|
update: makeUpdateEnvironmentContract(resolvedIds)
|
|
8770
9408
|
},
|
|
9409
|
+
file: makeFileContracts(resolvedIds),
|
|
8771
9410
|
flow: {
|
|
8772
9411
|
addTag: makeAddTagToFlowsContract(resolvedIds),
|
|
8773
9412
|
list: makeListFlowsContract(resolvedIds),
|
|
@@ -8810,6 +9449,15 @@ var makeContractsV1 = (ids) => {
|
|
|
8810
9449
|
tag: {
|
|
8811
9450
|
create: makeCreateTagContract(resolvedIds),
|
|
8812
9451
|
list: makeListTagsContract(resolvedIds)
|
|
9452
|
+
},
|
|
9453
|
+
trigger: {
|
|
9454
|
+
create: makeCreateTriggerContract(resolvedIds),
|
|
9455
|
+
delete: makeDeleteTriggerContract(resolvedIds),
|
|
9456
|
+
find: makeFindTriggersContract(resolvedIds),
|
|
9457
|
+
get: makeGetTriggerContract(resolvedIds),
|
|
9458
|
+
pause: makePauseTriggerContract(resolvedIds),
|
|
9459
|
+
resume: makeResumeTriggerContract(resolvedIds),
|
|
9460
|
+
update: makeUpdateTriggerContract(resolvedIds)
|
|
8813
9461
|
}
|
|
8814
9462
|
};
|
|
8815
9463
|
};
|
|
@@ -9110,7 +9758,17 @@ var interactMessages = {
|
|
|
9110
9758
|
actionMayHaveHappened: "The runner could not be reached, which does not mean the action was not performed: it may have stopped answering mid-action. Take a screenshot before repeating it.",
|
|
9111
9759
|
actionNotJson: `Stdin did not hold a JSON action. Pipe one object, for example '{"type":"click","button":"left","x":480,"y":260}'.`,
|
|
9112
9760
|
actionNotSupportedOnMobile: (type) => `A mobile runner has a touchscreen, so it cannot perform ${type} as asked. It taps with a left-button click, swipes with drag, and types into whatever the last tap focused.`,
|
|
9761
|
+
actionFailedScreenshotToStdout: "Its screen was written to stdout as a JPEG, so look at that rather than sending the action again.",
|
|
9762
|
+
actionFailedScreenshotUnwritten: (detail) => `Its screen could not be written, because ${detail}, so take one with qawolf runner screenshot rather than sending the action again.`,
|
|
9763
|
+
actionFailedScreenshotWritten: (path) => `Its screen was written to ${path}, so look at that rather than sending the action again.`,
|
|
9764
|
+
actionFailedWithoutScreenshot: "The runner answered without a screen, so nothing was written; take one with qawolf runner screenshot rather than sending the action again.",
|
|
9113
9765
|
actionPerformed: (type) => `Performed ${type}.`,
|
|
9766
|
+
actionPerformedScreenshotNotAnImage: (type) => `Performed ${type}, but the screen that came with the answer was not a JPEG, so nothing was written. The action took effect, so do not repeat it: take the screen with qawolf runner screenshot instead, and report it if it keeps happening.`,
|
|
9767
|
+
actionPerformedScreenshotToStdout: (type) => `Performed ${type} and wrote the runner's screen to stdout as a JPEG. Stdout holds the image bytes alone; this line, and the JSON with --json, is on stderr.`,
|
|
9768
|
+
actionPerformedScreenshotStdoutUnwritable: (type, detail) => `Performed ${type}, but its screen could not be written to stdout: ${detail}. The action took effect, so do not repeat it: keep the pipe reading stdout open, or take the screen with qawolf runner screenshot --out <file>.`,
|
|
9769
|
+
actionPerformedScreenshotUnwritable: (type, path, detail) => `Performed ${type}, but its screen could not be written to "${path}": ${detail}. The action took effect, so do not repeat it: take the screen with qawolf runner screenshot, giving --out a path this process can write to.`,
|
|
9770
|
+
actionPerformedScreenshotWritten: (type, path) => `Performed ${type} and wrote the runner's screen to ${path}.`,
|
|
9771
|
+
actionPerformedWithoutScreenshot: (type) => `Performed ${type}, but the runner answered without the screen it was asked for. The action took effect, so do not repeat it: take the screen with qawolf runner screenshot instead. If this keeps happening, the platform or this CLI is behind the other: upgrade with npm install -g @qawolf/cli.`,
|
|
9114
9772
|
actionAnsweredUnknown: (failureReason) => `The runner answered "${failureReason}", which this version of the CLI does not know how to report. Upgrade with npm install -g @qawolf/cli.`,
|
|
9115
9773
|
screenshotAnsweredUnknown: (failureReason) => `The runner answered "${failureReason}", which this version of the CLI does not know how to report. Upgrade with npm install -g @qawolf/cli.`,
|
|
9116
9774
|
runnerHasNoScreen: "This runner does not run a browser on a virtual desktop, so there is nothing about it to see or drive. Retrying will never help: launch a playwright runner instead.",
|
|
@@ -9118,12 +9776,16 @@ var interactMessages = {
|
|
|
9118
9776
|
nothingToInspect: (errorMessage) => `The runner had nothing to inspect${errorMessage === undefined ? "" : `: ${errorMessage}`}. There is no live page, nothing matched the selector, or no variable has that name; a runner cannot tell those apart. Run a flow on it first, or check the selector or name.`,
|
|
9119
9777
|
inspectAnsweredUnknown: (failureReason) => `The runner answered "${failureReason}", which this version of the CLI does not know how to report. Upgrade with npm install -g @qawolf/cli.`,
|
|
9120
9778
|
inspectMobileAnsweredUnknown: (failureReason) => `The runner answered "${failureReason}", which this version of the CLI does not know how to report. Upgrade with npm install -g @qawolf/cli.`,
|
|
9779
|
+
inspectMobileInvalidSelector: "The runner could not parse that selector under the strategy it was given. Retrying it unchanged will never help: correct the selector, or pick the strategy that matches it.",
|
|
9121
9780
|
runnerIsNotMobile: "This runner is not a mobile device, so there is nothing here to inspect. Retrying will never help: launch an android or ios runner instead.",
|
|
9122
9781
|
screenNeedsARun: "This runner has not run anything yet, so its screen has never started. Waiting will not clear this and there is nothing to retry: run a flow on it with qawolf runner run, then ask again. Evaluating a snippet does not start a screen.",
|
|
9123
9782
|
screenNotReady: "The runner has a screen and cannot serve this yet. Its virtual desktop restarts when a run changes the display size, and it serves one request at a time, so something already in flight is the usual reason. Retry in a second or two.",
|
|
9124
9783
|
screenshotNotAnImage: "The screen was captured but did not arrive as a JPEG, so nothing was written. Nothing about the command needs changing: try it again, and report it if it keeps happening.",
|
|
9784
|
+
stdoutIsATerminal: (flag) => `Stdout is a terminal, so the JPEG bytes would have nowhere to go. Redirect stdout to a file or pipe it into a reader, or give ${flag} a file path instead of "-".`,
|
|
9785
|
+
screenshotStdoutUnwritable: (detail) => `The screen was captured but could not be written to stdout: ${detail}. Keep the pipe reading stdout open, or give --out a file path instead of "-".`,
|
|
9125
9786
|
screenshotUnwritable: (path, detail) => `The screen was captured but could not be written to "${path}": ${detail}. Give --out a path this process can write to.`,
|
|
9126
9787
|
screenshotWritten: (path) => `Wrote the runner's screen to ${path}.`,
|
|
9788
|
+
screenshotWrittenToStdout: "Wrote the runner's screen to stdout as a JPEG. Stdout holds the image bytes alone; this line, and the JSON with --json, is on stderr.",
|
|
9127
9789
|
snippetEmpty: (path) => `"${path}" holds no code to evaluate.`,
|
|
9128
9790
|
snippetErrored: (errorMessage) => errorMessage === undefined ? "The snippet threw and reported no message." : `The snippet threw: ${errorMessage}`,
|
|
9129
9791
|
snippetFileUnreadable: (path) => `Could not read "${path}". Name a readable file, or "-" to read the snippet from stdin.`,
|
|
@@ -10553,19 +11215,38 @@ function isTimeoutError(err) {
|
|
|
10553
11215
|
|
|
10554
11216
|
// src/shell/interactiveRunner/writeScreenshot.ts
|
|
10555
11217
|
var jpegStartOfImage = [255, 216, 255];
|
|
11218
|
+
var stdoutPath = "-";
|
|
10556
11219
|
async function writeScreenshot(options) {
|
|
10557
11220
|
const bytes = Buffer.from(options.imageJpegBase64, "base64");
|
|
10558
11221
|
if (jpegStartOfImage.some((byte, index) => bytes[index] !== byte)) {
|
|
10559
11222
|
return { ok: false, reason: "not-a-jpeg" };
|
|
10560
11223
|
}
|
|
10561
11224
|
try {
|
|
10562
|
-
|
|
10563
|
-
|
|
11225
|
+
if (options.path === stdoutPath) {
|
|
11226
|
+
await writeToStdout(options.stdout ?? process.stdout, bytes);
|
|
11227
|
+
} else {
|
|
11228
|
+
await options.fs.mkdir(dirname3(options.path), { recursive: true });
|
|
11229
|
+
await options.fs.writeFile(options.path, bytes);
|
|
11230
|
+
}
|
|
10564
11231
|
} catch (error) {
|
|
10565
11232
|
return { detail: errorMessage(error), ok: false, reason: "unwritable" };
|
|
10566
11233
|
}
|
|
10567
11234
|
return { ok: true };
|
|
10568
11235
|
}
|
|
11236
|
+
function writeToStdout(stdout, bytes) {
|
|
11237
|
+
return new Promise((resolve, reject) => {
|
|
11238
|
+
const onError = (error) => reject(error);
|
|
11239
|
+
stdout.once("error", onError);
|
|
11240
|
+
stdout.write(bytes, (error) => {
|
|
11241
|
+
if (error) {
|
|
11242
|
+
reject(error);
|
|
11243
|
+
return;
|
|
11244
|
+
}
|
|
11245
|
+
stdout.off("error", onError);
|
|
11246
|
+
resolve();
|
|
11247
|
+
});
|
|
11248
|
+
});
|
|
11249
|
+
}
|
|
10569
11250
|
|
|
10570
11251
|
// src/shell/stdin.ts
|
|
10571
11252
|
async function readStdin() {
|
|
@@ -12575,9 +13256,14 @@ function createPageVerbs({ platformClient }) {
|
|
|
12575
13256
|
return {
|
|
12576
13257
|
async act({
|
|
12577
13258
|
action,
|
|
12578
|
-
runnerId
|
|
13259
|
+
runnerId,
|
|
13260
|
+
withScreenshot
|
|
12579
13261
|
}) {
|
|
12580
|
-
return toSdkResult(await platformClient.callPublicApi(performAction, {
|
|
13262
|
+
return toSdkResult(await platformClient.callPublicApi(performAction, {
|
|
13263
|
+
action,
|
|
13264
|
+
id: runnerId,
|
|
13265
|
+
...withScreenshot === undefined ? {} : { withScreenshot }
|
|
13266
|
+
}, runnerCallOptions));
|
|
12581
13267
|
},
|
|
12582
13268
|
async highlightSelector({
|
|
12583
13269
|
highlight,
|
|
@@ -13177,4 +13863,4 @@ export {
|
|
|
13177
13863
|
createRunnerSdk
|
|
13178
13864
|
};
|
|
13179
13865
|
|
|
13180
|
-
//# debugId=
|
|
13866
|
+
//# debugId=A460E98091C1C6D964756E2164756E21
|