@qawolf/cli 1.23.0 → 1.24.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 +285 -63
- package/dist/runner-sdk.js +275 -70
- package/dist/types/runnerSdk/types.d.ts +6 -2
- package/package.json +2 -2
- package/skills/qawolf-cli/SKILL.md +9 -2
package/dist/cli.js
CHANGED
|
@@ -8800,7 +8800,8 @@ var lifecycleMessages = {
|
|
|
8800
8800
|
|
|
8801
8801
|
// src/core/messages/interactiveRunner/list.ts
|
|
8802
8802
|
var listMessages = {
|
|
8803
|
-
noRunners: "
|
|
8803
|
+
noRunners: "Your team has no runner running. Launch one with qawolf runner launch.",
|
|
8804
|
+
noRunnersHere: "This directory has no runner running. Launch one with qawolf runner launch, or drop --here to see the whole team's runners.",
|
|
8804
8805
|
runnerCount: (count) => count === 1 ? "1 runner" : `${String(count)} runners`,
|
|
8805
8806
|
title: "Runners"
|
|
8806
8807
|
};
|
|
@@ -13779,6 +13780,9 @@ var ZodEmail = /* @__PURE__ */ $constructor("ZodEmail", (inst, def) => {
|
|
|
13779
13780
|
$ZodEmail.init(inst, def);
|
|
13780
13781
|
ZodStringFormat.init(inst, def);
|
|
13781
13782
|
});
|
|
13783
|
+
function email2(params) {
|
|
13784
|
+
return _email(ZodEmail, params);
|
|
13785
|
+
}
|
|
13782
13786
|
var ZodGUID = /* @__PURE__ */ $constructor("ZodGUID", (inst, def) => {
|
|
13783
13787
|
$ZodGUID.init(inst, def);
|
|
13784
13788
|
ZodStringFormat.init(inst, def);
|
|
@@ -13842,6 +13846,9 @@ var ZodBase64 = /* @__PURE__ */ $constructor("ZodBase64", (inst, def) => {
|
|
|
13842
13846
|
$ZodBase64.init(inst, def);
|
|
13843
13847
|
ZodStringFormat.init(inst, def);
|
|
13844
13848
|
});
|
|
13849
|
+
function base642(params) {
|
|
13850
|
+
return _base64(ZodBase64, params);
|
|
13851
|
+
}
|
|
13845
13852
|
var ZodBase64URL = /* @__PURE__ */ $constructor("ZodBase64URL", (inst, def) => {
|
|
13846
13853
|
$ZodBase64URL.init(inst, def);
|
|
13847
13854
|
ZodStringFormat.init(inst, def);
|
|
@@ -15751,6 +15758,44 @@ var agentReplySchema = object({
|
|
|
15751
15758
|
text: string2().describe("What the AI said.")
|
|
15752
15759
|
});
|
|
15753
15760
|
|
|
15761
|
+
// node_modules/@qawolf/api-contracts/dist/v1/resource.js
|
|
15762
|
+
function resource(fields, { urlFieldDescription = "Absolute URL." } = {}) {
|
|
15763
|
+
return object({
|
|
15764
|
+
...fields,
|
|
15765
|
+
url: url().describe(urlFieldDescription)
|
|
15766
|
+
});
|
|
15767
|
+
}
|
|
15768
|
+
|
|
15769
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/resource.js
|
|
15770
|
+
var emailDirectionSchema = _enum(["inbound", "outbound"]);
|
|
15771
|
+
var namedAddressSchema = object({
|
|
15772
|
+
address: string2().describe("The email address."),
|
|
15773
|
+
name: string2().optional().describe("The display name, when the message carried one.")
|
|
15774
|
+
});
|
|
15775
|
+
var emailUrlFieldDescription = "Absolute URL of the workspace. The inbox opens from the app header.";
|
|
15776
|
+
var makeEmailSummaryFields = () => ({
|
|
15777
|
+
createdAt: exports_iso.datetime({ offset: true }).describe("When QA Wolf received or sent the email."),
|
|
15778
|
+
direction: emailDirectionSchema.describe("inbound for mail the workspace received, outbound for mail it sent."),
|
|
15779
|
+
from: namedAddressSchema,
|
|
15780
|
+
id: string2().min(1).describe("The id of the email. Pass it to email.get to read the body."),
|
|
15781
|
+
subject: string2().optional(),
|
|
15782
|
+
to: array(namedAddressSchema)
|
|
15783
|
+
});
|
|
15784
|
+
var makeEmailResourceSchema = () => resource({
|
|
15785
|
+
...makeEmailSummaryFields(),
|
|
15786
|
+
attachments: array(object({
|
|
15787
|
+
fileName: string2(),
|
|
15788
|
+
index: number2().int().min(0).describe("The position of the attachment in the email, from 0. Pass it to email.getAttachment when file names repeat."),
|
|
15789
|
+
type: string2().optional().describe("The MIME type.")
|
|
15790
|
+
})).optional().describe("Attachment names, positions, and types. Read the content with email.getAttachment."),
|
|
15791
|
+
bcc: array(namedAddressSchema).optional(),
|
|
15792
|
+
cc: array(namedAddressSchema).optional(),
|
|
15793
|
+
html: string2().optional().describe("The HTML body."),
|
|
15794
|
+
links: array(string2()).describe("The links of the email, in order: HTML anchors, then images, then bare URLs of the plain text body. Follow one to confirm a sign-up or reset a password."),
|
|
15795
|
+
replyTo: array(namedAddressSchema).optional(),
|
|
15796
|
+
text: string2().optional().describe("The plain text body.")
|
|
15797
|
+
}, { urlFieldDescription: emailUrlFieldDescription });
|
|
15798
|
+
|
|
15754
15799
|
// node_modules/@qawolf/api-contracts/dist/v1/identity/organization.js
|
|
15755
15800
|
var identityOrganization = object({
|
|
15756
15801
|
id: string2(),
|
|
@@ -15806,14 +15851,6 @@ var defaultIdSchemas = {
|
|
|
15806
15851
|
workspace: string2().min(1).describe("The id of the workspace.")
|
|
15807
15852
|
};
|
|
15808
15853
|
|
|
15809
|
-
// node_modules/@qawolf/api-contracts/dist/v1/resource.js
|
|
15810
|
-
function resource(fields, { urlFieldDescription = "Absolute URL." } = {}) {
|
|
15811
|
-
return object({
|
|
15812
|
-
...fields,
|
|
15813
|
-
url: url().describe(urlFieldDescription)
|
|
15814
|
-
});
|
|
15815
|
-
}
|
|
15816
|
-
|
|
15817
15854
|
// node_modules/@qawolf/api-contracts/dist/v1/run/flowSelection.js
|
|
15818
15855
|
var makeFlowSelectionSchema = (ids) => object({
|
|
15819
15856
|
flowIds: array(ids.flow).default([]),
|
|
@@ -16343,6 +16380,131 @@ var makeAutomateContract = (ids) => {
|
|
|
16343
16380
|
};
|
|
16344
16381
|
};
|
|
16345
16382
|
|
|
16383
|
+
// node_modules/@qawolf/api-contracts/dist/v1/pagination.js
|
|
16384
|
+
var makePaginationInputFields = (limits) => ({
|
|
16385
|
+
cursor: string2().min(1).optional().describe("Opaque cursor copied from the previous response's nextCursor. Omit to fetch the first page."),
|
|
16386
|
+
limit: number2().int().min(1).max(limits.maxLimit).default(limits.defaultLimit).describe(`Maximum rows per page. Defaults to ${limits.defaultLimit}, capped at ${limits.maxLimit}.`)
|
|
16387
|
+
});
|
|
16388
|
+
var nextCursorSchema = string2().min(1).optional().describe("Repeat the request with this value as cursor to fetch the next page. Absent when there are no further results.");
|
|
16389
|
+
|
|
16390
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/find.js
|
|
16391
|
+
var makeFindEmailsContract = (ids) => {
|
|
16392
|
+
const input = object({
|
|
16393
|
+
address: email2().optional().describe("Only emails delivered to this exact address (inbound) or sent from it (outbound). Mail to a plus-suffixed address such as inbox+abc@example.com is found by that full address, not by inbox@example.com."),
|
|
16394
|
+
createdAfter: exports_iso.datetime({ offset: true }).optional().describe("Only include emails received or sent after this instant, e.g. since a flow submitted a sign-up form."),
|
|
16395
|
+
direction: emailDirectionSchema.default("inbound").describe("inbound lists the mail the workspace received: its inbox. outbound lists the mail it sent."),
|
|
16396
|
+
workspaceId: ids.workspace.optional().describe("The workspace whose emails to list. Required when authenticating with an organization or user API key."),
|
|
16397
|
+
...makePaginationInputFields({ defaultLimit: 20, maxLimit: 50 })
|
|
16398
|
+
});
|
|
16399
|
+
const output = object({
|
|
16400
|
+
emails: array(resource(makeEmailSummaryFields(), {
|
|
16401
|
+
urlFieldDescription: emailUrlFieldDescription
|
|
16402
|
+
})).describe("The workspace's emails, newest first. Bodies are available via email.get."),
|
|
16403
|
+
nextCursor: nextCursorSchema
|
|
16404
|
+
});
|
|
16405
|
+
return {
|
|
16406
|
+
description: "List the workspace's inbox, or its sent mail, newest first. Read a message body with email.get.",
|
|
16407
|
+
input,
|
|
16408
|
+
kind: "read",
|
|
16409
|
+
name: "email.find",
|
|
16410
|
+
output
|
|
16411
|
+
};
|
|
16412
|
+
};
|
|
16413
|
+
|
|
16414
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/get.js
|
|
16415
|
+
var makeGetEmailContract = (ids) => {
|
|
16416
|
+
const input = object({
|
|
16417
|
+
id: string2().min(1).describe("The id of the email, from email.find."),
|
|
16418
|
+
workspaceId: ids.workspace.optional().describe("The workspace the email belongs to. Required when authenticating with an organization or user API key.")
|
|
16419
|
+
});
|
|
16420
|
+
const output = makeEmailResourceSchema();
|
|
16421
|
+
return {
|
|
16422
|
+
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.",
|
|
16423
|
+
input,
|
|
16424
|
+
kind: "read",
|
|
16425
|
+
name: "email.get",
|
|
16426
|
+
output
|
|
16427
|
+
};
|
|
16428
|
+
};
|
|
16429
|
+
|
|
16430
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/getAttachment.js
|
|
16431
|
+
var makeGetEmailAttachmentContract = (ids) => {
|
|
16432
|
+
const input = object({
|
|
16433
|
+
fileName: string2().min(1).optional().describe("The attachment's file name, as email.get lists it. The first attachment with that name is returned."),
|
|
16434
|
+
id: string2().min(1).describe("The id of the email, from email.find."),
|
|
16435
|
+
index: number2().int().min(0).optional().describe("The attachment's position in the email, from 0, as email.get lists it. Use it when file names repeat."),
|
|
16436
|
+
workspaceId: ids.workspace.optional().describe("The workspace the email belongs to. Required when authenticating with an organization or user API key.")
|
|
16437
|
+
}).refine((input) => input.fileName === undefined !== (input.index === undefined), { message: "Provide fileName or index, not both." });
|
|
16438
|
+
const output = resource({
|
|
16439
|
+
contentBase64: string2().describe("The file content, base64 encoded."),
|
|
16440
|
+
fileName: string2(),
|
|
16441
|
+
index: number2().int().min(0).describe("The position of the attachment in the email, from 0."),
|
|
16442
|
+
type: string2().optional().describe("The MIME type.")
|
|
16443
|
+
}, { urlFieldDescription: emailUrlFieldDescription });
|
|
16444
|
+
return {
|
|
16445
|
+
description: "Read one attachment of a workspace email as base64 content, by file name or by position. email.get lists both.",
|
|
16446
|
+
input,
|
|
16447
|
+
kind: "read",
|
|
16448
|
+
name: "email.getAttachment",
|
|
16449
|
+
output
|
|
16450
|
+
};
|
|
16451
|
+
};
|
|
16452
|
+
|
|
16453
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/listAddresses.js
|
|
16454
|
+
var makeListEmailAddressesContract = (ids) => {
|
|
16455
|
+
const input = object({
|
|
16456
|
+
workspaceId: ids.workspace.optional().describe("The workspace whose inbox addresses to list. Required when authenticating with an organization or user API key."),
|
|
16457
|
+
...makePaginationInputFields({ defaultLimit: 20, maxLimit: 50 })
|
|
16458
|
+
});
|
|
16459
|
+
const output = object({
|
|
16460
|
+
addresses: array(resource({
|
|
16461
|
+
address: string2().describe("The inbox address. Mail sent to any plus-suffixed form, such as inbox+abc@example.com, lands in the same inbox."),
|
|
16462
|
+
isDefault: boolean2().describe("Whether this is the workspace's default inbox address.")
|
|
16463
|
+
}, { urlFieldDescription: emailUrlFieldDescription })).describe("The workspace's permanent inbox addresses, alphabetical."),
|
|
16464
|
+
nextCursor: nextCursorSchema
|
|
16465
|
+
});
|
|
16466
|
+
return {
|
|
16467
|
+
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.",
|
|
16468
|
+
input,
|
|
16469
|
+
kind: "read",
|
|
16470
|
+
name: "email.listAddresses",
|
|
16471
|
+
output
|
|
16472
|
+
};
|
|
16473
|
+
};
|
|
16474
|
+
|
|
16475
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/send.js
|
|
16476
|
+
var recipientsSchema = array(email2()).max(50);
|
|
16477
|
+
var maxAttachments = 10;
|
|
16478
|
+
var maxEmailAttachmentsBase64Length = 30 * 1024 * 1024;
|
|
16479
|
+
var attachmentsBase64Length = (attachments) => Object.values(attachments).reduce((total, content) => total + content.length, 0);
|
|
16480
|
+
var makeSendEmailContract = (ids) => {
|
|
16481
|
+
const input = object({
|
|
16482
|
+
attachments: record(string2().min(1), base642()).refine((attachments) => Object.keys(attachments).length <= maxAttachments, { message: `Send at most ${maxAttachments} attachments.` }).refine((attachments) => attachmentsBase64Length(attachments) <= maxEmailAttachmentsBase64Length, { message: "Send at most 30 MB of attachments." }).optional().describe("Files to attach, as file name to base64 content, at most 30 MB in total. The MIME type comes from the file name's extension."),
|
|
16483
|
+
bcc: recipientsSchema.optional(),
|
|
16484
|
+
cc: recipientsSchema.optional(),
|
|
16485
|
+
from: email2().optional().describe("The workspace inbox address to send from, or a plus-suffixed form of one. Defaults to the workspace's default inbox address. See email.listAddresses."),
|
|
16486
|
+
html: string2().optional().describe("The HTML body."),
|
|
16487
|
+
inReplyTo: string2().min(1).optional().describe("The id of an email of the workspace to reply to, from email.find. The reply threads under that message."),
|
|
16488
|
+
replyTo: recipientsSchema.optional().describe("Where replies should go instead of the from address."),
|
|
16489
|
+
subject: string2().min(1),
|
|
16490
|
+
text: string2().optional().describe("The plain text body."),
|
|
16491
|
+
to: recipientsSchema.min(1),
|
|
16492
|
+
workspaceId: ids.workspace.optional().describe("The workspace to send from. Required when authenticating with an organization or user API key.")
|
|
16493
|
+
}).refine((email) => email.html || email.text, {
|
|
16494
|
+
message: "Provide text, html, or both."
|
|
16495
|
+
});
|
|
16496
|
+
const output = resource(makeEmailSummaryFields(), {
|
|
16497
|
+
urlFieldDescription: emailUrlFieldDescription
|
|
16498
|
+
});
|
|
16499
|
+
return {
|
|
16500
|
+
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.",
|
|
16501
|
+
input,
|
|
16502
|
+
kind: "write",
|
|
16503
|
+
name: "email.send",
|
|
16504
|
+
output
|
|
16505
|
+
};
|
|
16506
|
+
};
|
|
16507
|
+
|
|
16346
16508
|
// node_modules/@qawolf/api-contracts/dist/v1/environment/deleteVariable.js
|
|
16347
16509
|
var makeDeleteEnvironmentVariableContract = (ids) => {
|
|
16348
16510
|
const input = object({
|
|
@@ -16361,13 +16523,6 @@ var makeDeleteEnvironmentVariableContract = (ids) => {
|
|
|
16361
16523
|
};
|
|
16362
16524
|
};
|
|
16363
16525
|
|
|
16364
|
-
// node_modules/@qawolf/api-contracts/dist/v1/pagination.js
|
|
16365
|
-
var makePaginationInputFields = (limits) => ({
|
|
16366
|
-
cursor: string2().min(1).optional().describe("Opaque cursor copied from the previous response's nextCursor. Omit to fetch the first page."),
|
|
16367
|
-
limit: number2().int().min(1).max(limits.maxLimit).default(limits.defaultLimit).describe(`Maximum rows per page. Defaults to ${limits.defaultLimit}, capped at ${limits.maxLimit}.`)
|
|
16368
|
-
});
|
|
16369
|
-
var nextCursorSchema = string2().min(1).optional().describe("Repeat the request with this value as cursor to fetch the next page. Absent when there are no further results.");
|
|
16370
|
-
|
|
16371
16526
|
// node_modules/@qawolf/api-contracts/dist/v1/environment/resource.js
|
|
16372
16527
|
var makeEnvironmentResourceSchema = (ids) => resource({
|
|
16373
16528
|
alias: string2().optional().describe("The environment's alias: a team-unique slug that team API keys can use in place of the id. Terminated environments have none."),
|
|
@@ -16539,15 +16694,27 @@ var makeCreateTagContract = (ids) => {
|
|
|
16539
16694
|
};
|
|
16540
16695
|
};
|
|
16541
16696
|
|
|
16697
|
+
// node_modules/@qawolf/api-contracts/dist/v1/flow/skippedFlows.js
|
|
16698
|
+
var makeSkippedFlowsSchema = (ids, { description, reason }) => array(object({
|
|
16699
|
+
flowId: ids.flow,
|
|
16700
|
+
name: string2().describe("The name of the flow."),
|
|
16701
|
+
reason
|
|
16702
|
+
})).describe(description);
|
|
16703
|
+
|
|
16542
16704
|
// node_modules/@qawolf/api-contracts/dist/v1/flow/addTag.js
|
|
16543
16705
|
var makeAddTagToFlowsContract = (ids) => {
|
|
16544
16706
|
const input = object({
|
|
16545
16707
|
flowIds: array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The flows that receive the tag."),
|
|
16546
16708
|
tagName: string2().trim().min(1).describe("The name of an existing tag on the caller's team.")
|
|
16547
16709
|
});
|
|
16548
|
-
const output = makeTagResourceSchema()
|
|
16710
|
+
const output = makeTagResourceSchema().extend({
|
|
16711
|
+
skippedFlows: makeSkippedFlowsSchema(ids, {
|
|
16712
|
+
description: "Requested flows that already carried the tag, so nothing changed for them.",
|
|
16713
|
+
reason: _enum(["already-tagged"]).describe('Why the flow was skipped: "already-tagged" means the flow already carried the tag.')
|
|
16714
|
+
})
|
|
16715
|
+
});
|
|
16549
16716
|
return {
|
|
16550
|
-
description: "Assign an existing tag to the selected flows. Create tags with tag.create.",
|
|
16717
|
+
description: "Assign an existing tag to the selected flows. Create tags with tag.create. Flows that already carry the tag are reported in skippedFlows.",
|
|
16551
16718
|
input,
|
|
16552
16719
|
kind: "write",
|
|
16553
16720
|
name: "flow.addTag",
|
|
@@ -16587,6 +16754,27 @@ var makeListFlowsContract = (ids) => {
|
|
|
16587
16754
|
};
|
|
16588
16755
|
};
|
|
16589
16756
|
|
|
16757
|
+
// node_modules/@qawolf/api-contracts/dist/v1/flow/removeTag.js
|
|
16758
|
+
var makeRemoveTagFromFlowsContract = (ids) => {
|
|
16759
|
+
const input = object({
|
|
16760
|
+
flowIds: array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The flows that lose the tag."),
|
|
16761
|
+
tagName: string2().trim().min(1).describe("The name of an existing tag on the caller's team.")
|
|
16762
|
+
});
|
|
16763
|
+
const output = makeTagResourceSchema().extend({
|
|
16764
|
+
skippedFlows: makeSkippedFlowsSchema(ids, {
|
|
16765
|
+
description: "Requested flows that did not carry the tag, so nothing changed for them.",
|
|
16766
|
+
reason: _enum(["not-tagged"]).describe('Why the flow was skipped: "not-tagged" means the flow did not carry the tag.')
|
|
16767
|
+
})
|
|
16768
|
+
});
|
|
16769
|
+
return {
|
|
16770
|
+
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.",
|
|
16771
|
+
input,
|
|
16772
|
+
kind: "write",
|
|
16773
|
+
name: "flow.removeTag",
|
|
16774
|
+
output
|
|
16775
|
+
};
|
|
16776
|
+
};
|
|
16777
|
+
|
|
16590
16778
|
// node_modules/@qawolf/api-contracts/dist/v1/flow/update.js
|
|
16591
16779
|
var makeUpdateFlowContract = (ids) => {
|
|
16592
16780
|
const input = object({
|
|
@@ -16731,6 +16919,24 @@ var makeCreateIssueContract = (ids) => {
|
|
|
16731
16919
|
};
|
|
16732
16920
|
};
|
|
16733
16921
|
|
|
16922
|
+
// node_modules/@qawolf/api-contracts/dist/v1/issue/removeFlows.js
|
|
16923
|
+
var makeRemoveFlowsFromIssueContract = (ids) => {
|
|
16924
|
+
const input = object({
|
|
16925
|
+
flowIds: array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The flows the coverage request no longer covers."),
|
|
16926
|
+
issueId: ids.issue
|
|
16927
|
+
});
|
|
16928
|
+
const output = object({
|
|
16929
|
+
issue: makeIssueResourceSchema(ids)
|
|
16930
|
+
});
|
|
16931
|
+
return {
|
|
16932
|
+
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.",
|
|
16933
|
+
input,
|
|
16934
|
+
kind: "write",
|
|
16935
|
+
name: "issue.removeFlows",
|
|
16936
|
+
output
|
|
16937
|
+
};
|
|
16938
|
+
};
|
|
16939
|
+
|
|
16734
16940
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/update.js
|
|
16735
16941
|
var makeUpdateIssueContract = (ids) => {
|
|
16736
16942
|
const descriptionSchema = string2().describe("The issue description as plain text; each line becomes a paragraph. Markdown is not parsed.");
|
|
@@ -17057,6 +17263,22 @@ var makeTerminateRunnerContract = () => {
|
|
|
17057
17263
|
};
|
|
17058
17264
|
};
|
|
17059
17265
|
|
|
17266
|
+
// node_modules/@qawolf/api-contracts/dist/v1/runner/list.js
|
|
17267
|
+
var makeListRunnersContract = () => {
|
|
17268
|
+
const input = object({});
|
|
17269
|
+
const output = object({
|
|
17270
|
+
outcome: literal("success"),
|
|
17271
|
+
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.")
|
|
17272
|
+
});
|
|
17273
|
+
return {
|
|
17274
|
+
description: "List the runners running on the caller's team right now. Takes no arguments: the API key already names the team. 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.",
|
|
17275
|
+
input,
|
|
17276
|
+
kind: "read",
|
|
17277
|
+
name: "runner.list",
|
|
17278
|
+
output
|
|
17279
|
+
};
|
|
17280
|
+
};
|
|
17281
|
+
|
|
17060
17282
|
// node_modules/@qawolf/api-contracts/dist/v1/runner/promoteSnapshot.js
|
|
17061
17283
|
var maxSnapshotPathLength = 1024;
|
|
17062
17284
|
var makePromoteSnapshotOnRunnerContract = () => {
|
|
@@ -17252,6 +17474,13 @@ var makeContractsV1 = (ids) => {
|
|
|
17252
17474
|
send: makeAgentSendContract(resolvedIds)
|
|
17253
17475
|
},
|
|
17254
17476
|
automate: makeAutomateContract(resolvedIds),
|
|
17477
|
+
email: {
|
|
17478
|
+
find: makeFindEmailsContract(resolvedIds),
|
|
17479
|
+
get: makeGetEmailContract(resolvedIds),
|
|
17480
|
+
getAttachment: makeGetEmailAttachmentContract(resolvedIds),
|
|
17481
|
+
listAddresses: makeListEmailAddressesContract(resolvedIds),
|
|
17482
|
+
send: makeSendEmailContract(resolvedIds)
|
|
17483
|
+
},
|
|
17255
17484
|
environment: {
|
|
17256
17485
|
create: makeCreateEnvironmentContract(resolvedIds),
|
|
17257
17486
|
deleteVariable: makeDeleteEnvironmentVariableContract(resolvedIds),
|
|
@@ -17265,6 +17494,7 @@ var makeContractsV1 = (ids) => {
|
|
|
17265
17494
|
flow: {
|
|
17266
17495
|
addTag: makeAddTagToFlowsContract(resolvedIds),
|
|
17267
17496
|
list: makeListFlowsContract(resolvedIds),
|
|
17497
|
+
removeTag: makeRemoveTagFromFlowsContract(resolvedIds),
|
|
17268
17498
|
update: makeUpdateFlowContract(resolvedIds)
|
|
17269
17499
|
},
|
|
17270
17500
|
issue: {
|
|
@@ -17272,6 +17502,7 @@ var makeContractsV1 = (ids) => {
|
|
|
17272
17502
|
create: makeCreateIssueContract(resolvedIds),
|
|
17273
17503
|
find: makeFindIssuesContract(resolvedIds),
|
|
17274
17504
|
get: makeGetIssueContract(resolvedIds),
|
|
17505
|
+
removeFlows: makeRemoveFlowsFromIssueContract(resolvedIds),
|
|
17275
17506
|
update: makeUpdateIssueContract(resolvedIds)
|
|
17276
17507
|
},
|
|
17277
17508
|
run: {
|
|
@@ -17289,6 +17520,7 @@ var makeContractsV1 = (ids) => {
|
|
|
17289
17520
|
inspect: makeInspectOnRunnerContract(),
|
|
17290
17521
|
inspectMobile: makeInspectMobileOnRunnerContract(),
|
|
17291
17522
|
launch: makeLaunchRunnerContract(),
|
|
17523
|
+
list: makeListRunnersContract(),
|
|
17292
17524
|
performAction: makePerformActionOnRunnerContract(),
|
|
17293
17525
|
promoteSnapshot: makePromoteSnapshotOnRunnerContract(),
|
|
17294
17526
|
readJournal: makeReadRunnerJournalContract(),
|
|
@@ -19367,7 +19599,7 @@ function startUpdateCheck(deps) {
|
|
|
19367
19599
|
// package.json
|
|
19368
19600
|
var package_default = {
|
|
19369
19601
|
name: "@qawolf/cli",
|
|
19370
|
-
version: "1.
|
|
19602
|
+
version: "1.24.0",
|
|
19371
19603
|
description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
|
|
19372
19604
|
keywords: [
|
|
19373
19605
|
"automation",
|
|
@@ -19438,7 +19670,7 @@ var package_default = {
|
|
|
19438
19670
|
"@clack/prompts": "1.5.1",
|
|
19439
19671
|
"@napi-rs/keyring": "1.3.0",
|
|
19440
19672
|
"@oxc-node/core": "0.1.0",
|
|
19441
|
-
"@qawolf/api-contracts": "0.
|
|
19673
|
+
"@qawolf/api-contracts": "0.47.0",
|
|
19442
19674
|
"@qawolf/emails": "1.1.1",
|
|
19443
19675
|
"@qawolf/flow-targets": "1.0.0",
|
|
19444
19676
|
"@qawolf/flows": "0.1.4",
|
|
@@ -30548,6 +30780,7 @@ var skippedContractNames = new Set([
|
|
|
30548
30780
|
"runner.inspect",
|
|
30549
30781
|
"runner.inspectMobile",
|
|
30550
30782
|
"runner.launch",
|
|
30783
|
+
"runner.list",
|
|
30551
30784
|
"runner.performAction",
|
|
30552
30785
|
"runner.promoteSnapshot",
|
|
30553
30786
|
"runner.readJournal",
|
|
@@ -32052,68 +32285,56 @@ async function handleRunnerLaunch(ctx, options, deps) {
|
|
|
32052
32285
|
// src/domains/interactiveRunner/list.ts
|
|
32053
32286
|
var columns = [
|
|
32054
32287
|
{ header: "id", value: (row) => row.id },
|
|
32055
|
-
{ header: "family", value: (row) => row.runnerName
|
|
32288
|
+
{ header: "family", value: (row) => row.runnerName },
|
|
32289
|
+
{ header: "launched here", value: (row) => row.launchedHere ? "yes" : "" },
|
|
32056
32290
|
{ header: "default", value: (row) => row.isDefault ? "yes" : "" }
|
|
32057
32291
|
];
|
|
32058
|
-
|
|
32059
|
-
|
|
32060
|
-
|
|
32061
|
-
|
|
32062
|
-
const environmentValue = deps.env[runnerIdEnvironmentVariable]?.trim();
|
|
32063
|
-
const fromEnvironment = environmentValue ? environmentValue : undefined;
|
|
32064
|
-
const candidates = [...held];
|
|
32065
|
-
for (const id of [storedDefault, fromEnvironment]) {
|
|
32066
|
-
if (id !== undefined && !candidates.some((runner) => runner.id === id)) {
|
|
32067
|
-
candidates.push({ id });
|
|
32068
|
-
}
|
|
32069
|
-
}
|
|
32070
|
-
return { candidates, defaultRunnerId: fromEnvironment ?? storedDefault };
|
|
32292
|
+
function rank(item) {
|
|
32293
|
+
if (item.isDefault)
|
|
32294
|
+
return 0;
|
|
32295
|
+
return item.launchedHere ? 1 : 2;
|
|
32071
32296
|
}
|
|
32072
|
-
async function
|
|
32073
|
-
const
|
|
32074
|
-
if (
|
|
32075
|
-
return
|
|
32076
|
-
return
|
|
32297
|
+
async function readDefaultRunnerId(deps) {
|
|
32298
|
+
const environmentValue = deps.env[runnerIdEnvironmentVariable]?.trim();
|
|
32299
|
+
if (environmentValue)
|
|
32300
|
+
return environmentValue;
|
|
32301
|
+
return deps.store.readDefaultRunnerId();
|
|
32077
32302
|
}
|
|
32078
32303
|
async function listRunners(ctx, deps) {
|
|
32079
|
-
const
|
|
32080
|
-
|
|
32081
|
-
|
|
32082
|
-
|
|
32083
|
-
|
|
32084
|
-
|
|
32085
|
-
|
|
32086
|
-
running.push(probe.runner);
|
|
32087
|
-
else
|
|
32088
|
-
gone.push(probe.runner.id);
|
|
32089
|
-
}
|
|
32304
|
+
const listed = await ctx.platformClient.callPublicApi(publicContractsV1.runner.list, {}, runnerCallOptions);
|
|
32305
|
+
if (!listed.ok)
|
|
32306
|
+
return { ...failureFields(listed), ok: false };
|
|
32307
|
+
const defaultRunnerId = await readDefaultRunnerId(deps);
|
|
32308
|
+
const runningIds = new Set(listed.value.runners.map((runner) => runner.id));
|
|
32309
|
+
const held = await deps.store.readRunners();
|
|
32310
|
+
const gone = held.filter((runner) => !runningIds.has(runner.id)).map((runner) => runner.id);
|
|
32090
32311
|
await deps.store.dropRunners(gone).catch(() => {
|
|
32091
32312
|
return;
|
|
32092
32313
|
});
|
|
32314
|
+
const heldIds = new Set(held.map((runner) => runner.id));
|
|
32315
|
+
const items = listed.value.runners.map((runner) => ({
|
|
32316
|
+
id: runner.id,
|
|
32317
|
+
isDefault: runner.id === defaultRunnerId,
|
|
32318
|
+
launchedHere: heldIds.has(runner.id),
|
|
32319
|
+
runnerName: runner.runnerName
|
|
32320
|
+
}));
|
|
32093
32321
|
return {
|
|
32094
|
-
items:
|
|
32095
|
-
...running.filter((runner) => runner.id === defaultRunnerId),
|
|
32096
|
-
...running.filter((runner) => runner.id !== defaultRunnerId)
|
|
32097
|
-
].map((runner) => ({
|
|
32098
|
-
id: runner.id,
|
|
32099
|
-
isDefault: runner.id === defaultRunnerId,
|
|
32100
|
-
runnerName: runner.runnerName
|
|
32101
|
-
})),
|
|
32322
|
+
items: items.sort((left, right) => rank(left) - rank(right) || left.id.localeCompare(right.id)),
|
|
32102
32323
|
ok: true
|
|
32103
32324
|
};
|
|
32104
32325
|
}
|
|
32105
|
-
async function handleRunnerList(ctx, deps) {
|
|
32326
|
+
async function handleRunnerList(ctx, options, deps) {
|
|
32106
32327
|
const listed = await listRunners(ctx, deps);
|
|
32107
32328
|
if (!listed.ok) {
|
|
32108
32329
|
return { ...failureFields(listed), exitCode: exitCodes.network };
|
|
32109
32330
|
}
|
|
32110
|
-
const items = listed.items;
|
|
32331
|
+
const items = options.here ? listed.items.filter((item) => item.launchedHere) : listed.items;
|
|
32111
32332
|
if (ctx.ui.mode === "json") {
|
|
32112
32333
|
ctx.ui.json(items);
|
|
32113
32334
|
return;
|
|
32114
32335
|
}
|
|
32115
32336
|
if (items.length === 0) {
|
|
32116
|
-
ctx.ui.info(interactiveRunnerMessages.noRunners);
|
|
32337
|
+
ctx.ui.info(options.here ? interactiveRunnerMessages.noRunnersHere : interactiveRunnerMessages.noRunners);
|
|
32117
32338
|
return;
|
|
32118
32339
|
}
|
|
32119
32340
|
if (ctx.ui.mode === "agent") {
|
|
@@ -32175,6 +32396,7 @@ Examples:
|
|
|
32175
32396
|
var listExamples2 = `
|
|
32176
32397
|
Examples:
|
|
32177
32398
|
$ qawolf runner list
|
|
32399
|
+
$ qawolf runner list --here
|
|
32178
32400
|
$ qawolf runner list --json`;
|
|
32179
32401
|
var keepaliveExamples = `
|
|
32180
32402
|
Examples:
|
|
@@ -32182,7 +32404,7 @@ Examples:
|
|
|
32182
32404
|
$ qawolf runner keepalive --runner ci`;
|
|
32183
32405
|
function registerRunnerLifecycleCommands(runner, signals) {
|
|
32184
32406
|
declareCommandKind(runner.command("launch"), "write").description("Launch an interactive runner and make it this directory's default").option("--id <id>", "Id to launch under. Relaunching an id attaches to that runner").option("--name <family>", "Runner family to run, e.g. playwright").addHelpText("after", launchExamples).action((opts, command) => withAuthContext(signals, (ctx) => handleRunnerLaunch(ctx, { id: opts.id, name: opts.name }, runnerDeps(ctx)))(opts, command));
|
|
32185
|
-
declareCommandKind(runner.command("list"), "read").description("List the runners
|
|
32407
|
+
declareCommandKind(runner.command("list"), "read").description("List the runners running on your team").option("--here", "Only the runners this directory launched").addHelpText("after", listExamples2).action((opts, command) => withAuthContext(signals, (ctx) => handleRunnerList(ctx, { here: opts.here === true }, runnerDeps(ctx)))(opts, command));
|
|
32186
32408
|
declareCommandKind(runner.command("terminate"), "write").description("End an interactive runner, and the pod it runs on with it").option("--runner <id>", runnerFlagDescription).action((opts, command) => withAuthContext(signals, (ctx) => handleRunnerTerminate(ctx, { runner: opts.runner }, runnerDeps(ctx)))(opts, command));
|
|
32187
32409
|
declareCommandKind(runner.command("stop-run"), "write").description("Stop what a runner is currently executing, leaving the runner up").option("--runner <id>", runnerFlagDescription).action((opts, command) => withAuthContext(signals, (ctx) => handleRunnerStopRun(ctx, { runner: opts.runner }, runnerDeps(ctx)))(opts, command));
|
|
32188
32410
|
declareCommandKind(runner.command("keepalive"), "read").description("Reset a runner's inactivity clock, for a caller that pauses between actions").option("--runner <id>", runnerFlagDescription).addHelpText("after", keepaliveExamples).action((opts, command) => withAuthContext(signals, (ctx) => handleRunnerKeepalive(ctx, { runner: opts.runner }, runnerDeps(ctx)))(opts, command));
|
|
@@ -32983,4 +33205,4 @@ createProgram({ signals }).parseAsync().catch(() => {
|
|
|
32983
33205
|
process.exitCode = 1;
|
|
32984
33206
|
}).finally(() => flushAndExit(typeof process.exitCode === "number" ? process.exitCode : 0));
|
|
32985
33207
|
|
|
32986
|
-
//# debugId=
|
|
33208
|
+
//# debugId=599EFC31E23F426D64756E2164756E21
|
package/dist/runner-sdk.js
CHANGED
|
@@ -6102,6 +6102,9 @@ var ZodEmail = /* @__PURE__ */ $constructor("ZodEmail", (inst, def) => {
|
|
|
6102
6102
|
$ZodEmail.init(inst, def);
|
|
6103
6103
|
ZodStringFormat.init(inst, def);
|
|
6104
6104
|
});
|
|
6105
|
+
function email2(params) {
|
|
6106
|
+
return _email(ZodEmail, params);
|
|
6107
|
+
}
|
|
6105
6108
|
var ZodGUID = /* @__PURE__ */ $constructor("ZodGUID", (inst, def) => {
|
|
6106
6109
|
$ZodGUID.init(inst, def);
|
|
6107
6110
|
ZodStringFormat.init(inst, def);
|
|
@@ -6165,6 +6168,9 @@ var ZodBase64 = /* @__PURE__ */ $constructor("ZodBase64", (inst, def) => {
|
|
|
6165
6168
|
$ZodBase64.init(inst, def);
|
|
6166
6169
|
ZodStringFormat.init(inst, def);
|
|
6167
6170
|
});
|
|
6171
|
+
function base642(params) {
|
|
6172
|
+
return _base64(ZodBase64, params);
|
|
6173
|
+
}
|
|
6168
6174
|
var ZodBase64URL = /* @__PURE__ */ $constructor("ZodBase64URL", (inst, def) => {
|
|
6169
6175
|
$ZodBase64URL.init(inst, def);
|
|
6170
6176
|
ZodStringFormat.init(inst, def);
|
|
@@ -6747,6 +6753,44 @@ var agentReplySchema = object({
|
|
|
6747
6753
|
text: string2().describe("What the AI said.")
|
|
6748
6754
|
});
|
|
6749
6755
|
|
|
6756
|
+
// node_modules/@qawolf/api-contracts/dist/v1/resource.js
|
|
6757
|
+
function resource(fields, { urlFieldDescription = "Absolute URL." } = {}) {
|
|
6758
|
+
return object({
|
|
6759
|
+
...fields,
|
|
6760
|
+
url: url().describe(urlFieldDescription)
|
|
6761
|
+
});
|
|
6762
|
+
}
|
|
6763
|
+
|
|
6764
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/resource.js
|
|
6765
|
+
var emailDirectionSchema = _enum(["inbound", "outbound"]);
|
|
6766
|
+
var namedAddressSchema = object({
|
|
6767
|
+
address: string2().describe("The email address."),
|
|
6768
|
+
name: string2().optional().describe("The display name, when the message carried one.")
|
|
6769
|
+
});
|
|
6770
|
+
var emailUrlFieldDescription = "Absolute URL of the workspace. The inbox opens from the app header.";
|
|
6771
|
+
var makeEmailSummaryFields = () => ({
|
|
6772
|
+
createdAt: exports_iso.datetime({ offset: true }).describe("When QA Wolf received or sent the email."),
|
|
6773
|
+
direction: emailDirectionSchema.describe("inbound for mail the workspace received, outbound for mail it sent."),
|
|
6774
|
+
from: namedAddressSchema,
|
|
6775
|
+
id: string2().min(1).describe("The id of the email. Pass it to email.get to read the body."),
|
|
6776
|
+
subject: string2().optional(),
|
|
6777
|
+
to: array(namedAddressSchema)
|
|
6778
|
+
});
|
|
6779
|
+
var makeEmailResourceSchema = () => resource({
|
|
6780
|
+
...makeEmailSummaryFields(),
|
|
6781
|
+
attachments: array(object({
|
|
6782
|
+
fileName: string2(),
|
|
6783
|
+
index: number2().int().min(0).describe("The position of the attachment in the email, from 0. Pass it to email.getAttachment when file names repeat."),
|
|
6784
|
+
type: string2().optional().describe("The MIME type.")
|
|
6785
|
+
})).optional().describe("Attachment names, positions, and types. Read the content with email.getAttachment."),
|
|
6786
|
+
bcc: array(namedAddressSchema).optional(),
|
|
6787
|
+
cc: array(namedAddressSchema).optional(),
|
|
6788
|
+
html: string2().optional().describe("The HTML body."),
|
|
6789
|
+
links: array(string2()).describe("The links of the email, in order: HTML anchors, then images, then bare URLs of the plain text body. Follow one to confirm a sign-up or reset a password."),
|
|
6790
|
+
replyTo: array(namedAddressSchema).optional(),
|
|
6791
|
+
text: string2().optional().describe("The plain text body.")
|
|
6792
|
+
}, { urlFieldDescription: emailUrlFieldDescription });
|
|
6793
|
+
|
|
6750
6794
|
// node_modules/@qawolf/api-contracts/dist/v1/identity/organization.js
|
|
6751
6795
|
var identityOrganization = object({
|
|
6752
6796
|
id: string2(),
|
|
@@ -6802,14 +6846,6 @@ var defaultIdSchemas = {
|
|
|
6802
6846
|
workspace: string2().min(1).describe("The id of the workspace.")
|
|
6803
6847
|
};
|
|
6804
6848
|
|
|
6805
|
-
// node_modules/@qawolf/api-contracts/dist/v1/resource.js
|
|
6806
|
-
function resource(fields, { urlFieldDescription = "Absolute URL." } = {}) {
|
|
6807
|
-
return object({
|
|
6808
|
-
...fields,
|
|
6809
|
-
url: url().describe(urlFieldDescription)
|
|
6810
|
-
});
|
|
6811
|
-
}
|
|
6812
|
-
|
|
6813
6849
|
// node_modules/@qawolf/api-contracts/dist/v1/run/flowSelection.js
|
|
6814
6850
|
var makeFlowSelectionSchema = (ids) => object({
|
|
6815
6851
|
flowIds: array(ids.flow).default([]),
|
|
@@ -7344,6 +7380,131 @@ var makeAutomateContract = (ids) => {
|
|
|
7344
7380
|
};
|
|
7345
7381
|
};
|
|
7346
7382
|
|
|
7383
|
+
// node_modules/@qawolf/api-contracts/dist/v1/pagination.js
|
|
7384
|
+
var makePaginationInputFields = (limits) => ({
|
|
7385
|
+
cursor: string2().min(1).optional().describe("Opaque cursor copied from the previous response's nextCursor. Omit to fetch the first page."),
|
|
7386
|
+
limit: number2().int().min(1).max(limits.maxLimit).default(limits.defaultLimit).describe(`Maximum rows per page. Defaults to ${limits.defaultLimit}, capped at ${limits.maxLimit}.`)
|
|
7387
|
+
});
|
|
7388
|
+
var nextCursorSchema = string2().min(1).optional().describe("Repeat the request with this value as cursor to fetch the next page. Absent when there are no further results.");
|
|
7389
|
+
|
|
7390
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/find.js
|
|
7391
|
+
var makeFindEmailsContract = (ids) => {
|
|
7392
|
+
const input = object({
|
|
7393
|
+
address: email2().optional().describe("Only emails delivered to this exact address (inbound) or sent from it (outbound). Mail to a plus-suffixed address such as inbox+abc@example.com is found by that full address, not by inbox@example.com."),
|
|
7394
|
+
createdAfter: exports_iso.datetime({ offset: true }).optional().describe("Only include emails received or sent after this instant, e.g. since a flow submitted a sign-up form."),
|
|
7395
|
+
direction: emailDirectionSchema.default("inbound").describe("inbound lists the mail the workspace received: its inbox. outbound lists the mail it sent."),
|
|
7396
|
+
workspaceId: ids.workspace.optional().describe("The workspace whose emails to list. Required when authenticating with an organization or user API key."),
|
|
7397
|
+
...makePaginationInputFields({ defaultLimit: 20, maxLimit: 50 })
|
|
7398
|
+
});
|
|
7399
|
+
const output = object({
|
|
7400
|
+
emails: array(resource(makeEmailSummaryFields(), {
|
|
7401
|
+
urlFieldDescription: emailUrlFieldDescription
|
|
7402
|
+
})).describe("The workspace's emails, newest first. Bodies are available via email.get."),
|
|
7403
|
+
nextCursor: nextCursorSchema
|
|
7404
|
+
});
|
|
7405
|
+
return {
|
|
7406
|
+
description: "List the workspace's inbox, or its sent mail, newest first. Read a message body with email.get.",
|
|
7407
|
+
input,
|
|
7408
|
+
kind: "read",
|
|
7409
|
+
name: "email.find",
|
|
7410
|
+
output
|
|
7411
|
+
};
|
|
7412
|
+
};
|
|
7413
|
+
|
|
7414
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/get.js
|
|
7415
|
+
var makeGetEmailContract = (ids) => {
|
|
7416
|
+
const input = object({
|
|
7417
|
+
id: string2().min(1).describe("The id of the email, from email.find."),
|
|
7418
|
+
workspaceId: ids.workspace.optional().describe("The workspace the email belongs to. Required when authenticating with an organization or user API key.")
|
|
7419
|
+
});
|
|
7420
|
+
const output = makeEmailResourceSchema();
|
|
7421
|
+
return {
|
|
7422
|
+
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.",
|
|
7423
|
+
input,
|
|
7424
|
+
kind: "read",
|
|
7425
|
+
name: "email.get",
|
|
7426
|
+
output
|
|
7427
|
+
};
|
|
7428
|
+
};
|
|
7429
|
+
|
|
7430
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/getAttachment.js
|
|
7431
|
+
var makeGetEmailAttachmentContract = (ids) => {
|
|
7432
|
+
const input = object({
|
|
7433
|
+
fileName: string2().min(1).optional().describe("The attachment's file name, as email.get lists it. The first attachment with that name is returned."),
|
|
7434
|
+
id: string2().min(1).describe("The id of the email, from email.find."),
|
|
7435
|
+
index: number2().int().min(0).optional().describe("The attachment's position in the email, from 0, as email.get lists it. Use it when file names repeat."),
|
|
7436
|
+
workspaceId: ids.workspace.optional().describe("The workspace the email belongs to. Required when authenticating with an organization or user API key.")
|
|
7437
|
+
}).refine((input) => input.fileName === undefined !== (input.index === undefined), { message: "Provide fileName or index, not both." });
|
|
7438
|
+
const output = resource({
|
|
7439
|
+
contentBase64: string2().describe("The file content, base64 encoded."),
|
|
7440
|
+
fileName: string2(),
|
|
7441
|
+
index: number2().int().min(0).describe("The position of the attachment in the email, from 0."),
|
|
7442
|
+
type: string2().optional().describe("The MIME type.")
|
|
7443
|
+
}, { urlFieldDescription: emailUrlFieldDescription });
|
|
7444
|
+
return {
|
|
7445
|
+
description: "Read one attachment of a workspace email as base64 content, by file name or by position. email.get lists both.",
|
|
7446
|
+
input,
|
|
7447
|
+
kind: "read",
|
|
7448
|
+
name: "email.getAttachment",
|
|
7449
|
+
output
|
|
7450
|
+
};
|
|
7451
|
+
};
|
|
7452
|
+
|
|
7453
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/listAddresses.js
|
|
7454
|
+
var makeListEmailAddressesContract = (ids) => {
|
|
7455
|
+
const input = object({
|
|
7456
|
+
workspaceId: ids.workspace.optional().describe("The workspace whose inbox addresses to list. Required when authenticating with an organization or user API key."),
|
|
7457
|
+
...makePaginationInputFields({ defaultLimit: 20, maxLimit: 50 })
|
|
7458
|
+
});
|
|
7459
|
+
const output = object({
|
|
7460
|
+
addresses: array(resource({
|
|
7461
|
+
address: string2().describe("The inbox address. Mail sent to any plus-suffixed form, such as inbox+abc@example.com, lands in the same inbox."),
|
|
7462
|
+
isDefault: boolean2().describe("Whether this is the workspace's default inbox address.")
|
|
7463
|
+
}, { urlFieldDescription: emailUrlFieldDescription })).describe("The workspace's permanent inbox addresses, alphabetical."),
|
|
7464
|
+
nextCursor: nextCursorSchema
|
|
7465
|
+
});
|
|
7466
|
+
return {
|
|
7467
|
+
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.",
|
|
7468
|
+
input,
|
|
7469
|
+
kind: "read",
|
|
7470
|
+
name: "email.listAddresses",
|
|
7471
|
+
output
|
|
7472
|
+
};
|
|
7473
|
+
};
|
|
7474
|
+
|
|
7475
|
+
// node_modules/@qawolf/api-contracts/dist/v1/email/send.js
|
|
7476
|
+
var recipientsSchema = array(email2()).max(50);
|
|
7477
|
+
var maxAttachments = 10;
|
|
7478
|
+
var maxEmailAttachmentsBase64Length = 30 * 1024 * 1024;
|
|
7479
|
+
var attachmentsBase64Length = (attachments) => Object.values(attachments).reduce((total, content) => total + content.length, 0);
|
|
7480
|
+
var makeSendEmailContract = (ids) => {
|
|
7481
|
+
const input = object({
|
|
7482
|
+
attachments: record(string2().min(1), base642()).refine((attachments) => Object.keys(attachments).length <= maxAttachments, { message: `Send at most ${maxAttachments} attachments.` }).refine((attachments) => attachmentsBase64Length(attachments) <= maxEmailAttachmentsBase64Length, { message: "Send at most 30 MB of attachments." }).optional().describe("Files to attach, as file name to base64 content, at most 30 MB in total. The MIME type comes from the file name's extension."),
|
|
7483
|
+
bcc: recipientsSchema.optional(),
|
|
7484
|
+
cc: recipientsSchema.optional(),
|
|
7485
|
+
from: email2().optional().describe("The workspace inbox address to send from, or a plus-suffixed form of one. Defaults to the workspace's default inbox address. See email.listAddresses."),
|
|
7486
|
+
html: string2().optional().describe("The HTML body."),
|
|
7487
|
+
inReplyTo: string2().min(1).optional().describe("The id of an email of the workspace to reply to, from email.find. The reply threads under that message."),
|
|
7488
|
+
replyTo: recipientsSchema.optional().describe("Where replies should go instead of the from address."),
|
|
7489
|
+
subject: string2().min(1),
|
|
7490
|
+
text: string2().optional().describe("The plain text body."),
|
|
7491
|
+
to: recipientsSchema.min(1),
|
|
7492
|
+
workspaceId: ids.workspace.optional().describe("The workspace to send from. Required when authenticating with an organization or user API key.")
|
|
7493
|
+
}).refine((email) => email.html || email.text, {
|
|
7494
|
+
message: "Provide text, html, or both."
|
|
7495
|
+
});
|
|
7496
|
+
const output = resource(makeEmailSummaryFields(), {
|
|
7497
|
+
urlFieldDescription: emailUrlFieldDescription
|
|
7498
|
+
});
|
|
7499
|
+
return {
|
|
7500
|
+
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.",
|
|
7501
|
+
input,
|
|
7502
|
+
kind: "write",
|
|
7503
|
+
name: "email.send",
|
|
7504
|
+
output
|
|
7505
|
+
};
|
|
7506
|
+
};
|
|
7507
|
+
|
|
7347
7508
|
// node_modules/@qawolf/api-contracts/dist/v1/environment/deleteVariable.js
|
|
7348
7509
|
var makeDeleteEnvironmentVariableContract = (ids) => {
|
|
7349
7510
|
const input = object({
|
|
@@ -7362,13 +7523,6 @@ var makeDeleteEnvironmentVariableContract = (ids) => {
|
|
|
7362
7523
|
};
|
|
7363
7524
|
};
|
|
7364
7525
|
|
|
7365
|
-
// node_modules/@qawolf/api-contracts/dist/v1/pagination.js
|
|
7366
|
-
var makePaginationInputFields = (limits) => ({
|
|
7367
|
-
cursor: string2().min(1).optional().describe("Opaque cursor copied from the previous response's nextCursor. Omit to fetch the first page."),
|
|
7368
|
-
limit: number2().int().min(1).max(limits.maxLimit).default(limits.defaultLimit).describe(`Maximum rows per page. Defaults to ${limits.defaultLimit}, capped at ${limits.maxLimit}.`)
|
|
7369
|
-
});
|
|
7370
|
-
var nextCursorSchema = string2().min(1).optional().describe("Repeat the request with this value as cursor to fetch the next page. Absent when there are no further results.");
|
|
7371
|
-
|
|
7372
7526
|
// node_modules/@qawolf/api-contracts/dist/v1/environment/resource.js
|
|
7373
7527
|
var makeEnvironmentResourceSchema = (ids) => resource({
|
|
7374
7528
|
alias: string2().optional().describe("The environment's alias: a team-unique slug that team API keys can use in place of the id. Terminated environments have none."),
|
|
@@ -7540,15 +7694,27 @@ var makeCreateTagContract = (ids) => {
|
|
|
7540
7694
|
};
|
|
7541
7695
|
};
|
|
7542
7696
|
|
|
7697
|
+
// node_modules/@qawolf/api-contracts/dist/v1/flow/skippedFlows.js
|
|
7698
|
+
var makeSkippedFlowsSchema = (ids, { description, reason }) => array(object({
|
|
7699
|
+
flowId: ids.flow,
|
|
7700
|
+
name: string2().describe("The name of the flow."),
|
|
7701
|
+
reason
|
|
7702
|
+
})).describe(description);
|
|
7703
|
+
|
|
7543
7704
|
// node_modules/@qawolf/api-contracts/dist/v1/flow/addTag.js
|
|
7544
7705
|
var makeAddTagToFlowsContract = (ids) => {
|
|
7545
7706
|
const input = object({
|
|
7546
7707
|
flowIds: array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The flows that receive the tag."),
|
|
7547
7708
|
tagName: string2().trim().min(1).describe("The name of an existing tag on the caller's team.")
|
|
7548
7709
|
});
|
|
7549
|
-
const output = makeTagResourceSchema()
|
|
7710
|
+
const output = makeTagResourceSchema().extend({
|
|
7711
|
+
skippedFlows: makeSkippedFlowsSchema(ids, {
|
|
7712
|
+
description: "Requested flows that already carried the tag, so nothing changed for them.",
|
|
7713
|
+
reason: _enum(["already-tagged"]).describe('Why the flow was skipped: "already-tagged" means the flow already carried the tag.')
|
|
7714
|
+
})
|
|
7715
|
+
});
|
|
7550
7716
|
return {
|
|
7551
|
-
description: "Assign an existing tag to the selected flows. Create tags with tag.create.",
|
|
7717
|
+
description: "Assign an existing tag to the selected flows. Create tags with tag.create. Flows that already carry the tag are reported in skippedFlows.",
|
|
7552
7718
|
input,
|
|
7553
7719
|
kind: "write",
|
|
7554
7720
|
name: "flow.addTag",
|
|
@@ -7588,6 +7754,27 @@ var makeListFlowsContract = (ids) => {
|
|
|
7588
7754
|
};
|
|
7589
7755
|
};
|
|
7590
7756
|
|
|
7757
|
+
// node_modules/@qawolf/api-contracts/dist/v1/flow/removeTag.js
|
|
7758
|
+
var makeRemoveTagFromFlowsContract = (ids) => {
|
|
7759
|
+
const input = object({
|
|
7760
|
+
flowIds: array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The flows that lose the tag."),
|
|
7761
|
+
tagName: string2().trim().min(1).describe("The name of an existing tag on the caller's team.")
|
|
7762
|
+
});
|
|
7763
|
+
const output = makeTagResourceSchema().extend({
|
|
7764
|
+
skippedFlows: makeSkippedFlowsSchema(ids, {
|
|
7765
|
+
description: "Requested flows that did not carry the tag, so nothing changed for them.",
|
|
7766
|
+
reason: _enum(["not-tagged"]).describe('Why the flow was skipped: "not-tagged" means the flow did not carry the tag.')
|
|
7767
|
+
})
|
|
7768
|
+
});
|
|
7769
|
+
return {
|
|
7770
|
+
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.",
|
|
7771
|
+
input,
|
|
7772
|
+
kind: "write",
|
|
7773
|
+
name: "flow.removeTag",
|
|
7774
|
+
output
|
|
7775
|
+
};
|
|
7776
|
+
};
|
|
7777
|
+
|
|
7591
7778
|
// node_modules/@qawolf/api-contracts/dist/v1/flow/update.js
|
|
7592
7779
|
var makeUpdateFlowContract = (ids) => {
|
|
7593
7780
|
const input = object({
|
|
@@ -7732,6 +7919,24 @@ var makeCreateIssueContract = (ids) => {
|
|
|
7732
7919
|
};
|
|
7733
7920
|
};
|
|
7734
7921
|
|
|
7922
|
+
// node_modules/@qawolf/api-contracts/dist/v1/issue/removeFlows.js
|
|
7923
|
+
var makeRemoveFlowsFromIssueContract = (ids) => {
|
|
7924
|
+
const input = object({
|
|
7925
|
+
flowIds: array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The flows the coverage request no longer covers."),
|
|
7926
|
+
issueId: ids.issue
|
|
7927
|
+
});
|
|
7928
|
+
const output = object({
|
|
7929
|
+
issue: makeIssueResourceSchema(ids)
|
|
7930
|
+
});
|
|
7931
|
+
return {
|
|
7932
|
+
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.",
|
|
7933
|
+
input,
|
|
7934
|
+
kind: "write",
|
|
7935
|
+
name: "issue.removeFlows",
|
|
7936
|
+
output
|
|
7937
|
+
};
|
|
7938
|
+
};
|
|
7939
|
+
|
|
7735
7940
|
// node_modules/@qawolf/api-contracts/dist/v1/issue/update.js
|
|
7736
7941
|
var makeUpdateIssueContract = (ids) => {
|
|
7737
7942
|
const descriptionSchema = string2().describe("The issue description as plain text; each line becomes a paragraph. Markdown is not parsed.");
|
|
@@ -8058,6 +8263,22 @@ var makeTerminateRunnerContract = () => {
|
|
|
8058
8263
|
};
|
|
8059
8264
|
};
|
|
8060
8265
|
|
|
8266
|
+
// node_modules/@qawolf/api-contracts/dist/v1/runner/list.js
|
|
8267
|
+
var makeListRunnersContract = () => {
|
|
8268
|
+
const input = object({});
|
|
8269
|
+
const output = object({
|
|
8270
|
+
outcome: literal("success"),
|
|
8271
|
+
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.")
|
|
8272
|
+
});
|
|
8273
|
+
return {
|
|
8274
|
+
description: "List the runners running on the caller's team right now. Takes no arguments: the API key already names the team. 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.",
|
|
8275
|
+
input,
|
|
8276
|
+
kind: "read",
|
|
8277
|
+
name: "runner.list",
|
|
8278
|
+
output
|
|
8279
|
+
};
|
|
8280
|
+
};
|
|
8281
|
+
|
|
8061
8282
|
// node_modules/@qawolf/api-contracts/dist/v1/runner/promoteSnapshot.js
|
|
8062
8283
|
var maxSnapshotPathLength = 1024;
|
|
8063
8284
|
var makePromoteSnapshotOnRunnerContract = () => {
|
|
@@ -8253,6 +8474,13 @@ var makeContractsV1 = (ids) => {
|
|
|
8253
8474
|
send: makeAgentSendContract(resolvedIds)
|
|
8254
8475
|
},
|
|
8255
8476
|
automate: makeAutomateContract(resolvedIds),
|
|
8477
|
+
email: {
|
|
8478
|
+
find: makeFindEmailsContract(resolvedIds),
|
|
8479
|
+
get: makeGetEmailContract(resolvedIds),
|
|
8480
|
+
getAttachment: makeGetEmailAttachmentContract(resolvedIds),
|
|
8481
|
+
listAddresses: makeListEmailAddressesContract(resolvedIds),
|
|
8482
|
+
send: makeSendEmailContract(resolvedIds)
|
|
8483
|
+
},
|
|
8256
8484
|
environment: {
|
|
8257
8485
|
create: makeCreateEnvironmentContract(resolvedIds),
|
|
8258
8486
|
deleteVariable: makeDeleteEnvironmentVariableContract(resolvedIds),
|
|
@@ -8266,6 +8494,7 @@ var makeContractsV1 = (ids) => {
|
|
|
8266
8494
|
flow: {
|
|
8267
8495
|
addTag: makeAddTagToFlowsContract(resolvedIds),
|
|
8268
8496
|
list: makeListFlowsContract(resolvedIds),
|
|
8497
|
+
removeTag: makeRemoveTagFromFlowsContract(resolvedIds),
|
|
8269
8498
|
update: makeUpdateFlowContract(resolvedIds)
|
|
8270
8499
|
},
|
|
8271
8500
|
issue: {
|
|
@@ -8273,6 +8502,7 @@ var makeContractsV1 = (ids) => {
|
|
|
8273
8502
|
create: makeCreateIssueContract(resolvedIds),
|
|
8274
8503
|
find: makeFindIssuesContract(resolvedIds),
|
|
8275
8504
|
get: makeGetIssueContract(resolvedIds),
|
|
8505
|
+
removeFlows: makeRemoveFlowsFromIssueContract(resolvedIds),
|
|
8276
8506
|
update: makeUpdateIssueContract(resolvedIds)
|
|
8277
8507
|
},
|
|
8278
8508
|
run: {
|
|
@@ -8290,6 +8520,7 @@ var makeContractsV1 = (ids) => {
|
|
|
8290
8520
|
inspect: makeInspectOnRunnerContract(),
|
|
8291
8521
|
inspectMobile: makeInspectMobileOnRunnerContract(),
|
|
8292
8522
|
launch: makeLaunchRunnerContract(),
|
|
8523
|
+
list: makeListRunnersContract(),
|
|
8293
8524
|
performAction: makePerformActionOnRunnerContract(),
|
|
8294
8525
|
promoteSnapshot: makePromoteSnapshotOnRunnerContract(),
|
|
8295
8526
|
readJournal: makeReadRunnerJournalContract(),
|
|
@@ -8306,20 +8537,6 @@ var makeContractsV1 = (ids) => {
|
|
|
8306
8537
|
};
|
|
8307
8538
|
var publicContractsV1 = makeContractsV1(defaultIdSchemas);
|
|
8308
8539
|
|
|
8309
|
-
// src/core/batchMap.ts
|
|
8310
|
-
async function* batchMap(items, fn, size) {
|
|
8311
|
-
if (size < 1) {
|
|
8312
|
-
throw new Error("batchMap size must be greater than 0");
|
|
8313
|
-
}
|
|
8314
|
-
for (let i = 0;i < items.length; i += size) {
|
|
8315
|
-
const batch = items.slice(i, i + size);
|
|
8316
|
-
const results = await Promise.all(batch.map(fn));
|
|
8317
|
-
for (const result of results) {
|
|
8318
|
-
yield result;
|
|
8319
|
-
}
|
|
8320
|
-
}
|
|
8321
|
-
}
|
|
8322
|
-
|
|
8323
8540
|
// src/core/formatSeconds.ts
|
|
8324
8541
|
function formatSeconds(ms) {
|
|
8325
8542
|
return `${Math.round(ms / 1000)}s`;
|
|
@@ -8628,7 +8845,8 @@ var lifecycleMessages = {
|
|
|
8628
8845
|
|
|
8629
8846
|
// src/core/messages/interactiveRunner/list.ts
|
|
8630
8847
|
var listMessages = {
|
|
8631
|
-
noRunners: "
|
|
8848
|
+
noRunners: "Your team has no runner running. Launch one with qawolf runner launch.",
|
|
8849
|
+
noRunnersHere: "This directory has no runner running. Launch one with qawolf runner launch, or drop --here to see the whole team's runners.",
|
|
8632
8850
|
runnerCount: (count) => count === 1 ? "1 runner" : `${String(count)} runners`,
|
|
8633
8851
|
title: "Runners"
|
|
8634
8852
|
};
|
|
@@ -8776,50 +8994,37 @@ var runnerCallOptions = { timeoutMs: 90000 };
|
|
|
8776
8994
|
var runnerIdEnvironmentVariable = "QAWOLF_RUNNER_ID";
|
|
8777
8995
|
|
|
8778
8996
|
// src/domains/interactiveRunner/list.ts
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
const environmentValue = deps.env[runnerIdEnvironmentVariable]?.trim();
|
|
8784
|
-
const fromEnvironment = environmentValue ? environmentValue : undefined;
|
|
8785
|
-
const candidates = [...held];
|
|
8786
|
-
for (const id of [storedDefault, fromEnvironment]) {
|
|
8787
|
-
if (id !== undefined && !candidates.some((runner) => runner.id === id)) {
|
|
8788
|
-
candidates.push({ id });
|
|
8789
|
-
}
|
|
8790
|
-
}
|
|
8791
|
-
return { candidates, defaultRunnerId: fromEnvironment ?? storedDefault };
|
|
8997
|
+
function rank(item) {
|
|
8998
|
+
if (item.isDefault)
|
|
8999
|
+
return 0;
|
|
9000
|
+
return item.launchedHere ? 1 : 2;
|
|
8792
9001
|
}
|
|
8793
|
-
async function
|
|
8794
|
-
const
|
|
8795
|
-
if (
|
|
8796
|
-
return
|
|
8797
|
-
return
|
|
9002
|
+
async function readDefaultRunnerId(deps) {
|
|
9003
|
+
const environmentValue = deps.env[runnerIdEnvironmentVariable]?.trim();
|
|
9004
|
+
if (environmentValue)
|
|
9005
|
+
return environmentValue;
|
|
9006
|
+
return deps.store.readDefaultRunnerId();
|
|
8798
9007
|
}
|
|
8799
9008
|
async function listRunners(ctx, deps) {
|
|
8800
|
-
const
|
|
8801
|
-
|
|
8802
|
-
|
|
8803
|
-
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
running.push(probe.runner);
|
|
8808
|
-
else
|
|
8809
|
-
gone.push(probe.runner.id);
|
|
8810
|
-
}
|
|
9009
|
+
const listed = await ctx.platformClient.callPublicApi(publicContractsV1.runner.list, {}, runnerCallOptions);
|
|
9010
|
+
if (!listed.ok)
|
|
9011
|
+
return { ...failureFields(listed), ok: false };
|
|
9012
|
+
const defaultRunnerId = await readDefaultRunnerId(deps);
|
|
9013
|
+
const runningIds = new Set(listed.value.runners.map((runner) => runner.id));
|
|
9014
|
+
const held = await deps.store.readRunners();
|
|
9015
|
+
const gone = held.filter((runner) => !runningIds.has(runner.id)).map((runner) => runner.id);
|
|
8811
9016
|
await deps.store.dropRunners(gone).catch(() => {
|
|
8812
9017
|
return;
|
|
8813
9018
|
});
|
|
9019
|
+
const heldIds = new Set(held.map((runner) => runner.id));
|
|
9020
|
+
const items = listed.value.runners.map((runner) => ({
|
|
9021
|
+
id: runner.id,
|
|
9022
|
+
isDefault: runner.id === defaultRunnerId,
|
|
9023
|
+
launchedHere: heldIds.has(runner.id),
|
|
9024
|
+
runnerName: runner.runnerName
|
|
9025
|
+
}));
|
|
8814
9026
|
return {
|
|
8815
|
-
items:
|
|
8816
|
-
...running.filter((runner) => runner.id === defaultRunnerId),
|
|
8817
|
-
...running.filter((runner) => runner.id !== defaultRunnerId)
|
|
8818
|
-
].map((runner) => ({
|
|
8819
|
-
id: runner.id,
|
|
8820
|
-
isDefault: runner.id === defaultRunnerId,
|
|
8821
|
-
runnerName: runner.runnerName
|
|
8822
|
-
})),
|
|
9027
|
+
items: items.sort((left, right) => rank(left) - rank(right) || left.id.localeCompare(right.id)),
|
|
8823
9028
|
ok: true
|
|
8824
9029
|
};
|
|
8825
9030
|
}
|
|
@@ -12394,4 +12599,4 @@ export {
|
|
|
12394
12599
|
createRunnerSdk
|
|
12395
12600
|
};
|
|
12396
12601
|
|
|
12397
|
-
//# debugId=
|
|
12602
|
+
//# debugId=231C026DA9D7E0DD64756E2164756E21
|
|
@@ -108,11 +108,15 @@ export type SubmittedRun = {
|
|
|
108
108
|
fileSync: FileSync;
|
|
109
109
|
runId: string;
|
|
110
110
|
};
|
|
111
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* A runner running on the team. `isDefault` and `launchedHere` are this working
|
|
113
|
+
* directory's own knowledge, which the API has no notion of.
|
|
114
|
+
*/
|
|
112
115
|
export type ListedRunner = {
|
|
113
116
|
id: string;
|
|
114
117
|
isDefault: boolean;
|
|
115
|
-
|
|
118
|
+
launchedHere: boolean;
|
|
119
|
+
runnerName: string;
|
|
116
120
|
};
|
|
117
121
|
export type KeptAlive = {
|
|
118
122
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qawolf/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.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.47.0",
|
|
75
75
|
"@qawolf/emails": "1.1.1",
|
|
76
76
|
"@qawolf/flow-targets": "1.0.0",
|
|
77
77
|
"@qawolf/flows": "0.1.4",
|
|
@@ -132,6 +132,11 @@ that `url`; never guess a route and never send a repository link in its place.
|
|
|
132
132
|
| `qawolf auth whoami` | read | Show authentication status |
|
|
133
133
|
| `qawolf automate` | write | 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. |
|
|
134
134
|
| `qawolf doctor` | local | Diagnose problems running flows locally |
|
|
135
|
+
| `qawolf email find` | read | List the workspace's inbox, or its sent mail, newest first. Read a message body with email.get. |
|
|
136
|
+
| `qawolf email get` | read | 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. |
|
|
137
|
+
| `qawolf email getAttachment` | read | Read one attachment of a workspace email as base64 content, by file name or by position. email.get lists both. |
|
|
138
|
+
| `qawolf email listAddresses` | read | 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. |
|
|
139
|
+
| `qawolf email send` | write | 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. |
|
|
135
140
|
| `qawolf environment create` | write | Create an environment on the caller's team and return it in the environment.get shape. |
|
|
136
141
|
| `qawolf environment deleteVariable` | write | Remove one environment variable by name. Succeeds whether or not the variable existed. |
|
|
137
142
|
| `qawolf environment find` | read | List the team's environments, newest first. |
|
|
@@ -140,7 +145,8 @@ that `url`; never guess a route and never send a repository link in its place.
|
|
|
140
145
|
| `qawolf environment listVariableNames` | read | Use this to answer which QA Wolf environment variables are available to test code. Returns names only; values never leave the server. |
|
|
141
146
|
| `qawolf environment setVariable` | write | 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. |
|
|
142
147
|
| `qawolf environment update` | write | Update an environment owned by the caller's team and return it in the environment.get shape. Omitted fields remain unchanged. |
|
|
143
|
-
| `qawolf flow addTag` | write | Assign an existing tag to the selected flows. Create tags with tag.create. |
|
|
148
|
+
| `qawolf flow addTag` | write | Assign an existing tag to the selected flows. Create tags with tag.create. Flows that already carry the tag are reported in skippedFlows. |
|
|
149
|
+
| `qawolf flow removeTag` | write | 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. |
|
|
144
150
|
| `qawolf flow update` | write | Move a flow between draft and active readiness. The other statuses shown in the app are derived and cannot be set. |
|
|
145
151
|
| `qawolf flows list` | local (read with --remote) | List flows matching [pattern] from the local project, or from a QA Wolf environment with --remote |
|
|
146
152
|
| `qawolf flows pull` | read | Download an environment's flows into the local .qawolf/<env>/ cache |
|
|
@@ -154,6 +160,7 @@ that `url`; never guess a route and never send a repository link in its place.
|
|
|
154
160
|
| `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. |
|
|
155
161
|
| `qawolf issue find` | read | List the team's bug reports, maintenance reports, or coverage requests, newest first. |
|
|
156
162
|
| `qawolf issue get` | read | Get an issue by id. |
|
|
163
|
+
| `qawolf issue removeFlows` | write | 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. |
|
|
157
164
|
| `qawolf issue update` | write | Update an issue owned by the caller's team. Omitted fields remain unchanged. |
|
|
158
165
|
| `qawolf run create` | write | Create a run for the selected flows and/or tags in an environment. |
|
|
159
166
|
| `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. |
|
|
@@ -174,7 +181,7 @@ that `url`; never guess a route and never send a repository link in its place.
|
|
|
174
181
|
| `qawolf runner inspect variable` | read | Print a top-level variable's value from the running workflow |
|
|
175
182
|
| `qawolf runner keepalive` | read | Reset a runner's inactivity clock, for a caller that pauses between actions |
|
|
176
183
|
| `qawolf runner launch` | write | Launch an interactive runner and make it this directory's default |
|
|
177
|
-
| `qawolf runner list` | read | List the runners
|
|
184
|
+
| `qawolf runner list` | read | List the runners running on your team |
|
|
178
185
|
| `qawolf runner promote-snapshot` | write | Accept a run's screenshot as the new baseline for an image diff, on the runner that produced it |
|
|
179
186
|
| `qawolf runner run` | write | Run a flow on an interactive runner, shipping the flow and what it imports |
|
|
180
187
|
| `qawolf runner screenshot` | read | Save a JPEG of an interactive runner's screen to a file |
|