@qawolf/cli 1.34.0 → 1.35.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 +175 -20
- package/dist/runner-sdk.js +173 -18
- package/package.json +2 -2
- package/skills/qawolf-cli/SKILL.md +5 -2
- package/skills/qawolf-cli/references/run-results.md +29 -2
package/dist/cli.js
CHANGED
|
@@ -16635,7 +16635,7 @@ var agentSessionStatuses = [
|
|
|
16635
16635
|
"failed",
|
|
16636
16636
|
"cancelled"
|
|
16637
16637
|
];
|
|
16638
|
-
var agentSessionStatusSchema = _enum(agentSessionStatuses).describe('Where the work stands. "working" means the AI is still on it. "waiting-for-you" means it asked a question and cannot continue until agent.send answers it. "completed", "failed" and "cancelled" are settled and will not change.');
|
|
16638
|
+
var agentSessionStatusSchema = _enum(agentSessionStatuses).describe('Where the work stands. "working" means the AI is still on it. "waiting-for-you" means it asked a question and cannot continue until agent.send answers it. "completed" means it finished what it was asked, and a new agent.send continues it. "failed" and "cancelled" are settled and will not change.');
|
|
16639
16639
|
var agentReplySchema = object({
|
|
16640
16640
|
askedAt: exports_iso.datetime().describe("When the AI wrote this, as an ISO 8601 timestamp."),
|
|
16641
16641
|
choices: array(string2()).optional().describe("The answers the AI offered, when the reply is a question with a fixed set of them. Answer by sending one of these back through agent.send."),
|
|
@@ -16814,7 +16814,7 @@ var defaultIdSchemas = {
|
|
|
16814
16814
|
trigger: string2().min(1).describe("The id of the trigger."),
|
|
16815
16815
|
workspace: string2().min(1).describe("The id of the workspace.")
|
|
16816
16816
|
};
|
|
16817
|
-
var workspaceForEnvironmentRef = (workspace) => workspace.optional().describe("The workspace the environment belongs to
|
|
16817
|
+
var workspaceForEnvironmentRef = (workspace) => workspace.optional().describe("The workspace the environment belongs to, which an alias resolves in. Read it from whoami.");
|
|
16818
16818
|
|
|
16819
16819
|
// node_modules/@qawolf/api-contracts/dist/v1/run/flowSelection.js
|
|
16820
16820
|
var makeFlowSelectionSchema = (ids) => object({
|
|
@@ -16988,7 +16988,7 @@ var runnerNameSchema = _enum([
|
|
|
16988
16988
|
"android",
|
|
16989
16989
|
"ios"
|
|
16990
16990
|
]);
|
|
16991
|
-
var runnerWorkspaceRequirement = "
|
|
16991
|
+
var runnerWorkspaceRequirement = "Read it from whoami.";
|
|
16992
16992
|
var runnerWorkspaceIdDescription = `The workspace the runner belongs to. ${runnerWorkspaceRequirement}`;
|
|
16993
16993
|
var runnerIdSchema = string2().min(1).max(63).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, "A runner id may contain only lowercase letters, digits and dashes, and must start and end with a letter or digit.");
|
|
16994
16994
|
var runnerWatchUrlSchema = 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. This link belongs to the user: put it in a normal message as soon as the runner is launched, so they can follow along while the browser is being driven. It is theirs to open, never a page for the caller to fetch or navigate to. The page ends when the runner is terminated, so share it while the runner is alive and report what you found at the end instead of repeating a dead link.");
|
|
@@ -17569,23 +17569,28 @@ var makeTriggerActionSchema = (ids) => object({
|
|
|
17569
17569
|
instructions: string2().min(1).optional().describe("Guidance for QA Wolf. Applies to generativeSuite only."),
|
|
17570
17570
|
investigateFailures: boolean2().optional().describe("Whether QA Wolf investigates failures in the resulting runs. Defaults to true."),
|
|
17571
17571
|
kind: triggerActionKindSchema.default("createSuite"),
|
|
17572
|
+
runConcurrencyLimit: string2().trim().min(1).max(255).optional().describe(`How many runs of the resulting suite may execute at once: a whole number from 1 to 1000, "unlimited", or a concurrency expression, which the server validates. It replaces the environment's limit rather than capping below it. Omit it to leave the environment's limit in charge.`),
|
|
17572
17573
|
tagNames: array(string2().min(1)).default([]).describe("Tags naming the flows to run. Combined with flowIds.")
|
|
17573
17574
|
}).describe("What the trigger runs when it fires.");
|
|
17574
17575
|
var makeTriggerScheduleFields = (ids) => ({
|
|
17575
17576
|
action: makeTriggerActionSchema(ids),
|
|
17576
17577
|
cadence: triggerCadenceSchema,
|
|
17577
17578
|
dayOfWeek: triggerDayOfWeekSchema.optional().describe("The day a weekly schedule fires on, read in timezoneId. Required when cadence is weekly."),
|
|
17579
|
+
daysOfWeek: array(triggerDayOfWeekSchema).min(1).refine((daysOfWeek) => new Set(daysOfWeek).size === daysOfWeek.length, {
|
|
17580
|
+
message: "Expected each day to be named at most once."
|
|
17581
|
+
}).optional().describe("The only days an hourly or daily schedule fires on, read in timezoneId. Name each day at most once. Omitting it fires on every day."),
|
|
17578
17582
|
environmentId: ids.environmentId.describe("The environment the scheduled runs happen in."),
|
|
17579
17583
|
minuteOfHour: number2().int().min(0).max(59).optional().describe("Minutes past the hour an hourly schedule fires. Defaults to 0."),
|
|
17580
17584
|
timeOfDay: string2().regex(/^([01]\d|2[0-3]):[0-5]\d$/).optional().describe('The wall clock time a daily or weekly schedule fires, as "HH:mm". Required when cadence is daily or weekly.'),
|
|
17581
|
-
timezoneId: string2().min(1).refine(isTimezone, "Expected an IANA timezone, such as America/New_York.").optional().describe("The IANA timezone
|
|
17585
|
+
timezoneId: string2().min(1).refine(isTimezone, "Expected an IANA timezone, such as America/New_York.").optional().describe("The IANA timezone the schedule is read in, such as America/New_York. Required when cadence is daily or weekly, and when an hourly schedule names daysOfWeek, whose day boundaries it sets. An hourly schedule firing on every day needs none, and is read in America/Los_Angeles.")
|
|
17582
17586
|
});
|
|
17583
17587
|
var makeTriggerDeploymentFields = (ids) => ({
|
|
17584
17588
|
action: makeTriggerActionSchema(ids),
|
|
17585
17589
|
branchPattern: string2().min(1).optional().describe("Only fire for deployments of a branch matching this pattern."),
|
|
17586
|
-
deployTargetPattern: string2().min(1).optional().describe("Only fire for deployments
|
|
17590
|
+
deployTargetPattern: string2().min(1).optional().describe("Only fire for deployments whose deploy target matches this pattern. A deploy target is the URL or label the deploy reported, which many deployments do not carry."),
|
|
17587
17591
|
environmentIds: array(ids.environment).default([]).describe("Only fire for deployments to these environments. Mutually exclusive with environmentPattern."),
|
|
17588
|
-
environmentPattern: string2().min(1).optional().describe("Only fire for deployments to environments matching this pattern. Mutually exclusive with environmentIds.")
|
|
17592
|
+
environmentPattern: string2().min(1).optional().describe("Only fire for deployments to environments matching this pattern. Mutually exclusive with environmentIds."),
|
|
17593
|
+
servicePattern: string2().min(1).optional().describe("Only fire for deployments whose service matches this pattern. A deployment that names no service never matches it.")
|
|
17589
17594
|
});
|
|
17590
17595
|
|
|
17591
17596
|
// node_modules/@qawolf/api-contracts/dist/v1/trigger/configurationRules.js
|
|
@@ -17621,20 +17626,28 @@ var requiredScheduleFields = {
|
|
|
17621
17626
|
hourly: [],
|
|
17622
17627
|
weekly: ["dayOfWeek", "timeOfDay", "timezoneId"]
|
|
17623
17628
|
};
|
|
17629
|
+
var optionalScheduleFields = {
|
|
17630
|
+
daily: ["daysOfWeek"],
|
|
17631
|
+
hourly: ["daysOfWeek", "minuteOfHour", "timezoneId"],
|
|
17632
|
+
weekly: []
|
|
17633
|
+
};
|
|
17624
17634
|
var cadencesUsingField = {
|
|
17625
17635
|
dayOfWeek: "a weekly cadence",
|
|
17636
|
+
daysOfWeek: "an hourly or daily cadence",
|
|
17626
17637
|
minuteOfHour: "an hourly cadence",
|
|
17627
17638
|
timeOfDay: "a daily or weekly cadence",
|
|
17628
|
-
timezoneId: "
|
|
17639
|
+
timezoneId: "an hourly, daily or weekly cadence"
|
|
17629
17640
|
};
|
|
17630
17641
|
var scheduleFields = [
|
|
17631
17642
|
"dayOfWeek",
|
|
17643
|
+
"daysOfWeek",
|
|
17632
17644
|
"minuteOfHour",
|
|
17633
17645
|
"timeOfDay",
|
|
17634
17646
|
"timezoneId"
|
|
17635
17647
|
];
|
|
17636
17648
|
var checkScheduleFields = (value, ctx) => {
|
|
17637
17649
|
const required = requiredScheduleFields[value.cadence];
|
|
17650
|
+
const optional = optionalScheduleFields[value.cadence];
|
|
17638
17651
|
for (const field of scheduleFields) {
|
|
17639
17652
|
const isSupplied = value[field] !== undefined;
|
|
17640
17653
|
if (required.includes(field)) {
|
|
@@ -17647,7 +17660,7 @@ var checkScheduleFields = (value, ctx) => {
|
|
|
17647
17660
|
}
|
|
17648
17661
|
continue;
|
|
17649
17662
|
}
|
|
17650
|
-
if (isSupplied && !(
|
|
17663
|
+
if (isSupplied && !optional.includes(field)) {
|
|
17651
17664
|
ctx.addIssue({
|
|
17652
17665
|
code: "custom",
|
|
17653
17666
|
message: `${field} applies to ${cadencesUsingField[field]} only.`,
|
|
@@ -17656,8 +17669,18 @@ var checkScheduleFields = (value, ctx) => {
|
|
|
17656
17669
|
}
|
|
17657
17670
|
}
|
|
17658
17671
|
};
|
|
17672
|
+
var checkHourlyZone = (value, ctx) => {
|
|
17673
|
+
if (value.cadence !== "hourly" || value.daysOfWeek === undefined || value.timezoneId !== undefined)
|
|
17674
|
+
return;
|
|
17675
|
+
ctx.addIssue({
|
|
17676
|
+
code: "custom",
|
|
17677
|
+
message: "timezoneId is required when an hourly cadence names daysOfWeek.",
|
|
17678
|
+
path: ["timezoneId"]
|
|
17679
|
+
});
|
|
17680
|
+
};
|
|
17659
17681
|
var checkSchedule = (value, ctx) => {
|
|
17660
17682
|
checkScheduleFields(value, ctx);
|
|
17683
|
+
checkHourlyZone(value, ctx);
|
|
17661
17684
|
if (value.action.kind === "generativeSuite") {
|
|
17662
17685
|
ctx.addIssue({
|
|
17663
17686
|
code: "custom",
|
|
@@ -18023,12 +18046,14 @@ var makeDeploymentResourceSchema = (ids) => resource({
|
|
|
18023
18046
|
commitAuthorName: string2().optional().describe("The author of the deployed commit."),
|
|
18024
18047
|
commitMessage: string2().optional().describe("The message of the deployed commit."),
|
|
18025
18048
|
commitSha: string2().optional().describe("The sha of the deployed commit."),
|
|
18049
|
+
commitUrl: string2().optional().describe("A link to the deployed commit, as declared by the deployment report."),
|
|
18026
18050
|
deployedAt: exports_iso.datetime().describe("When QA Wolf first received the deployment."),
|
|
18027
18051
|
deployTarget: string2().optional().describe("Identifies the deployed app within the environment: the URL it serves, or the build path of a mobile build. A trigger's deployTargetPattern matches against it."),
|
|
18028
18052
|
environmentId: ids.environment.describe("The QA Wolf environment the deployment reported into."),
|
|
18029
18053
|
environmentName: string2().optional().describe("The environment's name. Absent when the environment has since been deleted."),
|
|
18030
18054
|
id: ids.deployment,
|
|
18031
18055
|
provider: _enum(["github", "gitlab", "api"]).optional().describe("How QA Wolf received the deployment: a GitHub webhook, a GitLab webhook, or the deployment.reportStatus API."),
|
|
18056
|
+
service: string2().optional().describe("Which application was deployed, as the deployer named it. Absent when the deployer named none."),
|
|
18032
18057
|
status: _enum(["pending", "success", "failure", "inactive"]).optional().describe("The deployment's lifecycle status, in the vocabulary deployment.reportStatus accepts. Absent when no status was ever reported.")
|
|
18033
18058
|
}, {
|
|
18034
18059
|
urlFieldDescription: "Absolute URL of the workspace's deployments page."
|
|
@@ -18058,8 +18083,55 @@ var makeFindDeploymentsContract = (ids) => {
|
|
|
18058
18083
|
};
|
|
18059
18084
|
};
|
|
18060
18085
|
|
|
18086
|
+
// node_modules/@qawolf/api-contracts/dist/v1/deployment/didNotRunReason.js
|
|
18087
|
+
var didNotRunReasonSchema = _enum([
|
|
18088
|
+
"billing-prevented",
|
|
18089
|
+
"branch-still-syncing",
|
|
18090
|
+
"deployment-no-longer-live",
|
|
18091
|
+
"duplicate-run",
|
|
18092
|
+
"environment-not-linked-to-branch",
|
|
18093
|
+
"environment-not-ready",
|
|
18094
|
+
"environment-terminated",
|
|
18095
|
+
"internal-error",
|
|
18096
|
+
"low-risk-change",
|
|
18097
|
+
"no-flows-to-run",
|
|
18098
|
+
"no-matching-trigger",
|
|
18099
|
+
"no-pull-request",
|
|
18100
|
+
"no-relevant-flows",
|
|
18101
|
+
"rate-limited",
|
|
18102
|
+
"run-not-created",
|
|
18103
|
+
"skipped",
|
|
18104
|
+
"test-configuration-error",
|
|
18105
|
+
"trigger-not-found",
|
|
18106
|
+
"workspace-inactive",
|
|
18107
|
+
"workspace-not-ready"
|
|
18108
|
+
]).describe([
|
|
18109
|
+
"Why the matched trigger created no run, as a stable value safe to branch on in a CI pipeline. The accompanying `message` is the wording for a person to read and may be reworded at any time; this value will not be.",
|
|
18110
|
+
"billing-prevented: a billing restriction on the workspace stopped the run.",
|
|
18111
|
+
"branch-still-syncing: the environment was still syncing its flows.",
|
|
18112
|
+
"deployment-no-longer-live: the deployment was torn down or replaced by a newer one before the run started.",
|
|
18113
|
+
"duplicate-run: another run already covered this same deployment.",
|
|
18114
|
+
"environment-not-linked-to-branch: the environment has no branch to take flows from yet.",
|
|
18115
|
+
"environment-not-ready: the environment was still being prepared; retrying later can succeed.",
|
|
18116
|
+
"environment-terminated: the environment for the run is terminated.",
|
|
18117
|
+
"internal-error: QA Wolf could not start the run and the cause is on our side.",
|
|
18118
|
+
"low-risk-change: adaptive flow selection assessed the change as low risk, so nothing needed to run.",
|
|
18119
|
+
"no-flows-to-run: no flow was eligible, because the trigger's flows are in maintenance, still drafts, or missing on this branch.",
|
|
18120
|
+
"no-matching-trigger: no deployment trigger matched.",
|
|
18121
|
+
"no-pull-request: the trigger uses adaptive flow selection, which needs an open pull request, and this deployment had none.",
|
|
18122
|
+
"no-relevant-flows: adaptive flow selection found no existing flow covering this change.",
|
|
18123
|
+
"rate-limited: too many runs were requested at once; retrying later can succeed.",
|
|
18124
|
+
"run-not-created: the run never reached a decision.",
|
|
18125
|
+
"skipped: the run was skipped for a reason with no more specific value.",
|
|
18126
|
+
"test-configuration-error: the workspace's flows or dependency rules need fixing before this can run.",
|
|
18127
|
+
"trigger-not-found: the trigger no longer exists.",
|
|
18128
|
+
"workspace-inactive: the workspace is not active.",
|
|
18129
|
+
"workspace-not-ready: the workspace has not finished setting up."
|
|
18130
|
+
].join(`
|
|
18131
|
+
`));
|
|
18132
|
+
|
|
18061
18133
|
// node_modules/@qawolf/api-contracts/dist/v1/deployment/listTriggerEvaluations.js
|
|
18062
|
-
var conditionKindSchema = _enum(["environment", "deployTarget", "branch"]).describe("What the condition checks on the deployment: the environment it reported into, the deploy target
|
|
18134
|
+
var conditionKindSchema = _enum(["environment", "deployTarget", "branch", "service"]).describe("What the condition checks on the deployment: the environment it reported into, the deploy target it serves, the git branch of the deployed commit, or the service it deployed.");
|
|
18063
18135
|
var conditionVerdictSchema = discriminatedUnion("outcome", [
|
|
18064
18136
|
object({
|
|
18065
18137
|
kind: conditionKindSchema,
|
|
@@ -18082,12 +18154,13 @@ var makeRunOutcomeSchema = (ids) => discriminatedUnion("status", [
|
|
|
18082
18154
|
}),
|
|
18083
18155
|
object({ status: literal("starting") }),
|
|
18084
18156
|
object({
|
|
18085
|
-
|
|
18157
|
+
message: string2().describe("Why the matched trigger created no run, in plain language."),
|
|
18158
|
+
reason: didNotRunReasonSchema,
|
|
18086
18159
|
status: literal("did-not-run"),
|
|
18087
18160
|
supersededByRunId: ids.run.optional().describe("The run that covered this deployment instead, when an earlier delivery of the same deployment had already created one.")
|
|
18088
18161
|
}),
|
|
18089
18162
|
object({ status: literal("unknown") })
|
|
18090
|
-
]).describe("What became of the match. Matching is not running: a matched trigger can still be stopped from creating a run, and did-not-run carries the reason. starting means run creation is still in progress; unknown means QA Wolf has no record of what followed the match.");
|
|
18163
|
+
]).describe("What became of the match. Matching is not running: a matched trigger can still be stopped from creating a run, and did-not-run carries the reason. starting means run creation is still in progress; unknown means QA Wolf has no record of what followed the match. did-not-run also carries a stable reason to branch on, beside the message for a person to read.");
|
|
18091
18164
|
var makeVerdictSchema = (ids) => discriminatedUnion("outcome", [
|
|
18092
18165
|
object({
|
|
18093
18166
|
conditionSets: conditionSetsField,
|
|
@@ -18136,6 +18209,7 @@ var deploymentReportMetadata = strictObject({
|
|
|
18136
18209
|
commitAuthorName: string2().trim().min(1).max(255).describe("The display name of the person who authored the deployed commit.").optional(),
|
|
18137
18210
|
commitMessage: string2().trim().min(1).max(2048).describe("The message of the deployed commit. The deployments list shows its first line.").optional(),
|
|
18138
18211
|
commitSha: string2().trim().min(1).max(255).describe("The commit sha of the deployed application revision.").optional(),
|
|
18212
|
+
commitUrl: httpUrl().max(2048).describe("A link to the deployed commit in your code host. Send this when QA Wolf cannot resolve the commit itself, for example when the QA Wolf GitHub App is not installed.").optional(),
|
|
18139
18213
|
pullRequestNumber: number2().int().positive().describe("The number of the pull request the deployment belongs to. Requires repository.").optional(),
|
|
18140
18214
|
ref: string2().trim().min(1).max(255).describe("The branch or ref that was deployed.").optional(),
|
|
18141
18215
|
repository: string2().trim().min(1).max(255).describe('The owner/name of the repository, e.g. "acme/web".').optional()
|
|
@@ -18170,6 +18244,7 @@ var makeReportDeploymentStatusContract = (ids) => {
|
|
|
18170
18244
|
environmentVariables: record(string2(), string2()).describe("Environment variable overrides for the runs this deployment requests. A report that omits this field keeps the stored values. A report that sends it replaces them.").optional(),
|
|
18171
18245
|
metadata: deploymentReportMetadata.describe("Details the deployer declares about the deployed revision; a code host integration's own record of the same commit is shown in preference to the message and author declared here.").optional(),
|
|
18172
18246
|
providerDeploymentId: string2().trim().min(1).max(255).describe('Your identifier for the deployment, e.g. "vercel_dpl_123". Reports with the same providerDeploymentId update one deployment within this workspace.'),
|
|
18247
|
+
service: string2().trim().min(1).max(255).describe('Which application was deployed, e.g. "checkout-api", when several services deploy into one environment. A report that omits it keeps the stored value.').optional(),
|
|
18173
18248
|
status: deploymentStatusSchema.describe("The deployment lifecycle status. A deployment's first success report evaluates global triggers asynchronously, and it is the only report that does. The response does not include the resulting runs."),
|
|
18174
18249
|
workspaceId: ids.workspace.describe("The workspace to report the deployment status into. A team API key must name its own workspace.")
|
|
18175
18250
|
}).superRefine((value, context) => {
|
|
@@ -18840,6 +18915,70 @@ var makeGetIssueContract = (ids) => {
|
|
|
18840
18915
|
};
|
|
18841
18916
|
};
|
|
18842
18917
|
|
|
18918
|
+
// node_modules/@qawolf/api-contracts/dist/v1/investigation/finding.js
|
|
18919
|
+
var investigationFindingStateDescription = 'What the investigation concluded about the cause. Known values: "investigating", "fixed", "fix-proposed", "reported", "report-proposed", "flake", "question" and "dismissed". New values can appear.';
|
|
18920
|
+
var makeInvestigationFindingSchema = (ids) => object({
|
|
18921
|
+
actual: string2().optional(),
|
|
18922
|
+
commitHash: string2().optional(),
|
|
18923
|
+
decidedBy: _enum(["agent", "user"]).optional().describe("Who decided: the AI on its own, or a person who approved or dismissed it. Absent until someone decides."),
|
|
18924
|
+
disputeReason: string2().optional().describe("Why a person disputed what the AI did. Present on a proposal the AI made again after that dispute."),
|
|
18925
|
+
expected: string2().optional(),
|
|
18926
|
+
findingId: string2(),
|
|
18927
|
+
flowIds: array(ids.flow),
|
|
18928
|
+
headline: string2().optional(),
|
|
18929
|
+
issueId: ids.issue.optional(),
|
|
18930
|
+
kind: string2().describe('What the failure is. Known values: "maintenance", "bug", "flake" and "unknown". New values can appear.'),
|
|
18931
|
+
matchReason: string2().optional(),
|
|
18932
|
+
priority: issuePrioritySchema.optional(),
|
|
18933
|
+
question: object({
|
|
18934
|
+
answers: array(object({
|
|
18935
|
+
description: string2().optional(),
|
|
18936
|
+
title: string2(),
|
|
18937
|
+
value: string2().describe('What choosing this answer means. Known values: "apply", "dismiss", "report", "maintenance" and "bug". New values can appear.')
|
|
18938
|
+
})),
|
|
18939
|
+
text: string2()
|
|
18940
|
+
}).optional().describe("The question waiting for a person, with the answers offered."),
|
|
18941
|
+
response: object({
|
|
18942
|
+
answer: string2().optional(),
|
|
18943
|
+
at: exports_iso.datetime(),
|
|
18944
|
+
reason: string2().optional(),
|
|
18945
|
+
type: string2().describe('Known values: "answer" and "dispute". New values can appear.')
|
|
18946
|
+
}).optional().describe("A person's answer or dispute that the investigation hasn't acted on yet."),
|
|
18947
|
+
state: string2().describe(investigationFindingStateDescription),
|
|
18948
|
+
steps: array(string2()).optional(),
|
|
18949
|
+
subSessionIds: array(ids.chatSession),
|
|
18950
|
+
summary: string2().optional(),
|
|
18951
|
+
updatedAt: exports_iso.datetime()
|
|
18952
|
+
});
|
|
18953
|
+
|
|
18954
|
+
// node_modules/@qawolf/api-contracts/dist/v1/investigation/get.js
|
|
18955
|
+
var makeGetInvestigationContract = (ids) => {
|
|
18956
|
+
const input = object({ runId: ids.run });
|
|
18957
|
+
const output = resource({
|
|
18958
|
+
findings: array(makeInvestigationFindingSchema(ids)),
|
|
18959
|
+
runId: ids.run,
|
|
18960
|
+
sessionId: ids.chatSession.optional().describe("The investigation session. Absent when the run has none."),
|
|
18961
|
+
status: _enum(["investigating", "finished", "not-investigated"]).describe('Whether the investigation session is still working. "not-investigated" when the run has no investigation.')
|
|
18962
|
+
}, { urlFieldDescription: "The run in the QA Wolf app." });
|
|
18963
|
+
return {
|
|
18964
|
+
annotations: {
|
|
18965
|
+
destructiveHint: false,
|
|
18966
|
+
openWorldHint: false,
|
|
18967
|
+
readOnlyHint: true
|
|
18968
|
+
},
|
|
18969
|
+
description: "Read what the QA Wolf AI investigating a run has concluded: one finding per cause of its failures, " + "with the question waiting for a person and any answer or dispute the investigation hasn't acted on yet.",
|
|
18970
|
+
input,
|
|
18971
|
+
kind: "read",
|
|
18972
|
+
name: "investigation.get",
|
|
18973
|
+
output
|
|
18974
|
+
};
|
|
18975
|
+
};
|
|
18976
|
+
|
|
18977
|
+
// node_modules/@qawolf/api-contracts/dist/v1/investigation/index.js
|
|
18978
|
+
var makeInvestigationContracts = (ids) => ({
|
|
18979
|
+
get: makeGetInvestigationContract(ids)
|
|
18980
|
+
});
|
|
18981
|
+
|
|
18843
18982
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/addFlows.js
|
|
18844
18983
|
var makeAddFlowsToIssueContract = (ids) => {
|
|
18845
18984
|
const input = object({
|
|
@@ -19097,6 +19236,13 @@ var makeDiagnoseRunContract = (ids) => {
|
|
|
19097
19236
|
};
|
|
19098
19237
|
|
|
19099
19238
|
// node_modules/@qawolf/api-contracts/dist/v1/run/summary.js
|
|
19239
|
+
var publicRunStatusValues = [
|
|
19240
|
+
"queued",
|
|
19241
|
+
"running",
|
|
19242
|
+
"passed",
|
|
19243
|
+
"failed",
|
|
19244
|
+
"canceled"
|
|
19245
|
+
];
|
|
19100
19246
|
var makeRunSummaryFields = (ids) => ({
|
|
19101
19247
|
completedAt: exports_iso.datetime().optional().describe("When the run finished executing. Absent while queued or running, and also absent for a terminal run that never completed execution (e.g. every flow was canceled or skipped)."),
|
|
19102
19248
|
createdAt: exports_iso.datetime(),
|
|
@@ -19107,7 +19253,7 @@ var makeRunSummaryFields = (ids) => ({
|
|
|
19107
19253
|
commitUrl: string2().optional().describe("Link to the commit on the code host.")
|
|
19108
19254
|
}).describe("The branch and commit under test. The fields are present when a deploy notification started the run, and absent for runs started another way, for example manually or with run.create."),
|
|
19109
19255
|
runId: ids.run,
|
|
19110
|
-
status: _enum(
|
|
19256
|
+
status: _enum(publicRunStatusValues).describe("Whole-run status, and the value to gate a pipeline on. Terminal statuses are passed, failed, and canceled; poll until one is reached. `failed` means the run found a bug that is still open and serious enough to block — a lower-priority bug, or one since resolved, reads `passed`, and the per-flow diagnoses are still in `flows`. The run stays `running` while any investigation is unresolved, including one that carried over to a later run, so a terminal status always means a settled answer.")
|
|
19111
19257
|
});
|
|
19112
19258
|
|
|
19113
19259
|
// node_modules/@qawolf/api-contracts/dist/v1/run/find.js
|
|
@@ -19140,7 +19286,9 @@ var makeFindRunsContract = (ids) => {
|
|
|
19140
19286
|
|
|
19141
19287
|
// node_modules/@qawolf/api-contracts/dist/v1/run/get.js
|
|
19142
19288
|
var makeGetRunContract = (ids) => {
|
|
19289
|
+
const flowStatus = _enum(publicRunStatusValues);
|
|
19143
19290
|
const input = object({
|
|
19291
|
+
flowStatuses: array(flowStatus).min(1).optional().describe("Return only the flows whose status is one of these. A suite run can " + "hold hundreds of flows, so start an investigation with failed " + "alone. A flow that passed after a retry reads passed, so add " + "passed when a flaky flow is missing from the answer. Omit to " + "return every flow. The run-level fields are unaffected."),
|
|
19144
19292
|
runId: ids.run
|
|
19145
19293
|
});
|
|
19146
19294
|
const artifactUrls = {
|
|
@@ -19197,11 +19345,12 @@ var makeGetRunContract = (ids) => {
|
|
|
19197
19345
|
attempts,
|
|
19198
19346
|
flowId: ids.flow,
|
|
19199
19347
|
name: string2(),
|
|
19200
|
-
status:
|
|
19348
|
+
status: flowStatus.exclude(["failed"])
|
|
19201
19349
|
});
|
|
19202
|
-
const flows = array(discriminatedUnion("status", [failedFlow, nonFailedFlow])).describe("The run's flows, ordered alphabetically by name.");
|
|
19350
|
+
const flows = array(discriminatedUnion("status", [failedFlow, nonFailedFlow])).describe("The run's flows, ordered alphabetically by name. Only the flows " + "matching flowStatuses when the request set it.");
|
|
19203
19351
|
const output = resource({
|
|
19204
19352
|
...makeRunSummaryFields(ids),
|
|
19353
|
+
blockingBugCount: number2().int().nonnegative().describe("How many bugs this run found are blocking: still open, and priority urgent, high, or unprioritized — unprioritized counts because nobody has ruled it out yet. This is what `failed` is derived from, so it explains a failure rather than adding a second verdict: gate on `status`, then read this to say how many bugs are holding the build. It counts a bug filed against a later run by an investigation that carried over from this one, and it drops a bug once that bug is resolved."),
|
|
19205
19354
|
flows,
|
|
19206
19355
|
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.")
|
|
19207
19356
|
}, { urlFieldDescription: "Absolute URL of the run page." });
|
|
@@ -19211,7 +19360,7 @@ var makeGetRunContract = (ids) => {
|
|
|
19211
19360
|
openWorldHint: false,
|
|
19212
19361
|
readOnlyHint: true
|
|
19213
19362
|
},
|
|
19214
|
-
description: "Get a run's status, per-flow results, and
|
|
19363
|
+
description: "Get a run's status, per-flow results, links, and how many of its bugs are blocking.",
|
|
19215
19364
|
input,
|
|
19216
19365
|
kind: "read",
|
|
19217
19366
|
name: "run.get",
|
|
@@ -19463,8 +19612,12 @@ var makeImportPackageOnRunnerContract = (ids) => {
|
|
|
19463
19612
|
var makeLaunchRunnerContract = (ids) => {
|
|
19464
19613
|
const input = object({
|
|
19465
19614
|
id: runnerIdSchema.describe("Id to launch the runner under, chosen by the caller. Launching the same id again returns the runner already running under it."),
|
|
19615
|
+
initialUrl: navigableUrlSchema.optional().describe("The page to open as the browser starts, so the first screenshot already shows the application rather than a blank page."),
|
|
19466
19616
|
runnerName: runnerNameSchema.optional().describe("The runner family to launch. Defaults to the standard web family, playwright."),
|
|
19467
19617
|
workspaceId: ids.workspace.optional().describe(`The workspace to launch the runner in. ${runnerWorkspaceRequirement}`)
|
|
19618
|
+
}).refine((request) => request.initialUrl === undefined || (request.runnerName ?? "playwright") === "playwright", {
|
|
19619
|
+
message: "initialUrl opens a page in the runner's browser, so only the playwright runner takes it.",
|
|
19620
|
+
path: ["initialUrl"]
|
|
19468
19621
|
});
|
|
19469
19622
|
const output = makeRunnerSchema().extend({
|
|
19470
19623
|
alreadyRunning: boolean2().describe("True when a runner was already running under this id and was returned unchanged, so no second runner was started and nothing new is billed. Not an error either way."),
|
|
@@ -19476,7 +19629,7 @@ var makeLaunchRunnerContract = (ids) => {
|
|
|
19476
19629
|
openWorldHint: false,
|
|
19477
19630
|
readOnlyHint: false
|
|
19478
19631
|
},
|
|
19479
|
-
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
|
|
19632
|
+
description: "Launch an interactive runner on the caller's team under an id the caller chooses. Send `initialUrl` so its browser comes up on the page the work starts from, which saves a separate navigation and the browser's cold start. 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. A success means the runner is answering: the call waits for the pod it started to come up, so the very next call to the runner reaches it. If the pod does not come up in time the call fails instead, leaving the runner running, and launching the same id again attaches to it.",
|
|
19480
19633
|
input,
|
|
19481
19634
|
kind: "write",
|
|
19482
19635
|
name: "runner.launch",
|
|
@@ -19522,7 +19675,7 @@ var makeListRunnersContract = (ids) => {
|
|
|
19522
19675
|
openWorldHint: false,
|
|
19523
19676
|
readOnlyHint: true
|
|
19524
19677
|
},
|
|
19525
|
-
description: "List the runners running on the caller's team right now. A
|
|
19678
|
+
description: "List the runners running on the caller's team right now. A listed runner may be driven by another machine or session, so sending it work can collide with theirs. 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.",
|
|
19526
19679
|
input,
|
|
19527
19680
|
kind: "read",
|
|
19528
19681
|
name: "runner.list",
|
|
@@ -19607,6 +19760,7 @@ var makeRunFlowOnRunnerContract = (ids) => {
|
|
|
19607
19760
|
env: runEnvironmentSchema.optional().describe("Environment variables to make available to the run."),
|
|
19608
19761
|
environmentId: ids.environmentRef.optional().describe("A QA Wolf environment whose variables the run is given, by id or alias. QA Wolf reads and decrypts them itself, so they never travel in the request and the count and length limits on `env` do not apply to them. Send this or `env`, not both."),
|
|
19609
19762
|
files: runFilesSchema.describe("Every file the run needs keyed by its path — the flow file, everything it imports, package.json and tsconfig.json. A runner holds no copy of your project, so what runs is exactly what is sent here."),
|
|
19763
|
+
flowId: ids.flow.optional().describe("The QA Wolf flow this run is for. The run then sees it as `QAWOLF_WORKFLOW_ID`, the same value a platform run of that flow sees, so fixtures named and cleaned up by it match across both. Omit it when the flow is not in QA Wolf yet, and the run has no `QAWOLF_WORKFLOW_ID`."),
|
|
19610
19764
|
id: runnerIdSchema.describe("Id of the runner to run the flow on."),
|
|
19611
19765
|
selection: runSelectionSchema.optional().describe("Run only these lines, inside the page the runner is already on, instead of running the whole flow from a fresh browser. Omit to run the whole entry point."),
|
|
19612
19766
|
unchangedFiles: unchangedFilesSchema.optional().describe("Files this runner already holds from an earlier run, keyed by path with a hex SHA-256 of the content it should hold. Send this to make `files` only what changed. The runner refuses with `needs-full-sync` if it holds none of a referenced path, so it never runs something other than what was asked for. Omit it to send every file."),
|
|
@@ -19858,6 +20012,7 @@ var makeContractsV1 = (ids) => {
|
|
|
19858
20012
|
removeTag: makeRemoveTagFromFlowsContract(resolvedIds),
|
|
19859
20013
|
update: makeUpdateFlowContract(resolvedIds)
|
|
19860
20014
|
},
|
|
20015
|
+
investigation: makeInvestigationContracts(resolvedIds),
|
|
19861
20016
|
issue: {
|
|
19862
20017
|
addFlows: makeAddFlowsToIssueContract(resolvedIds),
|
|
19863
20018
|
create: makeCreateIssueContract(resolvedIds),
|
|
@@ -22390,7 +22545,7 @@ function startUpdateCheck(deps) {
|
|
|
22390
22545
|
// package.json
|
|
22391
22546
|
var package_default = {
|
|
22392
22547
|
name: "@qawolf/cli",
|
|
22393
|
-
version: "1.
|
|
22548
|
+
version: "1.35.0",
|
|
22394
22549
|
description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
22395
22550
|
keywords: [
|
|
22396
22551
|
"automation",
|
|
@@ -22461,7 +22616,7 @@ var package_default = {
|
|
|
22461
22616
|
"@clack/prompts": "1.5.1",
|
|
22462
22617
|
"@napi-rs/keyring": "1.3.0",
|
|
22463
22618
|
"@oxc-node/core": "0.1.0",
|
|
22464
|
-
"@qawolf/api-contracts": "0.
|
|
22619
|
+
"@qawolf/api-contracts": "0.70.0",
|
|
22465
22620
|
"@qawolf/emails": "1.1.1",
|
|
22466
22621
|
"@qawolf/flow-targets": "1.0.0",
|
|
22467
22622
|
"@qawolf/flows": "0.1.4",
|
|
@@ -38665,4 +38820,4 @@ createProgram({ signals }).parseAsync().catch(() => {
|
|
|
38665
38820
|
process.exitCode = 1;
|
|
38666
38821
|
}).finally(() => exitWhenIdle(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
38667
38822
|
|
|
38668
|
-
//# debugId=
|
|
38823
|
+
//# debugId=DB32E61082C9C27564756E2164756E21
|
package/dist/runner-sdk.js
CHANGED
|
@@ -6998,7 +6998,7 @@ var agentSessionStatuses = [
|
|
|
6998
6998
|
"failed",
|
|
6999
6999
|
"cancelled"
|
|
7000
7000
|
];
|
|
7001
|
-
var agentSessionStatusSchema = _enum(agentSessionStatuses).describe('Where the work stands. "working" means the AI is still on it. "waiting-for-you" means it asked a question and cannot continue until agent.send answers it. "completed", "failed" and "cancelled" are settled and will not change.');
|
|
7001
|
+
var agentSessionStatusSchema = _enum(agentSessionStatuses).describe('Where the work stands. "working" means the AI is still on it. "waiting-for-you" means it asked a question and cannot continue until agent.send answers it. "completed" means it finished what it was asked, and a new agent.send continues it. "failed" and "cancelled" are settled and will not change.');
|
|
7002
7002
|
var agentReplySchema = object({
|
|
7003
7003
|
askedAt: exports_iso.datetime().describe("When the AI wrote this, as an ISO 8601 timestamp."),
|
|
7004
7004
|
choices: array(string2()).optional().describe("The answers the AI offered, when the reply is a question with a fixed set of them. Answer by sending one of these back through agent.send."),
|
|
@@ -7177,7 +7177,7 @@ var defaultIdSchemas = {
|
|
|
7177
7177
|
trigger: string2().min(1).describe("The id of the trigger."),
|
|
7178
7178
|
workspace: string2().min(1).describe("The id of the workspace.")
|
|
7179
7179
|
};
|
|
7180
|
-
var workspaceForEnvironmentRef = (workspace) => workspace.optional().describe("The workspace the environment belongs to
|
|
7180
|
+
var workspaceForEnvironmentRef = (workspace) => workspace.optional().describe("The workspace the environment belongs to, which an alias resolves in. Read it from whoami.");
|
|
7181
7181
|
|
|
7182
7182
|
// node_modules/@qawolf/api-contracts/dist/v1/run/flowSelection.js
|
|
7183
7183
|
var makeFlowSelectionSchema = (ids) => object({
|
|
@@ -7353,7 +7353,7 @@ var runnerNameSchema = _enum([
|
|
|
7353
7353
|
"android",
|
|
7354
7354
|
"ios"
|
|
7355
7355
|
]);
|
|
7356
|
-
var runnerWorkspaceRequirement = "
|
|
7356
|
+
var runnerWorkspaceRequirement = "Read it from whoami.";
|
|
7357
7357
|
var runnerWorkspaceIdDescription = `The workspace the runner belongs to. ${runnerWorkspaceRequirement}`;
|
|
7358
7358
|
var runnerIdSchema = string2().min(1).max(63).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, "A runner id may contain only lowercase letters, digits and dashes, and must start and end with a letter or digit.");
|
|
7359
7359
|
var runnerWatchUrlSchema = 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. This link belongs to the user: put it in a normal message as soon as the runner is launched, so they can follow along while the browser is being driven. It is theirs to open, never a page for the caller to fetch or navigate to. The page ends when the runner is terminated, so share it while the runner is alive and report what you found at the end instead of repeating a dead link.");
|
|
@@ -7938,23 +7938,28 @@ var makeTriggerActionSchema = (ids) => object({
|
|
|
7938
7938
|
instructions: string2().min(1).optional().describe("Guidance for QA Wolf. Applies to generativeSuite only."),
|
|
7939
7939
|
investigateFailures: boolean2().optional().describe("Whether QA Wolf investigates failures in the resulting runs. Defaults to true."),
|
|
7940
7940
|
kind: triggerActionKindSchema.default("createSuite"),
|
|
7941
|
+
runConcurrencyLimit: string2().trim().min(1).max(255).optional().describe(`How many runs of the resulting suite may execute at once: a whole number from 1 to 1000, "unlimited", or a concurrency expression, which the server validates. It replaces the environment's limit rather than capping below it. Omit it to leave the environment's limit in charge.`),
|
|
7941
7942
|
tagNames: array(string2().min(1)).default([]).describe("Tags naming the flows to run. Combined with flowIds.")
|
|
7942
7943
|
}).describe("What the trigger runs when it fires.");
|
|
7943
7944
|
var makeTriggerScheduleFields = (ids) => ({
|
|
7944
7945
|
action: makeTriggerActionSchema(ids),
|
|
7945
7946
|
cadence: triggerCadenceSchema,
|
|
7946
7947
|
dayOfWeek: triggerDayOfWeekSchema.optional().describe("The day a weekly schedule fires on, read in timezoneId. Required when cadence is weekly."),
|
|
7948
|
+
daysOfWeek: array(triggerDayOfWeekSchema).min(1).refine((daysOfWeek) => new Set(daysOfWeek).size === daysOfWeek.length, {
|
|
7949
|
+
message: "Expected each day to be named at most once."
|
|
7950
|
+
}).optional().describe("The only days an hourly or daily schedule fires on, read in timezoneId. Name each day at most once. Omitting it fires on every day."),
|
|
7947
7951
|
environmentId: ids.environmentId.describe("The environment the scheduled runs happen in."),
|
|
7948
7952
|
minuteOfHour: number2().int().min(0).max(59).optional().describe("Minutes past the hour an hourly schedule fires. Defaults to 0."),
|
|
7949
7953
|
timeOfDay: string2().regex(/^([01]\d|2[0-3]):[0-5]\d$/).optional().describe('The wall clock time a daily or weekly schedule fires, as "HH:mm". Required when cadence is daily or weekly.'),
|
|
7950
|
-
timezoneId: string2().min(1).refine(isTimezone, "Expected an IANA timezone, such as America/New_York.").optional().describe("The IANA timezone
|
|
7954
|
+
timezoneId: string2().min(1).refine(isTimezone, "Expected an IANA timezone, such as America/New_York.").optional().describe("The IANA timezone the schedule is read in, such as America/New_York. Required when cadence is daily or weekly, and when an hourly schedule names daysOfWeek, whose day boundaries it sets. An hourly schedule firing on every day needs none, and is read in America/Los_Angeles.")
|
|
7951
7955
|
});
|
|
7952
7956
|
var makeTriggerDeploymentFields = (ids) => ({
|
|
7953
7957
|
action: makeTriggerActionSchema(ids),
|
|
7954
7958
|
branchPattern: string2().min(1).optional().describe("Only fire for deployments of a branch matching this pattern."),
|
|
7955
|
-
deployTargetPattern: string2().min(1).optional().describe("Only fire for deployments
|
|
7959
|
+
deployTargetPattern: string2().min(1).optional().describe("Only fire for deployments whose deploy target matches this pattern. A deploy target is the URL or label the deploy reported, which many deployments do not carry."),
|
|
7956
7960
|
environmentIds: array(ids.environment).default([]).describe("Only fire for deployments to these environments. Mutually exclusive with environmentPattern."),
|
|
7957
|
-
environmentPattern: string2().min(1).optional().describe("Only fire for deployments to environments matching this pattern. Mutually exclusive with environmentIds.")
|
|
7961
|
+
environmentPattern: string2().min(1).optional().describe("Only fire for deployments to environments matching this pattern. Mutually exclusive with environmentIds."),
|
|
7962
|
+
servicePattern: string2().min(1).optional().describe("Only fire for deployments whose service matches this pattern. A deployment that names no service never matches it.")
|
|
7958
7963
|
});
|
|
7959
7964
|
|
|
7960
7965
|
// node_modules/@qawolf/api-contracts/dist/v1/trigger/configurationRules.js
|
|
@@ -7990,20 +7995,28 @@ var requiredScheduleFields = {
|
|
|
7990
7995
|
hourly: [],
|
|
7991
7996
|
weekly: ["dayOfWeek", "timeOfDay", "timezoneId"]
|
|
7992
7997
|
};
|
|
7998
|
+
var optionalScheduleFields = {
|
|
7999
|
+
daily: ["daysOfWeek"],
|
|
8000
|
+
hourly: ["daysOfWeek", "minuteOfHour", "timezoneId"],
|
|
8001
|
+
weekly: []
|
|
8002
|
+
};
|
|
7993
8003
|
var cadencesUsingField = {
|
|
7994
8004
|
dayOfWeek: "a weekly cadence",
|
|
8005
|
+
daysOfWeek: "an hourly or daily cadence",
|
|
7995
8006
|
minuteOfHour: "an hourly cadence",
|
|
7996
8007
|
timeOfDay: "a daily or weekly cadence",
|
|
7997
|
-
timezoneId: "
|
|
8008
|
+
timezoneId: "an hourly, daily or weekly cadence"
|
|
7998
8009
|
};
|
|
7999
8010
|
var scheduleFields = [
|
|
8000
8011
|
"dayOfWeek",
|
|
8012
|
+
"daysOfWeek",
|
|
8001
8013
|
"minuteOfHour",
|
|
8002
8014
|
"timeOfDay",
|
|
8003
8015
|
"timezoneId"
|
|
8004
8016
|
];
|
|
8005
8017
|
var checkScheduleFields = (value, ctx) => {
|
|
8006
8018
|
const required = requiredScheduleFields[value.cadence];
|
|
8019
|
+
const optional = optionalScheduleFields[value.cadence];
|
|
8007
8020
|
for (const field of scheduleFields) {
|
|
8008
8021
|
const isSupplied = value[field] !== undefined;
|
|
8009
8022
|
if (required.includes(field)) {
|
|
@@ -8016,7 +8029,7 @@ var checkScheduleFields = (value, ctx) => {
|
|
|
8016
8029
|
}
|
|
8017
8030
|
continue;
|
|
8018
8031
|
}
|
|
8019
|
-
if (isSupplied && !(
|
|
8032
|
+
if (isSupplied && !optional.includes(field)) {
|
|
8020
8033
|
ctx.addIssue({
|
|
8021
8034
|
code: "custom",
|
|
8022
8035
|
message: `${field} applies to ${cadencesUsingField[field]} only.`,
|
|
@@ -8025,8 +8038,18 @@ var checkScheduleFields = (value, ctx) => {
|
|
|
8025
8038
|
}
|
|
8026
8039
|
}
|
|
8027
8040
|
};
|
|
8041
|
+
var checkHourlyZone = (value, ctx) => {
|
|
8042
|
+
if (value.cadence !== "hourly" || value.daysOfWeek === undefined || value.timezoneId !== undefined)
|
|
8043
|
+
return;
|
|
8044
|
+
ctx.addIssue({
|
|
8045
|
+
code: "custom",
|
|
8046
|
+
message: "timezoneId is required when an hourly cadence names daysOfWeek.",
|
|
8047
|
+
path: ["timezoneId"]
|
|
8048
|
+
});
|
|
8049
|
+
};
|
|
8028
8050
|
var checkSchedule = (value, ctx) => {
|
|
8029
8051
|
checkScheduleFields(value, ctx);
|
|
8052
|
+
checkHourlyZone(value, ctx);
|
|
8030
8053
|
if (value.action.kind === "generativeSuite") {
|
|
8031
8054
|
ctx.addIssue({
|
|
8032
8055
|
code: "custom",
|
|
@@ -8392,12 +8415,14 @@ var makeDeploymentResourceSchema = (ids) => resource({
|
|
|
8392
8415
|
commitAuthorName: string2().optional().describe("The author of the deployed commit."),
|
|
8393
8416
|
commitMessage: string2().optional().describe("The message of the deployed commit."),
|
|
8394
8417
|
commitSha: string2().optional().describe("The sha of the deployed commit."),
|
|
8418
|
+
commitUrl: string2().optional().describe("A link to the deployed commit, as declared by the deployment report."),
|
|
8395
8419
|
deployedAt: exports_iso.datetime().describe("When QA Wolf first received the deployment."),
|
|
8396
8420
|
deployTarget: string2().optional().describe("Identifies the deployed app within the environment: the URL it serves, or the build path of a mobile build. A trigger's deployTargetPattern matches against it."),
|
|
8397
8421
|
environmentId: ids.environment.describe("The QA Wolf environment the deployment reported into."),
|
|
8398
8422
|
environmentName: string2().optional().describe("The environment's name. Absent when the environment has since been deleted."),
|
|
8399
8423
|
id: ids.deployment,
|
|
8400
8424
|
provider: _enum(["github", "gitlab", "api"]).optional().describe("How QA Wolf received the deployment: a GitHub webhook, a GitLab webhook, or the deployment.reportStatus API."),
|
|
8425
|
+
service: string2().optional().describe("Which application was deployed, as the deployer named it. Absent when the deployer named none."),
|
|
8401
8426
|
status: _enum(["pending", "success", "failure", "inactive"]).optional().describe("The deployment's lifecycle status, in the vocabulary deployment.reportStatus accepts. Absent when no status was ever reported.")
|
|
8402
8427
|
}, {
|
|
8403
8428
|
urlFieldDescription: "Absolute URL of the workspace's deployments page."
|
|
@@ -8427,8 +8452,55 @@ var makeFindDeploymentsContract = (ids) => {
|
|
|
8427
8452
|
};
|
|
8428
8453
|
};
|
|
8429
8454
|
|
|
8455
|
+
// node_modules/@qawolf/api-contracts/dist/v1/deployment/didNotRunReason.js
|
|
8456
|
+
var didNotRunReasonSchema = _enum([
|
|
8457
|
+
"billing-prevented",
|
|
8458
|
+
"branch-still-syncing",
|
|
8459
|
+
"deployment-no-longer-live",
|
|
8460
|
+
"duplicate-run",
|
|
8461
|
+
"environment-not-linked-to-branch",
|
|
8462
|
+
"environment-not-ready",
|
|
8463
|
+
"environment-terminated",
|
|
8464
|
+
"internal-error",
|
|
8465
|
+
"low-risk-change",
|
|
8466
|
+
"no-flows-to-run",
|
|
8467
|
+
"no-matching-trigger",
|
|
8468
|
+
"no-pull-request",
|
|
8469
|
+
"no-relevant-flows",
|
|
8470
|
+
"rate-limited",
|
|
8471
|
+
"run-not-created",
|
|
8472
|
+
"skipped",
|
|
8473
|
+
"test-configuration-error",
|
|
8474
|
+
"trigger-not-found",
|
|
8475
|
+
"workspace-inactive",
|
|
8476
|
+
"workspace-not-ready"
|
|
8477
|
+
]).describe([
|
|
8478
|
+
"Why the matched trigger created no run, as a stable value safe to branch on in a CI pipeline. The accompanying `message` is the wording for a person to read and may be reworded at any time; this value will not be.",
|
|
8479
|
+
"billing-prevented: a billing restriction on the workspace stopped the run.",
|
|
8480
|
+
"branch-still-syncing: the environment was still syncing its flows.",
|
|
8481
|
+
"deployment-no-longer-live: the deployment was torn down or replaced by a newer one before the run started.",
|
|
8482
|
+
"duplicate-run: another run already covered this same deployment.",
|
|
8483
|
+
"environment-not-linked-to-branch: the environment has no branch to take flows from yet.",
|
|
8484
|
+
"environment-not-ready: the environment was still being prepared; retrying later can succeed.",
|
|
8485
|
+
"environment-terminated: the environment for the run is terminated.",
|
|
8486
|
+
"internal-error: QA Wolf could not start the run and the cause is on our side.",
|
|
8487
|
+
"low-risk-change: adaptive flow selection assessed the change as low risk, so nothing needed to run.",
|
|
8488
|
+
"no-flows-to-run: no flow was eligible, because the trigger's flows are in maintenance, still drafts, or missing on this branch.",
|
|
8489
|
+
"no-matching-trigger: no deployment trigger matched.",
|
|
8490
|
+
"no-pull-request: the trigger uses adaptive flow selection, which needs an open pull request, and this deployment had none.",
|
|
8491
|
+
"no-relevant-flows: adaptive flow selection found no existing flow covering this change.",
|
|
8492
|
+
"rate-limited: too many runs were requested at once; retrying later can succeed.",
|
|
8493
|
+
"run-not-created: the run never reached a decision.",
|
|
8494
|
+
"skipped: the run was skipped for a reason with no more specific value.",
|
|
8495
|
+
"test-configuration-error: the workspace's flows or dependency rules need fixing before this can run.",
|
|
8496
|
+
"trigger-not-found: the trigger no longer exists.",
|
|
8497
|
+
"workspace-inactive: the workspace is not active.",
|
|
8498
|
+
"workspace-not-ready: the workspace has not finished setting up."
|
|
8499
|
+
].join(`
|
|
8500
|
+
`));
|
|
8501
|
+
|
|
8430
8502
|
// node_modules/@qawolf/api-contracts/dist/v1/deployment/listTriggerEvaluations.js
|
|
8431
|
-
var conditionKindSchema = _enum(["environment", "deployTarget", "branch"]).describe("What the condition checks on the deployment: the environment it reported into, the deploy target
|
|
8503
|
+
var conditionKindSchema = _enum(["environment", "deployTarget", "branch", "service"]).describe("What the condition checks on the deployment: the environment it reported into, the deploy target it serves, the git branch of the deployed commit, or the service it deployed.");
|
|
8432
8504
|
var conditionVerdictSchema = discriminatedUnion("outcome", [
|
|
8433
8505
|
object({
|
|
8434
8506
|
kind: conditionKindSchema,
|
|
@@ -8451,12 +8523,13 @@ var makeRunOutcomeSchema = (ids) => discriminatedUnion("status", [
|
|
|
8451
8523
|
}),
|
|
8452
8524
|
object({ status: literal("starting") }),
|
|
8453
8525
|
object({
|
|
8454
|
-
|
|
8526
|
+
message: string2().describe("Why the matched trigger created no run, in plain language."),
|
|
8527
|
+
reason: didNotRunReasonSchema,
|
|
8455
8528
|
status: literal("did-not-run"),
|
|
8456
8529
|
supersededByRunId: ids.run.optional().describe("The run that covered this deployment instead, when an earlier delivery of the same deployment had already created one.")
|
|
8457
8530
|
}),
|
|
8458
8531
|
object({ status: literal("unknown") })
|
|
8459
|
-
]).describe("What became of the match. Matching is not running: a matched trigger can still be stopped from creating a run, and did-not-run carries the reason. starting means run creation is still in progress; unknown means QA Wolf has no record of what followed the match.");
|
|
8532
|
+
]).describe("What became of the match. Matching is not running: a matched trigger can still be stopped from creating a run, and did-not-run carries the reason. starting means run creation is still in progress; unknown means QA Wolf has no record of what followed the match. did-not-run also carries a stable reason to branch on, beside the message for a person to read.");
|
|
8460
8533
|
var makeVerdictSchema = (ids) => discriminatedUnion("outcome", [
|
|
8461
8534
|
object({
|
|
8462
8535
|
conditionSets: conditionSetsField,
|
|
@@ -8505,6 +8578,7 @@ var deploymentReportMetadata = strictObject({
|
|
|
8505
8578
|
commitAuthorName: string2().trim().min(1).max(255).describe("The display name of the person who authored the deployed commit.").optional(),
|
|
8506
8579
|
commitMessage: string2().trim().min(1).max(2048).describe("The message of the deployed commit. The deployments list shows its first line.").optional(),
|
|
8507
8580
|
commitSha: string2().trim().min(1).max(255).describe("The commit sha of the deployed application revision.").optional(),
|
|
8581
|
+
commitUrl: httpUrl().max(2048).describe("A link to the deployed commit in your code host. Send this when QA Wolf cannot resolve the commit itself, for example when the QA Wolf GitHub App is not installed.").optional(),
|
|
8508
8582
|
pullRequestNumber: number2().int().positive().describe("The number of the pull request the deployment belongs to. Requires repository.").optional(),
|
|
8509
8583
|
ref: string2().trim().min(1).max(255).describe("The branch or ref that was deployed.").optional(),
|
|
8510
8584
|
repository: string2().trim().min(1).max(255).describe('The owner/name of the repository, e.g. "acme/web".').optional()
|
|
@@ -8539,6 +8613,7 @@ var makeReportDeploymentStatusContract = (ids) => {
|
|
|
8539
8613
|
environmentVariables: record(string2(), string2()).describe("Environment variable overrides for the runs this deployment requests. A report that omits this field keeps the stored values. A report that sends it replaces them.").optional(),
|
|
8540
8614
|
metadata: deploymentReportMetadata.describe("Details the deployer declares about the deployed revision; a code host integration's own record of the same commit is shown in preference to the message and author declared here.").optional(),
|
|
8541
8615
|
providerDeploymentId: string2().trim().min(1).max(255).describe('Your identifier for the deployment, e.g. "vercel_dpl_123". Reports with the same providerDeploymentId update one deployment within this workspace.'),
|
|
8616
|
+
service: string2().trim().min(1).max(255).describe('Which application was deployed, e.g. "checkout-api", when several services deploy into one environment. A report that omits it keeps the stored value.').optional(),
|
|
8542
8617
|
status: deploymentStatusSchema.describe("The deployment lifecycle status. A deployment's first success report evaluates global triggers asynchronously, and it is the only report that does. The response does not include the resulting runs."),
|
|
8543
8618
|
workspaceId: ids.workspace.describe("The workspace to report the deployment status into. A team API key must name its own workspace.")
|
|
8544
8619
|
}).superRefine((value, context) => {
|
|
@@ -9209,6 +9284,70 @@ var makeGetIssueContract = (ids) => {
|
|
|
9209
9284
|
};
|
|
9210
9285
|
};
|
|
9211
9286
|
|
|
9287
|
+
// node_modules/@qawolf/api-contracts/dist/v1/investigation/finding.js
|
|
9288
|
+
var investigationFindingStateDescription = 'What the investigation concluded about the cause. Known values: "investigating", "fixed", "fix-proposed", "reported", "report-proposed", "flake", "question" and "dismissed". New values can appear.';
|
|
9289
|
+
var makeInvestigationFindingSchema = (ids) => object({
|
|
9290
|
+
actual: string2().optional(),
|
|
9291
|
+
commitHash: string2().optional(),
|
|
9292
|
+
decidedBy: _enum(["agent", "user"]).optional().describe("Who decided: the AI on its own, or a person who approved or dismissed it. Absent until someone decides."),
|
|
9293
|
+
disputeReason: string2().optional().describe("Why a person disputed what the AI did. Present on a proposal the AI made again after that dispute."),
|
|
9294
|
+
expected: string2().optional(),
|
|
9295
|
+
findingId: string2(),
|
|
9296
|
+
flowIds: array(ids.flow),
|
|
9297
|
+
headline: string2().optional(),
|
|
9298
|
+
issueId: ids.issue.optional(),
|
|
9299
|
+
kind: string2().describe('What the failure is. Known values: "maintenance", "bug", "flake" and "unknown". New values can appear.'),
|
|
9300
|
+
matchReason: string2().optional(),
|
|
9301
|
+
priority: issuePrioritySchema.optional(),
|
|
9302
|
+
question: object({
|
|
9303
|
+
answers: array(object({
|
|
9304
|
+
description: string2().optional(),
|
|
9305
|
+
title: string2(),
|
|
9306
|
+
value: string2().describe('What choosing this answer means. Known values: "apply", "dismiss", "report", "maintenance" and "bug". New values can appear.')
|
|
9307
|
+
})),
|
|
9308
|
+
text: string2()
|
|
9309
|
+
}).optional().describe("The question waiting for a person, with the answers offered."),
|
|
9310
|
+
response: object({
|
|
9311
|
+
answer: string2().optional(),
|
|
9312
|
+
at: exports_iso.datetime(),
|
|
9313
|
+
reason: string2().optional(),
|
|
9314
|
+
type: string2().describe('Known values: "answer" and "dispute". New values can appear.')
|
|
9315
|
+
}).optional().describe("A person's answer or dispute that the investigation hasn't acted on yet."),
|
|
9316
|
+
state: string2().describe(investigationFindingStateDescription),
|
|
9317
|
+
steps: array(string2()).optional(),
|
|
9318
|
+
subSessionIds: array(ids.chatSession),
|
|
9319
|
+
summary: string2().optional(),
|
|
9320
|
+
updatedAt: exports_iso.datetime()
|
|
9321
|
+
});
|
|
9322
|
+
|
|
9323
|
+
// node_modules/@qawolf/api-contracts/dist/v1/investigation/get.js
|
|
9324
|
+
var makeGetInvestigationContract = (ids) => {
|
|
9325
|
+
const input = object({ runId: ids.run });
|
|
9326
|
+
const output = resource({
|
|
9327
|
+
findings: array(makeInvestigationFindingSchema(ids)),
|
|
9328
|
+
runId: ids.run,
|
|
9329
|
+
sessionId: ids.chatSession.optional().describe("The investigation session. Absent when the run has none."),
|
|
9330
|
+
status: _enum(["investigating", "finished", "not-investigated"]).describe('Whether the investigation session is still working. "not-investigated" when the run has no investigation.')
|
|
9331
|
+
}, { urlFieldDescription: "The run in the QA Wolf app." });
|
|
9332
|
+
return {
|
|
9333
|
+
annotations: {
|
|
9334
|
+
destructiveHint: false,
|
|
9335
|
+
openWorldHint: false,
|
|
9336
|
+
readOnlyHint: true
|
|
9337
|
+
},
|
|
9338
|
+
description: "Read what the QA Wolf AI investigating a run has concluded: one finding per cause of its failures, " + "with the question waiting for a person and any answer or dispute the investigation hasn't acted on yet.",
|
|
9339
|
+
input,
|
|
9340
|
+
kind: "read",
|
|
9341
|
+
name: "investigation.get",
|
|
9342
|
+
output
|
|
9343
|
+
};
|
|
9344
|
+
};
|
|
9345
|
+
|
|
9346
|
+
// node_modules/@qawolf/api-contracts/dist/v1/investigation/index.js
|
|
9347
|
+
var makeInvestigationContracts = (ids) => ({
|
|
9348
|
+
get: makeGetInvestigationContract(ids)
|
|
9349
|
+
});
|
|
9350
|
+
|
|
9212
9351
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/addFlows.js
|
|
9213
9352
|
var makeAddFlowsToIssueContract = (ids) => {
|
|
9214
9353
|
const input = object({
|
|
@@ -9466,6 +9605,13 @@ var makeDiagnoseRunContract = (ids) => {
|
|
|
9466
9605
|
};
|
|
9467
9606
|
|
|
9468
9607
|
// node_modules/@qawolf/api-contracts/dist/v1/run/summary.js
|
|
9608
|
+
var publicRunStatusValues = [
|
|
9609
|
+
"queued",
|
|
9610
|
+
"running",
|
|
9611
|
+
"passed",
|
|
9612
|
+
"failed",
|
|
9613
|
+
"canceled"
|
|
9614
|
+
];
|
|
9469
9615
|
var makeRunSummaryFields = (ids) => ({
|
|
9470
9616
|
completedAt: exports_iso.datetime().optional().describe("When the run finished executing. Absent while queued or running, and also absent for a terminal run that never completed execution (e.g. every flow was canceled or skipped)."),
|
|
9471
9617
|
createdAt: exports_iso.datetime(),
|
|
@@ -9476,7 +9622,7 @@ var makeRunSummaryFields = (ids) => ({
|
|
|
9476
9622
|
commitUrl: string2().optional().describe("Link to the commit on the code host.")
|
|
9477
9623
|
}).describe("The branch and commit under test. The fields are present when a deploy notification started the run, and absent for runs started another way, for example manually or with run.create."),
|
|
9478
9624
|
runId: ids.run,
|
|
9479
|
-
status: _enum(
|
|
9625
|
+
status: _enum(publicRunStatusValues).describe("Whole-run status, and the value to gate a pipeline on. Terminal statuses are passed, failed, and canceled; poll until one is reached. `failed` means the run found a bug that is still open and serious enough to block — a lower-priority bug, or one since resolved, reads `passed`, and the per-flow diagnoses are still in `flows`. The run stays `running` while any investigation is unresolved, including one that carried over to a later run, so a terminal status always means a settled answer.")
|
|
9480
9626
|
});
|
|
9481
9627
|
|
|
9482
9628
|
// node_modules/@qawolf/api-contracts/dist/v1/run/find.js
|
|
@@ -9509,7 +9655,9 @@ var makeFindRunsContract = (ids) => {
|
|
|
9509
9655
|
|
|
9510
9656
|
// node_modules/@qawolf/api-contracts/dist/v1/run/get.js
|
|
9511
9657
|
var makeGetRunContract = (ids) => {
|
|
9658
|
+
const flowStatus = _enum(publicRunStatusValues);
|
|
9512
9659
|
const input = object({
|
|
9660
|
+
flowStatuses: array(flowStatus).min(1).optional().describe("Return only the flows whose status is one of these. A suite run can " + "hold hundreds of flows, so start an investigation with failed " + "alone. A flow that passed after a retry reads passed, so add " + "passed when a flaky flow is missing from the answer. Omit to " + "return every flow. The run-level fields are unaffected."),
|
|
9513
9661
|
runId: ids.run
|
|
9514
9662
|
});
|
|
9515
9663
|
const artifactUrls = {
|
|
@@ -9566,11 +9714,12 @@ var makeGetRunContract = (ids) => {
|
|
|
9566
9714
|
attempts,
|
|
9567
9715
|
flowId: ids.flow,
|
|
9568
9716
|
name: string2(),
|
|
9569
|
-
status:
|
|
9717
|
+
status: flowStatus.exclude(["failed"])
|
|
9570
9718
|
});
|
|
9571
|
-
const flows = array(discriminatedUnion("status", [failedFlow, nonFailedFlow])).describe("The run's flows, ordered alphabetically by name.");
|
|
9719
|
+
const flows = array(discriminatedUnion("status", [failedFlow, nonFailedFlow])).describe("The run's flows, ordered alphabetically by name. Only the flows " + "matching flowStatuses when the request set it.");
|
|
9572
9720
|
const output = resource({
|
|
9573
9721
|
...makeRunSummaryFields(ids),
|
|
9722
|
+
blockingBugCount: number2().int().nonnegative().describe("How many bugs this run found are blocking: still open, and priority urgent, high, or unprioritized — unprioritized counts because nobody has ruled it out yet. This is what `failed` is derived from, so it explains a failure rather than adding a second verdict: gate on `status`, then read this to say how many bugs are holding the build. It counts a bug filed against a later run by an investigation that carried over from this one, and it drops a bug once that bug is resolved."),
|
|
9574
9723
|
flows,
|
|
9575
9724
|
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.")
|
|
9576
9725
|
}, { urlFieldDescription: "Absolute URL of the run page." });
|
|
@@ -9580,7 +9729,7 @@ var makeGetRunContract = (ids) => {
|
|
|
9580
9729
|
openWorldHint: false,
|
|
9581
9730
|
readOnlyHint: true
|
|
9582
9731
|
},
|
|
9583
|
-
description: "Get a run's status, per-flow results, and
|
|
9732
|
+
description: "Get a run's status, per-flow results, links, and how many of its bugs are blocking.",
|
|
9584
9733
|
input,
|
|
9585
9734
|
kind: "read",
|
|
9586
9735
|
name: "run.get",
|
|
@@ -9832,8 +9981,12 @@ var makeImportPackageOnRunnerContract = (ids) => {
|
|
|
9832
9981
|
var makeLaunchRunnerContract = (ids) => {
|
|
9833
9982
|
const input = object({
|
|
9834
9983
|
id: runnerIdSchema.describe("Id to launch the runner under, chosen by the caller. Launching the same id again returns the runner already running under it."),
|
|
9984
|
+
initialUrl: navigableUrlSchema.optional().describe("The page to open as the browser starts, so the first screenshot already shows the application rather than a blank page."),
|
|
9835
9985
|
runnerName: runnerNameSchema.optional().describe("The runner family to launch. Defaults to the standard web family, playwright."),
|
|
9836
9986
|
workspaceId: ids.workspace.optional().describe(`The workspace to launch the runner in. ${runnerWorkspaceRequirement}`)
|
|
9987
|
+
}).refine((request) => request.initialUrl === undefined || (request.runnerName ?? "playwright") === "playwright", {
|
|
9988
|
+
message: "initialUrl opens a page in the runner's browser, so only the playwright runner takes it.",
|
|
9989
|
+
path: ["initialUrl"]
|
|
9837
9990
|
});
|
|
9838
9991
|
const output = makeRunnerSchema().extend({
|
|
9839
9992
|
alreadyRunning: boolean2().describe("True when a runner was already running under this id and was returned unchanged, so no second runner was started and nothing new is billed. Not an error either way."),
|
|
@@ -9845,7 +9998,7 @@ var makeLaunchRunnerContract = (ids) => {
|
|
|
9845
9998
|
openWorldHint: false,
|
|
9846
9999
|
readOnlyHint: false
|
|
9847
10000
|
},
|
|
9848
|
-
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
|
|
10001
|
+
description: "Launch an interactive runner on the caller's team under an id the caller chooses. Send `initialUrl` so its browser comes up on the page the work starts from, which saves a separate navigation and the browser's cold start. 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. A success means the runner is answering: the call waits for the pod it started to come up, so the very next call to the runner reaches it. If the pod does not come up in time the call fails instead, leaving the runner running, and launching the same id again attaches to it.",
|
|
9849
10002
|
input,
|
|
9850
10003
|
kind: "write",
|
|
9851
10004
|
name: "runner.launch",
|
|
@@ -9891,7 +10044,7 @@ var makeListRunnersContract = (ids) => {
|
|
|
9891
10044
|
openWorldHint: false,
|
|
9892
10045
|
readOnlyHint: true
|
|
9893
10046
|
},
|
|
9894
|
-
description: "List the runners running on the caller's team right now. A
|
|
10047
|
+
description: "List the runners running on the caller's team right now. A listed runner may be driven by another machine or session, so sending it work can collide with theirs. 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.",
|
|
9895
10048
|
input,
|
|
9896
10049
|
kind: "read",
|
|
9897
10050
|
name: "runner.list",
|
|
@@ -9976,6 +10129,7 @@ var makeRunFlowOnRunnerContract = (ids) => {
|
|
|
9976
10129
|
env: runEnvironmentSchema.optional().describe("Environment variables to make available to the run."),
|
|
9977
10130
|
environmentId: ids.environmentRef.optional().describe("A QA Wolf environment whose variables the run is given, by id or alias. QA Wolf reads and decrypts them itself, so they never travel in the request and the count and length limits on `env` do not apply to them. Send this or `env`, not both."),
|
|
9978
10131
|
files: runFilesSchema.describe("Every file the run needs keyed by its path — the flow file, everything it imports, package.json and tsconfig.json. A runner holds no copy of your project, so what runs is exactly what is sent here."),
|
|
10132
|
+
flowId: ids.flow.optional().describe("The QA Wolf flow this run is for. The run then sees it as `QAWOLF_WORKFLOW_ID`, the same value a platform run of that flow sees, so fixtures named and cleaned up by it match across both. Omit it when the flow is not in QA Wolf yet, and the run has no `QAWOLF_WORKFLOW_ID`."),
|
|
9979
10133
|
id: runnerIdSchema.describe("Id of the runner to run the flow on."),
|
|
9980
10134
|
selection: runSelectionSchema.optional().describe("Run only these lines, inside the page the runner is already on, instead of running the whole flow from a fresh browser. Omit to run the whole entry point."),
|
|
9981
10135
|
unchangedFiles: unchangedFilesSchema.optional().describe("Files this runner already holds from an earlier run, keyed by path with a hex SHA-256 of the content it should hold. Send this to make `files` only what changed. The runner refuses with `needs-full-sync` if it holds none of a referenced path, so it never runs something other than what was asked for. Omit it to send every file."),
|
|
@@ -10227,6 +10381,7 @@ var makeContractsV1 = (ids) => {
|
|
|
10227
10381
|
removeTag: makeRemoveTagFromFlowsContract(resolvedIds),
|
|
10228
10382
|
update: makeUpdateFlowContract(resolvedIds)
|
|
10229
10383
|
},
|
|
10384
|
+
investigation: makeInvestigationContracts(resolvedIds),
|
|
10230
10385
|
issue: {
|
|
10231
10386
|
addFlows: makeAddFlowsToIssueContract(resolvedIds),
|
|
10232
10387
|
create: makeCreateIssueContract(resolvedIds),
|
|
@@ -14876,4 +15031,4 @@ export {
|
|
|
14876
15031
|
createRunnerSdk
|
|
14877
15032
|
};
|
|
14878
15033
|
|
|
14879
|
-
//# debugId=
|
|
15034
|
+
//# debugId=CF6139275CB5B8DC64756E2164756E21
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qawolf/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.35.0",
|
|
4
4
|
"description": "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"automation",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@clack/prompts": "1.5.1",
|
|
72
72
|
"@napi-rs/keyring": "1.3.0",
|
|
73
73
|
"@oxc-node/core": "0.1.0",
|
|
74
|
-
"@qawolf/api-contracts": "0.
|
|
74
|
+
"@qawolf/api-contracts": "0.70.0",
|
|
75
75
|
"@qawolf/emails": "1.1.1",
|
|
76
76
|
"@qawolf/flow-targets": "1.0.0",
|
|
77
77
|
"@qawolf/flows": "0.1.4",
|
|
@@ -76,7 +76,9 @@ sequence, omit it when you want the payloads themselves.
|
|
|
76
76
|
|
|
77
77
|
A `--json` response shows you most of its own shape, so read it first.
|
|
78
78
|
|
|
79
|
-
`qawolf run get` is the exception worth reading about before you use it.
|
|
79
|
+
`qawolf run get` is the exception worth reading about before you use it. A
|
|
80
|
+
suite run can hold hundreds of flows, so start with
|
|
81
|
+
`--flow-statuses failed` and widen only if you need the rest. Its
|
|
80
82
|
artifact URLs expire, its failure fields are absent from a passing run, and its
|
|
81
83
|
`traceUrl` downloads a Playwright trace that you can read as JSON without
|
|
82
84
|
opening the trace viewer. **Read
|
|
@@ -164,6 +166,7 @@ that `url`; never guess a route and never send a repository link in its place.
|
|
|
164
166
|
| `qawolf install android` | local | Install Android system images, AVDs, and the Appium driver used by the project's Android flows |
|
|
165
167
|
| `qawolf install browsers` | local | Install Playwright browsers used by the project's web flows |
|
|
166
168
|
| `qawolf install clear` | local | Remove the managed runtime cache (all installed runtime versions) |
|
|
169
|
+
| `qawolf investigation get` | read | Read what the QA Wolf AI investigating a run has concluded: one finding per cause of its failures, with the question waiting for a person and any answer or dispute the investigation hasn't acted on yet. |
|
|
167
170
|
| `qawolf issue addFlows` | write | 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. |
|
|
168
171
|
| `qawolf issue create` | write | Create a bug or coverage request issue for the caller's team. Maintenance issues cannot be created through the public API. |
|
|
169
172
|
| `qawolf issue find` | read | List the team's bug reports, maintenance reports, or coverage requests, newest first. |
|
|
@@ -176,7 +179,7 @@ that `url`; never guess a route and never send a repository link in its place.
|
|
|
176
179
|
| `qawolf run create` | write | Create a run for the selected flows and/or tags in an environment. |
|
|
177
180
|
| `qawolf run diagnose` | write | 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. |
|
|
178
181
|
| `qawolf run find` | read | List an environment's recent runs, newest first. |
|
|
179
|
-
| `qawolf run get` | read | Get a run's status, per-flow results, and
|
|
182
|
+
| `qawolf run get` | read | Get a run's status, per-flow results, links, and how many of its bugs are blocking. |
|
|
180
183
|
| `qawolf run reattempt` | write | 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. |
|
|
181
184
|
| `qawolf run stop` | write | 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. |
|
|
182
185
|
| `qawolf run triage` | read | Prototype. Ask Jev, a TypeSafe System One model, whether a flow failure in a run is a bug in the product or a test that needs maintenance. Compares the failing attempt with the flow's last passing run in the same environment. Records nothing. |
|
|
@@ -8,6 +8,32 @@ this file for the parts a single response cannot show you: fields that appear
|
|
|
8
8
|
only when something fails, rules about the artifact URLs, and how to read a
|
|
9
9
|
trace without opening the trace viewer.
|
|
10
10
|
|
|
11
|
+
## Start with the failed flows
|
|
12
|
+
|
|
13
|
+
A run of a whole suite can hold hundreds of flows, and the full response then
|
|
14
|
+
runs to hundreds of kilobytes: more than a shell shows you, and more than any
|
|
15
|
+
investigation needs. The interesting part is a handful of failed flows, so ask
|
|
16
|
+
for those first:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
qawolf run get --run-id "$RUN_ID" --flow-statuses failed --json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`--flow-statuses` takes one or more of `queued`, `running`, `passed`, `failed`
|
|
23
|
+
and `canceled`, separated by spaces (`--flow-statuses failed canceled`), and
|
|
24
|
+
keeps only the flows whose status matches. The run-level fields (`status`,
|
|
25
|
+
`blockingBugCount`, `git`, `url`) still describe the whole run, so a filtered
|
|
26
|
+
read tells you both how the run went and which flows to look at. Widen the
|
|
27
|
+
filter, or drop it, only when you need the other flows too.
|
|
28
|
+
|
|
29
|
+
A flow that failed and then passed on a retry has status `passed`, so a
|
|
30
|
+
`failed`-only read leaves it out. If the flow you were asked about passed on a
|
|
31
|
+
retry, add `passed` to the filter and read its earlier attempts. For a flow
|
|
32
|
+
that is still queued, running or was canceled, widen the filter or drop it.
|
|
33
|
+
|
|
34
|
+
Do not save the full response to a file and script over it to find the failed
|
|
35
|
+
flows. The filter answers that in one call.
|
|
36
|
+
|
|
11
37
|
## The shape
|
|
12
38
|
|
|
13
39
|
A run holds flows, a flow holds attempts, and artifacts hang off an attempt:
|
|
@@ -63,7 +89,7 @@ recording) and `traceUrl` (a Playwright `trace.zip`).
|
|
|
63
89
|
authentication header is needed and no QA Wolf credentials are involved.
|
|
64
90
|
|
|
65
91
|
```bash
|
|
66
|
-
qawolf run get --run-id "$RUN_ID" --json \
|
|
92
|
+
qawolf run get --run-id "$RUN_ID" --flow-statuses failed --json \
|
|
67
93
|
| jq -r '.flows[].attempts[-1].traceUrl // empty' \
|
|
68
94
|
| head -1 \
|
|
69
95
|
| xargs -r curl -sS -o trace.zip
|
|
@@ -159,7 +185,8 @@ Every documented field of the `run.get` response. `[]` marks an array, so
|
|
|
159
185
|
- `git.commitUrl` — Link to the commit on the code host.
|
|
160
186
|
- `runId` — 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.
|
|
161
187
|
- `status` — One of: queued, running, passed, failed, canceled
|
|
162
|
-
- `
|
|
188
|
+
- `blockingBugCount` — How many bugs this run found are blocking: still open, and priority urgent, high, or unprioritized — unprioritized counts because nobody has ruled it out yet. This is what `failed` is derived from, so it explains a failure rather than adding a second verdict: gate on `status`, then read this to say how many bugs are holding the build. It counts a bug filed against a later run by an investigation that carried over from this one, and it drops a bug once that bug is resolved.
|
|
189
|
+
- `flows` — The run's flows, ordered alphabetically by name. Only the flows matching flowStatuses when the request set it.
|
|
163
190
|
- `flows[].attempts` — The flow's finished execution attempts, oldest first, including manual Wolf Browser attempts. Present once at least one attempt has finished, so a flow that passed after retries also lists its failed attempts. Artifact URLs appear only on automated attempts that reached a verdict, stay valid for at least a day (call run.get again for fresh ones), and can return 404 when the attempt did not produce that artifact.
|
|
164
191
|
- `flows[].attempts[].logsUrl` — Signed URL for the attempt's execution logs.
|
|
165
192
|
- `flows[].attempts[].traceUrl` — Signed URL for the attempt's Playwright trace (a trace.zip; open it with `npx playwright show-trace`).
|