@qawolf/cli 1.37.0 → 1.39.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 CHANGED
@@ -16749,6 +16749,11 @@ var makeRequestFileDownloadContract = (ids) => {
16749
16749
  readUrl: string2().describe('Fetch the file\'s bytes from here, for example `curl -o journeys.csv "<readUrl>"`. Write it to a file and read that file, rather than printing the contents, so a large file costs one line of output instead of all of it.')
16750
16750
  });
16751
16751
  return {
16752
+ annotationJustifications: {
16753
+ destructiveHint: "Does not change, overwrite or delete the stored file.",
16754
+ openWorldHint: "Access is limited to QA Wolf team storage; the caller cannot supply an arbitrary external destination.",
16755
+ readOnlyHint: "Returns an expiring read URL for an existing file in the authorized workspace storage."
16756
+ },
16752
16757
  annotations: {
16753
16758
  destructiveHint: false,
16754
16759
  openWorldHint: false,
@@ -16775,6 +16780,11 @@ var makeRequestFileUploadContract = (ids) => {
16775
16780
  uploadUrl: string2().describe(`Send the file's bytes here with a single HTTP PUT carrying the returned contentType, for example \`curl -H 'Content-Type: application/octet-stream' --upload-file "journeys.csv" "<uploadUrl>"\`. Upload the bytes from the shell rather than through this API, so a large file never has to be written out as text.`)
16776
16781
  });
16777
16782
  return {
16783
+ annotationJustifications: {
16784
+ destructiveHint: "Using the returned upload URL with an existing file name replaces that stored file.",
16785
+ openWorldHint: "The upload target is QA Wolf team storage, not an arbitrary external service or recipient.",
16786
+ readOnlyHint: "Returns an expiring upload URL that permits writing a file to the authorized workspace storage."
16787
+ },
16778
16788
  annotations: {
16779
16789
  destructiveHint: true,
16780
16790
  openWorldHint: false,
@@ -16890,6 +16900,11 @@ var makeCreateRunContract = (ids) => {
16890
16900
  tracking: _enum(["registered", "failed", "not-requested"]).describe('Whether the conversation named by aiTaskId or chatSessionId will receive run status updates: "registered" when it will, "failed" when the run was created but the registration failed, "not-requested" when neither id was given or the AI task has no conversation to notify.')
16891
16901
  }, { urlFieldDescription: "Absolute URL of the run page." });
16892
16902
  return {
16903
+ annotationJustifications: {
16904
+ destructiveHint: "Test code can overwrite or delete application data.",
16905
+ openWorldHint: "Test execution can submit forms or change the application under test and its connected services.",
16906
+ readOnlyHint: "Creates a run and enqueues execution of selected flows."
16907
+ },
16893
16908
  annotations: {
16894
16909
  destructiveHint: true,
16895
16910
  openWorldHint: true,
@@ -16903,6 +16918,77 @@ var makeCreateRunContract = (ids) => {
16903
16918
  };
16904
16919
  };
16905
16920
 
16921
+ // node_modules/@qawolf/api-contracts/dist/v1/run/listScreenshotComparisons.js
16922
+ var maxListedScreenshotAttempts = 20;
16923
+ var makeListScreenshotComparisonsContract = (ids) => {
16924
+ const input = object({
16925
+ flowIds: array(ids.flow).min(1).max(100).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").optional().describe("Only list the comparisons of these flows. Each flow must have a result in the run. Omit to list every failed flow of the run."),
16926
+ runId: ids.run
16927
+ });
16928
+ const imageUrl = (image) => url().describe(`Signed URL of the full-size ${image} PNG. It stops working at expiresAt.`);
16929
+ const previewUrl = (image) => url().optional().describe(`Signed URL of a JPEG copy of the ${image} image, scaled down so its long edge is at most 1568 pixels. ` + "Fetch this one to look at the image: it is small enough to view inline, while the full-size PNG can be too large. " + "It stops working at expiresAt. Absent when QA Wolf could not make the copy, for example because the full-size image is gone.");
16930
+ const passedEnvironment = object({
16931
+ environmentId: ids.environment,
16932
+ lastPassedAt: exports_iso.datetime().describe("When the latest passing comparison in this environment ran.")
16933
+ });
16934
+ const passingElsewhere = discriminatedUnion("status", [
16935
+ object({
16936
+ status: literal("not-tracked").describe("QA Wolf does not record screenshot comparisons for this workspace, so it cannot tell.")
16937
+ }),
16938
+ object({
16939
+ environments: array(passedEnvironment).describe("Other environments where the current baseline passed this screenshot in the last 14 days, most recent first. " + "Empty when it passed nowhere else, or when the baseline no longer exists."),
16940
+ status: literal("tracked")
16941
+ })
16942
+ ]).describe("Whether the current baseline still passes in other environments. " + "A baseline that passes elsewhere points to a difference in this environment rather than an outdated baseline.");
16943
+ const comparison = object({
16944
+ actualPreviewUrl: previewUrl("actual"),
16945
+ actualUrl: imageUrl("actual (the screenshot the flow took)"),
16946
+ attemptCompletedAt: exports_iso.datetime().describe("When the run attempt that made the comparison finished."),
16947
+ baselineStatus: _enum([
16948
+ "unchanged",
16949
+ "accepted",
16950
+ "changed-since-run",
16951
+ "deleted",
16952
+ "unknown"
16953
+ ]).describe('How the current baseline relates to the expected image this comparison used. "unchanged": the baseline is still the expected image. ' + `"accepted": the baseline is now this comparison's actual screenshot, because someone accepted it, so a reattempt should pass. ` + '"changed-since-run": someone replaced the baseline with another image after this run, so rerun the flow before deciding anything. ' + '"deleted": the baseline no longer exists, and the next run will save its screenshot as the new baseline. ' + `"unknown": the run's copy of the expected image is gone, so QA Wolf cannot compare.`),
16954
+ comparisonId: string2().describe("Identifies this comparison: the run attempt id and the position of the comparison in that attempt."),
16955
+ diffPreviewUrl: previewUrl("diff"),
16956
+ diffUrl: imageUrl("diff (the pixels that differ are highlighted)"),
16957
+ expectedPreviewUrl: previewUrl("expected"),
16958
+ expectedUrl: imageUrl("expected (the baseline as it was when the flow ran)"),
16959
+ filePath: string2().optional().describe("The flow file that made the comparison."),
16960
+ flowId: ids.flow,
16961
+ lineNumber: number2().int().optional().describe("The line of filePath that made the comparison."),
16962
+ name: string2().describe("The screenshot name the flow passed to toHaveScreenshot. The baseline is stored as _screenshots_/<name>.png in team storage."),
16963
+ passingElsewhere,
16964
+ runAttemptId: string2(),
16965
+ similarity: number2().describe("How much of the actual image matches the expected image, in percent."),
16966
+ sizeMismatch: boolean2().describe("The actual and expected images have different dimensions. That fails the comparison whatever the pixels show, and similarity reads 0.")
16967
+ });
16968
+ const output = object({
16969
+ comparisons: array(comparison).describe(`Each screenshot comparison that failed its flow, from the ${maxListedScreenshotAttempts} most recent failed attempts of the selected flows, oldest attempt first.`),
16970
+ expiresAt: exports_iso.datetime().describe("When the image URLs stop working. Call run.listScreenshotComparisons again for fresh ones after it."),
16971
+ truncated: boolean2().describe(`True when the selected flows have more than ${maxListedScreenshotAttempts} failed attempts. Only the ${maxListedScreenshotAttempts} most recent are listed, and the older attempts cannot be listed.`)
16972
+ });
16973
+ return {
16974
+ annotationJustifications: {
16975
+ destructiveHint: "Does not change baselines, results or the run.",
16976
+ openWorldHint: "Reads recorded QA Wolf screenshots without changing the application under test.",
16977
+ readOnlyHint: "Creates missing JPEG previews of the compared images and keeps them in team storage."
16978
+ },
16979
+ annotations: {
16980
+ destructiveHint: false,
16981
+ openWorldHint: false,
16982
+ readOnlyHint: false
16983
+ },
16984
+ description: "List the screenshot comparisons that failed a run's flows, with the expected, actual and diff images of each. " + "Only comparisons that caused a failure are listed: a screenshot that differs within tolerance, or that differs on a line that did not fail, is left out. " + "Each comparison tells whether its baseline changed since the run and whether the baseline still passes in other environments. " + "The image URLs expire after a few minutes; fetch the preview URLs to look at the images. " + "The first call for an image makes its missing JPEG preview and keeps it in team storage, so later calls reuse it.",
16985
+ input,
16986
+ kind: "read",
16987
+ name: "run.listScreenshotComparisons",
16988
+ output
16989
+ };
16990
+ };
16991
+
16906
16992
  // node_modules/@qawolf/api-contracts/dist/v1/runner/actionSequence.js
16907
16993
  var maxActionsPerRequest = 10;
16908
16994
  var screenshotModes = ["none", "final", "each"];
@@ -16963,6 +17049,7 @@ var browserActionSchema = discriminatedUnion("type", [
16963
17049
  type: literal("type")
16964
17050
  })
16965
17051
  ]);
17052
+
16966
17053
  // node_modules/@qawolf/api-contracts/dist/v1/runner/environment.js
16967
17054
  var reservedRunEnvironmentVariableName = "QAWOLF_TEAM_ID";
16968
17055
  function refusalForRunEnvironmentVariableName(name) {
@@ -17083,6 +17170,11 @@ var makeInspectOnRunnerContract = (ids) => {
17083
17170
  })
17084
17171
  ]);
17085
17172
  return {
17173
+ annotationJustifications: {
17174
+ destructiveHint: "Does not edit test code or application data, although the activity refresh can extend billed runtime.",
17175
+ openWorldHint: "Inspects the private runner session without submitting application actions.",
17176
+ readOnlyHint: "Retrieves browser inspection data and refreshes activity, which can cancel an inactivity shutdown."
17177
+ },
17086
17178
  annotations: {
17087
17179
  destructiveHint: false,
17088
17180
  openWorldHint: false,
@@ -17247,6 +17339,11 @@ var makeInspectMobileOnRunnerContract = (ids) => {
17247
17339
  ])
17248
17340
  ]);
17249
17341
  return {
17342
+ annotationJustifications: {
17343
+ destructiveHint: "Does not change application data, edit tests, or stop the runner.",
17344
+ openWorldHint: "Inspects the existing QA Wolf mobile runner without submitting application actions or contacting arbitrary services.",
17345
+ readOnlyHint: "Reads mobile session status, contexts, page source, or elements without refreshing the runner's inactivity timer."
17346
+ },
17250
17347
  annotations: {
17251
17348
  destructiveHint: false,
17252
17349
  openWorldHint: false,
@@ -17421,6 +17518,11 @@ var makePerformActionOnRunnerContract = (ids) => {
17421
17518
  failure
17422
17519
  ]);
17423
17520
  return {
17521
+ annotationJustifications: {
17522
+ destructiveHint: "Actions can submit irreversible transactions or delete existing data, so uncertain outcomes must be inspected before retrying.",
17523
+ openWorldHint: "Clicks, typing and navigation can submit external forms or change application state.",
17524
+ readOnlyHint: "Performs a browser or device action and can start a browser when needed."
17525
+ },
17424
17526
  annotations: {
17425
17527
  destructiveHint: true,
17426
17528
  openWorldHint: true,
@@ -17472,6 +17574,7 @@ var failedStepSchema = discriminatedUnion("failureReason", [
17472
17574
  failureReason: _enum([
17473
17575
  ...screenFailureReasons,
17474
17576
  "action-not-supported-on-mobile",
17577
+ "action-not-supported-on-browser",
17475
17578
  outOfTimeFailureReason
17476
17579
  ]),
17477
17580
  index: actionIndexSchema,
@@ -17486,6 +17589,7 @@ var sequenceFailureReasons = [
17486
17589
  "action-failed",
17487
17590
  ...screenFailureReasons,
17488
17591
  "action-not-supported-on-mobile",
17592
+ "action-not-supported-on-browser",
17489
17593
  outOfTimeFailureReason,
17490
17594
  unconfirmedFailureReason,
17491
17595
  runnerUnreachableFailureReason
@@ -17494,11 +17598,11 @@ var sequenceFailureReasons = [
17494
17598
  // node_modules/@qawolf/api-contracts/dist/v1/runner/performActions.js
17495
17599
  var actionsDescription = `The actions to perform, in order, each exactly what \`runner.performAction\` takes: coordinates are whole pixels on the runner's virtual desktop, in the same space as \`runner.takeScreenshot\`, and the shapes follow the computer-use vocabulary. At most ${maxActionsPerRequest} per request. For when the next several steps are already known — click a field, type into it, press Enter — and one look at the screen at the end is enough. They run back to back on the runner, with no pause between them: put in one request only steps whose targets are all on the screen you last saw and are not moved by the steps before them, and when a step changes the page — a submit, a navigation, opening a menu — make it the last one and read the frame.`;
17496
17600
  var screenshotModeDescription = "`final`, the default, answers with one screenshot in `imageJpegBase64`: the screen after the last action, or, after a stop, as it stands. `each` puts a screenshot after every action on its entry in `results`, for when each step must be checked; every frame is a full image, so keep such sequences short. `none` sends no screenshot.";
17497
- var stopOnFailureDescription = "`true`, the default, leaves the remaining actions unperformed once one fails. `false` carries on past an action that reached the runner and did not take effect (`action-failed`, `action-not-supported-on-mobile`), so use it only for actions that do not depend on each other: a `type` after a `click` that failed goes to whatever has focus. A runner that cannot be reached, a screen that cannot serve, or running out of time ends the sequence either way.";
17601
+ var stopOnFailureDescription = "`true`, the default, leaves the remaining actions unperformed once one fails. `false` carries on past an action that reached the runner and did not take effect (`action-failed`, `action-not-supported-on-mobile`, `action-not-supported-on-browser`), so use it only for actions that do not depend on each other: a `type` after a `click` that failed goes to whatever has focus. A runner that cannot be reached, a screen that cannot serve, or running out of time ends the sequence either way.";
17498
17602
  var finalImageDescription = "Present with `screenshotMode: final` when the runner still answered: the screen after the last action performed, or, after a stop, as it stands.";
17499
17603
  var makePerformActionsOnRunnerContract = (ids) => {
17500
17604
  const input = object({
17501
- actions: array(browserActionSchema).min(1).max(maxActionsPerRequest).describe(actionsDescription),
17605
+ actions: array(runnerActionSchema).min(1).max(maxActionsPerRequest).describe(actionsDescription),
17502
17606
  id: runnerIdSchema.describe("Id of the runner to act on."),
17503
17607
  screenshotMode: _enum(screenshotModes).optional().describe(screenshotModeDescription),
17504
17608
  stopOnFailure: boolean2().optional().describe(stopOnFailureDescription),
@@ -17523,12 +17627,17 @@ var makePerformActionsOnRunnerContract = (ids) => {
17523
17627
  })
17524
17628
  ]);
17525
17629
  return {
17630
+ annotationJustifications: {
17631
+ destructiveHint: "Actions can submit irreversible transactions or delete existing data, so uncertain outcomes must be inspected before retrying.",
17632
+ openWorldHint: "Clicks, typing and navigation can submit external forms or change application state.",
17633
+ readOnlyHint: "Performs a sequence of browser or device actions on a runner."
17634
+ },
17526
17635
  annotations: {
17527
17636
  destructiveHint: true,
17528
17637
  openWorldHint: true,
17529
17638
  readOnlyHint: false
17530
17639
  },
17531
- description: "Perform a sequence of raw browser actions on an interactive runner in one request, one after another, and answer with what happened to each. A `success` means every action took effect. A `failure` names the first action that did not (`failedIndex`, `failureReason`), the last one that did (`lastCompletedIndex`), and whether actions were left unperformed (`stoppedEarly`); `results` has one entry per action reached, in order. Read `effect` on an entry before sending its action again: `performed` means the runner did it; `not-performed` means the runner answered that it did not take effect, though a `navigate` that timed out may still be loading; `unknown` means the runner stopped answering with the action in flight (`runner-unreachable`), or its screen went quiet mid-action (`action-unconfirmed`), and it may have taken effect — a click that submitted a form, say — so take a screenshot instead of repeating it. A sequence gets about a minute to start its actions; an action it did not reach in time is `out-of-time`, nothing after it was attempted, and the rest can go in a new request. Everything `runner.performAction` says about a runner that has never run anything, a mobile runner, and the `screen-needs-a-run`, `screen-not-ready`, `runner-has-no-screen` and `action-not-supported-on-mobile` reasons holds for each action here.",
17640
+ description: "Perform a sequence of raw actions on an interactive runner in one request, one after another, and answer with what happened to each. A `success` means every action took effect. A `failure` names the first action that did not (`failedIndex`, `failureReason`), the last one that did (`lastCompletedIndex`), and whether actions were left unperformed (`stoppedEarly`); `results` has one entry per action reached, in order. Read `effect` on an entry before sending its action again: `performed` means the runner did it; `not-performed` means the runner answered that it did not take effect, though a `navigate` that timed out may still be loading; `unknown` means the runner stopped answering with the action in flight (`runner-unreachable`), or its screen went quiet mid-action (`action-unconfirmed`), and it may have taken effect — a click that submitted a form, say — so take a screenshot instead of repeating it. A sequence gets about a minute to start its actions; an action it did not reach in time is `out-of-time`, nothing after it was attempted, and the rest can go in a new request. Everything `runner.performAction` says about a runner that has never run anything, a mobile runner, and the `screen-needs-a-run`, `screen-not-ready`, `runner-has-no-screen`, `action-not-supported-on-mobile` and `action-not-supported-on-browser` reasons holds for each action here.",
17532
17641
  input,
17533
17642
  kind: "write",
17534
17643
  name: "runner.performActions",
@@ -17596,6 +17705,11 @@ var makeRecordOnRunnerContract = (ids) => {
17596
17705
  url: url()
17597
17706
  });
17598
17707
  return {
17708
+ annotationJustifications: {
17709
+ destructiveHint: "Starts or stops a video recording without changing the application under test.",
17710
+ openWorldHint: "Controls recording on a QA Wolf runner without starting external work.",
17711
+ readOnlyHint: "Starts or stops video recording and changes automatic capture settings."
17712
+ },
17599
17713
  annotations: {
17600
17714
  destructiveHint: false,
17601
17715
  openWorldHint: false,
@@ -17623,6 +17737,11 @@ var makeRunnerRecordingsContract = (ids) => {
17623
17737
  }))
17624
17738
  });
17625
17739
  return {
17740
+ annotationJustifications: {
17741
+ destructiveHint: "Does not delete or change any recording.",
17742
+ openWorldHint: "Reads QA Wolf workspace storage without changing the application under test.",
17743
+ readOnlyHint: "Lists or retrieves a runner's finalized recordings."
17744
+ },
17626
17745
  annotations: {
17627
17746
  destructiveHint: false,
17628
17747
  openWorldHint: false,
@@ -17852,6 +17971,11 @@ var makeCreateTriggerContract = (ids) => {
17852
17971
  ]).superRefine(checkTriggerConfiguration);
17853
17972
  const output = object({ trigger: makeTriggerResourceSchema(ids) });
17854
17973
  return {
17974
+ annotationJustifications: {
17975
+ destructiveHint: "Enables automatic execution of test code that may overwrite or delete application data.",
17976
+ openWorldHint: "Triggered runs can change the application under test and update connected integrations.",
17977
+ readOnlyHint: "Creates an active schedule or deployment trigger that can start test runs."
17978
+ },
17855
17979
  annotations: {
17856
17980
  destructiveHint: true,
17857
17981
  openWorldHint: true,
@@ -17875,6 +17999,11 @@ var makeFindTriggersContract = (ids) => {
17875
17999
  triggers: array(makeTriggerResourceSchema(ids)).describe("The team's triggers, newest first.")
17876
18000
  });
17877
18001
  return {
18002
+ annotationJustifications: {
18003
+ destructiveHint: "Does not modify or delete triggers or their runs.",
18004
+ openWorldHint: "Reads private QA Wolf trigger records without changing external systems.",
18005
+ readOnlyHint: "Lists trigger configuration in the authorized workspace without changing it."
18006
+ },
17878
18007
  annotations: {
17879
18008
  destructiveHint: false,
17880
18009
  openWorldHint: false,
@@ -17893,6 +18022,11 @@ var makeGetTriggerContract = (ids) => {
17893
18022
  const input = object({ triggerId: ids.trigger });
17894
18023
  const output = object({ trigger: makeTriggerResourceSchema(ids) });
17895
18024
  return {
18025
+ annotationJustifications: {
18026
+ destructiveHint: "Does not modify or delete the trigger or its runs.",
18027
+ openWorldHint: "Reads a private QA Wolf trigger without changing external systems.",
18028
+ readOnlyHint: "Retrieves one authorized trigger and its configuration without changing it."
18029
+ },
17896
18030
  annotations: {
17897
18031
  destructiveHint: false,
17898
18032
  openWorldHint: false,
@@ -17911,6 +18045,11 @@ var makePauseTriggerContract = (ids) => {
17911
18045
  const input = object({ triggerId: ids.trigger });
17912
18046
  const output = object({ trigger: makeTriggerResourceSchema(ids) });
17913
18047
  return {
18048
+ annotationJustifications: {
18049
+ destructiveHint: "Disables future automatic execution for the selected trigger until it is resumed.",
18050
+ openWorldHint: "Changes private QA Wolf scheduling state without starting external work.",
18051
+ readOnlyHint: "Pauses an existing trigger so it stops starting new work."
18052
+ },
17914
18053
  annotations: {
17915
18054
  destructiveHint: true,
17916
18055
  openWorldHint: false,
@@ -17927,6 +18066,11 @@ var makeResumeTriggerContract = (ids) => {
17927
18066
  const input = object({ triggerId: ids.trigger });
17928
18067
  const output = object({ trigger: makeTriggerResourceSchema(ids) });
17929
18068
  return {
18069
+ annotationJustifications: {
18070
+ destructiveHint: "Enables automatic test execution that may overwrite or delete application data.",
18071
+ openWorldHint: "Resumed execution can change the application under test and update connected integrations.",
18072
+ readOnlyHint: "Reactivates a paused trigger so future matching schedules or deployments can start runs."
18073
+ },
17930
18074
  annotations: {
17931
18075
  destructiveHint: true,
17932
18076
  openWorldHint: true,
@@ -17945,6 +18089,11 @@ var makeDeleteTriggerContract = (ids) => {
17945
18089
  triggerId: ids.trigger.describe("The id of the deleted trigger.")
17946
18090
  });
17947
18091
  return {
18092
+ annotationJustifications: {
18093
+ destructiveHint: "Permanently deletes the selected trigger configuration.",
18094
+ openWorldHint: "Removes private QA Wolf trigger configuration without starting external work.",
18095
+ readOnlyHint: "Permanently removes a trigger while preserving runs it already created."
18096
+ },
17948
18097
  annotations: {
17949
18098
  destructiveHint: true,
17950
18099
  openWorldHint: false,
@@ -17981,6 +18130,11 @@ var makeUpdateTriggerContract = (ids) => {
17981
18130
  ]).superRefine(checkTriggerConfiguration);
17982
18131
  const output = object({ trigger: makeTriggerResourceSchema(ids) });
17983
18132
  return {
18133
+ annotationJustifications: {
18134
+ destructiveHint: "Overwrites trigger configuration and can enable tests that change or delete application data.",
18135
+ openWorldHint: "The updated trigger can execute tests against external applications and update connected integrations.",
18136
+ readOnlyHint: "Replaces an existing trigger configuration and can change future automatic runs."
18137
+ },
17984
18138
  annotations: {
17985
18139
  destructiveHint: true,
17986
18140
  openWorldHint: true,
@@ -18022,6 +18176,11 @@ var makeAgentGetContract = (ids) => {
18022
18176
  urlFieldDescription: "Absolute URL of the live session in the QA Wolf app."
18023
18177
  });
18024
18178
  return {
18179
+ annotationJustifications: {
18180
+ destructiveHint: "Does not cancel work or edit tests and messages.",
18181
+ openWorldHint: "Reads a QA Wolf session without posting to external services.",
18182
+ readOnlyHint: "Retrieves session status, replies and the live link without sending work."
18183
+ },
18025
18184
  annotations: {
18026
18185
  destructiveHint: false,
18027
18186
  openWorldHint: false,
@@ -18053,6 +18212,11 @@ var makeAgentSendContract = (ids) => {
18053
18212
  urlFieldDescription: "Absolute URL of the live session in the QA Wolf app."
18054
18213
  });
18055
18214
  return {
18215
+ annotationJustifications: {
18216
+ destructiveHint: "Delegated execution can overwrite test code or change and delete application data.",
18217
+ openWorldHint: "Delegated work can submit application actions and publish code to connected repositories.",
18218
+ readOnlyHint: "Creates or continues AI work that can implement, run and publish tests."
18219
+ },
18056
18220
  annotations: {
18057
18221
  destructiveHint: true,
18058
18222
  openWorldHint: true,
@@ -18091,6 +18255,11 @@ var makeFindCodeHostIntegrationsContract = (ids) => {
18091
18255
  settingsUrl: url().describe("Absolute URL of the workspace's integrations settings page.")
18092
18256
  });
18093
18257
  return {
18258
+ annotationJustifications: {
18259
+ destructiveHint: "Does not disconnect integrations or change repository access.",
18260
+ openWorldHint: "Reads QA Wolf integration records without contacting or changing GitHub or GitLab.",
18261
+ readOnlyHint: "Lists the workspace's stored code host integrations and settings link without modifying them."
18262
+ },
18094
18263
  annotations: {
18095
18264
  destructiveHint: false,
18096
18265
  openWorldHint: false,
@@ -18123,6 +18292,11 @@ var makeListCodeHostRepositoriesContract = (ids) => {
18123
18292
  repositories: array(makeCodeHostRepositoryResourceSchema()).describe("The repositories the workspace's code host integrations cover, alphabetical by full name.")
18124
18293
  });
18125
18294
  return {
18295
+ annotationJustifications: {
18296
+ destructiveHint: "Does not edit repositories, integration settings, or access permissions.",
18297
+ openWorldHint: "Reads repositories already recorded for the workspace's integrations, without accessing arbitrary external repositories.",
18298
+ readOnlyHint: "Lists repository metadata from the workspace's last code host sync without triggering a new sync."
18299
+ },
18126
18300
  annotations: {
18127
18301
  destructiveHint: false,
18128
18302
  openWorldHint: false,
@@ -18166,6 +18340,11 @@ var makeFindDeploymentsContract = (ids) => {
18166
18340
  nextCursor: nextCursorSchema
18167
18341
  });
18168
18342
  return {
18343
+ annotationJustifications: {
18344
+ destructiveHint: "Does not modify deployments, environments, triggers, or runs.",
18345
+ openWorldHint: "Reads QA Wolf deployment records without contacting deployment providers or starting tests.",
18346
+ readOnlyHint: "Lists stored workspace deployments without reporting or changing their status."
18347
+ },
18169
18348
  annotations: {
18170
18349
  destructiveHint: false,
18171
18350
  openWorldHint: false,
@@ -18240,6 +18419,11 @@ var makeListDeploymentTriggerEvaluationsContract = (ids) => {
18240
18419
  object({ state: literal("not-evaluated") }).describe("Triggers were never evaluated for this deployment. Only a deployment's first success report evaluates triggers, so a deployment that never reported success carries no verdicts.")
18241
18420
  ]);
18242
18421
  return {
18422
+ annotationJustifications: {
18423
+ destructiveHint: "Does not alter recorded verdicts, trigger configuration, or existing runs.",
18424
+ openWorldHint: "Reads stored QA Wolf verdicts without starting tests or updating external services.",
18425
+ readOnlyHint: "Retrieves the recorded trigger verdicts for one deployment without evaluating triggers again."
18426
+ },
18243
18427
  annotations: {
18244
18428
  destructiveHint: false,
18245
18429
  openWorldHint: false,
@@ -18311,6 +18495,11 @@ var makeReportDeploymentStatusContract = (ids) => {
18311
18495
  }, { urlFieldDescription: "Absolute URL of the environment's runs page." });
18312
18496
  const output = object({ deployment });
18313
18497
  return {
18498
+ annotationJustifications: {
18499
+ destructiveHint: "Can replace deployment details and variable overrides, and trigger tests that overwrite or delete application data.",
18500
+ openWorldHint: "Successful deployments can start tests against external applications and update connected integrations.",
18501
+ readOnlyHint: "Creates or updates a deployment, can create an environment, and evaluates triggers on its first success report."
18502
+ },
18314
18503
  annotations: {
18315
18504
  destructiveHint: true,
18316
18505
  openWorldHint: true,
@@ -18347,6 +18536,11 @@ var makeFindEmailsContract = (ids) => {
18347
18536
  nextCursor: nextCursorSchema
18348
18537
  });
18349
18538
  return {
18539
+ annotationJustifications: {
18540
+ destructiveHint: "Does not send, edit, or delete email messages.",
18541
+ openWorldHint: "Reads the workspace's QA Wolf inbox records without contacting recipients or arbitrary mailboxes.",
18542
+ readOnlyHint: "Searches stored workspace emails and returns matching message summaries."
18543
+ },
18350
18544
  annotations: {
18351
18545
  destructiveHint: false,
18352
18546
  openWorldHint: false,
@@ -18368,6 +18562,11 @@ var makeGetEmailContract = (ids) => {
18368
18562
  });
18369
18563
  const output = makeEmailResourceSchema();
18370
18564
  return {
18565
+ annotationJustifications: {
18566
+ destructiveHint: "Does not alter or delete the message or its attachments.",
18567
+ openWorldHint: "Reads a stored workspace message without forwarding it or contacting external recipients.",
18568
+ readOnlyHint: "Retrieves the content of an existing workspace email."
18569
+ },
18371
18570
  annotations: {
18372
18571
  destructiveHint: false,
18373
18572
  openWorldHint: false,
@@ -18396,6 +18595,11 @@ var makeGetEmailAttachmentContract = (ids) => {
18396
18595
  type: string2().optional().describe("The MIME type.")
18397
18596
  }, { urlFieldDescription: emailUrlFieldDescription });
18398
18597
  return {
18598
+ annotationJustifications: {
18599
+ destructiveHint: "Does not modify or delete the email or attachment.",
18600
+ openWorldHint: "Access is limited to attachments of authorized workspace emails, not arbitrary external files.",
18601
+ readOnlyHint: "Reads one attachment from an existing workspace email and returns its content."
18602
+ },
18399
18603
  annotations: {
18400
18604
  destructiveHint: false,
18401
18605
  openWorldHint: false,
@@ -18420,6 +18624,11 @@ var makeListEmailAddressesContract = (ids) => {
18420
18624
  nextCursor: nextCursorSchema
18421
18625
  });
18422
18626
  return {
18627
+ annotationJustifications: {
18628
+ destructiveHint: "Does not register, replace, or remove inbox addresses.",
18629
+ openWorldHint: "Reads QA Wolf inbox configuration without contacting external mail services or recipients.",
18630
+ readOnlyHint: "Lists the workspace's registered inbox addresses without changing them."
18631
+ },
18423
18632
  annotations: {
18424
18633
  destructiveHint: false,
18425
18634
  openWorldHint: false,
@@ -18447,6 +18656,11 @@ var makeRegisterEmailAddressContract = (ids) => {
18447
18656
  });
18448
18657
  const output = makeEmailAddressResourceSchema();
18449
18658
  return {
18659
+ annotationJustifications: {
18660
+ destructiveHint: "Adds an address without replacing or deleting existing inbox addresses or emails.",
18661
+ openWorldHint: "Adds a QA Wolf workspace inbox address without sending messages to external recipients.",
18662
+ readOnlyHint: "Registers an additional inbox address for the workspace."
18663
+ },
18450
18664
  annotations: {
18451
18665
  destructiveHint: false,
18452
18666
  openWorldHint: false,
@@ -18485,6 +18699,11 @@ var makeSendEmailContract = (ids) => {
18485
18699
  urlFieldDescription: emailUrlFieldDescription
18486
18700
  });
18487
18701
  return {
18702
+ annotationJustifications: {
18703
+ destructiveHint: "Sending an email is irreversible; recipients may act on it, and the tool cannot recall it.",
18704
+ openWorldHint: "Delivers message content and attachments to caller-selected email recipients outside QA Wolf.",
18705
+ readOnlyHint: "Sends an email from a workspace inbox and stores the sent message."
18706
+ },
18488
18707
  annotations: {
18489
18708
  destructiveHint: true,
18490
18709
  openWorldHint: true,
@@ -18530,6 +18749,11 @@ var makeCreateEnvironmentContract = (ids) => {
18530
18749
  });
18531
18750
  const output = makeEnvironmentResourceSchema(ids);
18532
18751
  return {
18752
+ annotationJustifications: {
18753
+ destructiveHint: "Adds a new environment and branch rather than deleting or overwriting an existing one.",
18754
+ openWorldHint: "Creates a branch in the connected Git provider rather than changing only QA Wolf records.",
18755
+ readOnlyHint: "Creates a QA Wolf environment and its remote flow-code branch."
18756
+ },
18533
18757
  annotations: {
18534
18758
  destructiveHint: false,
18535
18759
  openWorldHint: true,
@@ -18554,6 +18778,11 @@ var makeDeleteEnvironmentVariableContract = (ids) => {
18554
18778
  name: string2().describe("The canonicalized name that was removed. Returned even when the environment had no such variable.")
18555
18779
  });
18556
18780
  return {
18781
+ annotationJustifications: {
18782
+ destructiveHint: "Deletes an existing variable value, while an already-absent variable is left absent.",
18783
+ openWorldHint: "Changes private test configuration without submitting it to an external application.",
18784
+ readOnlyHint: "Removes a named environment variable from QA Wolf storage."
18785
+ },
18557
18786
  annotations: {
18558
18787
  destructiveHint: true,
18559
18788
  openWorldHint: false,
@@ -18581,6 +18810,11 @@ var makeFindEnvironmentsContract = (ids) => {
18581
18810
  nextCursor: nextCursorSchema
18582
18811
  });
18583
18812
  return {
18813
+ annotationJustifications: {
18814
+ destructiveHint: "Does not edit environments, variables or branches.",
18815
+ openWorldHint: "Reads private QA Wolf environment metadata without publishing changes.",
18816
+ readOnlyHint: "Lists workspace environments and their configuration summaries."
18817
+ },
18584
18818
  annotations: {
18585
18819
  destructiveHint: false,
18586
18820
  openWorldHint: false,
@@ -18609,6 +18843,11 @@ var makeGetEnvironmentVariableContract = (ids) => {
18609
18843
  })).describe("The found variables, sorted by name.")
18610
18844
  });
18611
18845
  return {
18846
+ annotationJustifications: {
18847
+ destructiveHint: "Does not replace or remove variable values.",
18848
+ openWorldHint: "Reads private stored configuration without submitting it to an external application.",
18849
+ readOnlyHint: "Retrieves decrypted values of named environment variables and reports missing names."
18850
+ },
18612
18851
  annotations: {
18613
18852
  destructiveHint: false,
18614
18853
  openWorldHint: false,
@@ -18630,6 +18869,11 @@ var makeGetEnvironmentContract = (ids) => {
18630
18869
  });
18631
18870
  const output = makeEnvironmentResourceSchema(ids);
18632
18871
  return {
18872
+ annotationJustifications: {
18873
+ destructiveHint: "Does not alter environment settings or concurrency limits.",
18874
+ openWorldHint: "Reads QA Wolf environment state without updating the connected Git provider.",
18875
+ readOnlyHint: "Retrieves an environment's configuration, run health and code-reconciliation state."
18876
+ },
18633
18877
  annotations: {
18634
18878
  destructiveHint: false,
18635
18879
  openWorldHint: false,
@@ -18651,6 +18895,11 @@ var makeListEnvironmentVariableNamesContract = (ids) => {
18651
18895
  variableNames: array(string2()).describe("Names of the environment's variables, sorted alphabetically. Values are never returned.")
18652
18896
  });
18653
18897
  return {
18898
+ annotationJustifications: {
18899
+ destructiveHint: "Does not alter variables or expose their stored values.",
18900
+ openWorldHint: "Reads private configuration names without changing external systems.",
18901
+ readOnlyHint: "Lists available environment variable names without retrieving their values."
18902
+ },
18654
18903
  annotations: {
18655
18904
  destructiveHint: false,
18656
18905
  openWorldHint: false,
@@ -18674,6 +18923,11 @@ var makeSetEnvironmentVariableContract = (ids) => {
18674
18923
  name: string2().describe("The stored variable name after whitespace is replaced with underscores and letters are uppercased.")
18675
18924
  });
18676
18925
  return {
18926
+ annotationJustifications: {
18927
+ destructiveHint: "Can overwrite an existing variable value, while an unchanged value is skipped.",
18928
+ openWorldHint: "Changes stored QA Wolf configuration rather than submitting forms or publishing content.",
18929
+ readOnlyHint: "Creates or replaces a named environment variable without returning its value."
18930
+ },
18677
18931
  annotations: {
18678
18932
  destructiveHint: true,
18679
18933
  openWorldHint: false,
@@ -18701,6 +18955,11 @@ var makeUpdateEnvironmentContract = (ids) => {
18701
18955
  });
18702
18956
  const output = makeEnvironmentResourceSchema(ids);
18703
18957
  return {
18958
+ annotationJustifications: {
18959
+ destructiveHint: "Can overwrite existing environment settings and affect future run capacity.",
18960
+ openWorldHint: "Changes private environment settings without publishing code or contacting application users.",
18961
+ readOnlyHint: "Updates an environment's name or run concurrency limit."
18962
+ },
18704
18963
  annotations: {
18705
18964
  destructiveHint: true,
18706
18965
  openWorldHint: false,
@@ -18728,6 +18987,11 @@ var makeCreateTagContract = (ids) => {
18728
18987
  });
18729
18988
  const output = makeTagResourceSchema();
18730
18989
  return {
18990
+ annotationJustifications: {
18991
+ destructiveHint: "Creates a tag without deleting existing tags or flow associations.",
18992
+ openWorldHint: "Adds private QA Wolf metadata without publishing to an external application.",
18993
+ readOnlyHint: "Creates a workspace tag for grouping and selecting flows."
18994
+ },
18731
18995
  annotations: {
18732
18996
  destructiveHint: false,
18733
18997
  openWorldHint: false,
@@ -18761,6 +19025,11 @@ var makeAddTagToFlowsContract = (ids) => {
18761
19025
  })
18762
19026
  });
18763
19027
  return {
19028
+ annotationJustifications: {
19029
+ destructiveHint: "Adds associations without removing existing tags.",
19030
+ openWorldHint: "Changes private flow-tag associations without running flows or publishing code.",
19031
+ readOnlyHint: "Adds an existing tag to selected flows and skips flows already carrying it."
19032
+ },
18764
19033
  annotations: {
18765
19034
  destructiveHint: false,
18766
19035
  openWorldHint: false,
@@ -18815,6 +19084,11 @@ var makeListFlowsContract = (ids) => {
18815
19084
  }))
18816
19085
  });
18817
19086
  return {
19087
+ annotationJustifications: {
19088
+ destructiveHint: "Does not change flow code, readiness or tags.",
19089
+ openWorldHint: "Reads flow records without pushing code or executing application actions.",
19090
+ readOnlyHint: "Lists flows at an environment's reconciled commit or on a selected AI task branch."
19091
+ },
18818
19092
  annotations: {
18819
19093
  destructiveHint: false,
18820
19094
  openWorldHint: false,
@@ -18841,6 +19115,11 @@ var makeRemoveTagFromFlowsContract = (ids) => {
18841
19115
  })
18842
19116
  });
18843
19117
  return {
19118
+ annotationJustifications: {
19119
+ destructiveHint: "Deletes existing tag associations and skips flows that do not carry the tag.",
19120
+ openWorldHint: "Changes private flow-tag associations without updating external services.",
19121
+ readOnlyHint: "Removes a selected tag from specified flows."
19122
+ },
18844
19123
  annotations: {
18845
19124
  destructiveHint: true,
18846
19125
  openWorldHint: false,
@@ -18870,6 +19149,11 @@ var makeUpdateFlowContract = (ids) => {
18870
19149
  })
18871
19150
  });
18872
19151
  return {
19152
+ annotationJustifications: {
19153
+ destructiveHint: "Overwrites readiness and can deactivate a flow that was active.",
19154
+ openWorldHint: "Changes private readiness state without itself executing the flow or publishing code.",
19155
+ readOnlyHint: "Changes a flow between draft and active readiness."
19156
+ },
18873
19157
  annotations: {
18874
19158
  destructiveHint: true,
18875
19159
  openWorldHint: false,
@@ -18892,6 +19176,7 @@ var issuePrioritySchema = _enum([
18892
19176
  "urgent"
18893
19177
  ]);
18894
19178
  var issueStatusSchema = _enum([
19179
+ "backlog",
18895
19180
  "pending",
18896
19181
  "inProgress",
18897
19182
  "paused",
@@ -18900,7 +19185,12 @@ var issueStatusSchema = _enum([
18900
19185
  "archived"
18901
19186
  ]);
18902
19187
  var publicIssueTypeSchema = _enum(["bug", "coverageRequest", "maintenance"]);
18903
- var openIssueStatuses = ["pending", "inProgress", "paused"];
19188
+ var openIssueStatuses = [
19189
+ "backlog",
19190
+ "pending",
19191
+ "inProgress",
19192
+ "paused"
19193
+ ];
18904
19194
  var makeIssueResourceSchema = (ids) => resource({
18905
19195
  coveredFlowIds: array(ids.flow).describe("The flows a coverage request covers. Always empty on bug and maintenance reports, whose flows are listed under reproductions."),
18906
19196
  createdAt: exports_coerce.date().describe("When the issue was created."),
@@ -18922,7 +19212,7 @@ var makeIssueResourceSchema = (ids) => resource({
18922
19212
  var makeFindIssuesContract = (ids) => {
18923
19213
  const input = object({
18924
19214
  ...makePaginationInputFields({ defaultLimit: 20, maxLimit: 100 }),
18925
- statuses: array(issueStatusSchema).min(1).default([...openIssueStatuses]).describe("Issue statuses to include. Defaults to pending, in-progress, and paused issues."),
19215
+ statuses: array(issueStatusSchema).min(1).default([...openIssueStatuses]).describe("Issue statuses to include. Defaults to backlog, pending, in-progress, and paused issues."),
18926
19216
  type: publicIssueTypeSchema.describe("The issue type to include: bug report, maintenance report, or coverage request."),
18927
19217
  workspaceId: ids.workspace.optional().describe("The workspace whose issues to list. Required when authenticating with an organization or user API key.")
18928
19218
  });
@@ -18931,6 +19221,11 @@ var makeFindIssuesContract = (ids) => {
18931
19221
  nextCursor: nextCursorSchema
18932
19222
  });
18933
19223
  return {
19224
+ annotationJustifications: {
19225
+ destructiveHint: "Does not edit issue details, statuses or coverage associations.",
19226
+ openWorldHint: "Reads QA Wolf issue records without publishing updates to linked trackers.",
19227
+ readOnlyHint: "Lists workspace bug reports, maintenance reports or coverage requests."
19228
+ },
18934
19229
  annotations: {
18935
19230
  destructiveHint: false,
18936
19231
  openWorldHint: false,
@@ -18951,6 +19246,11 @@ var makeGetIssueContract = (ids) => {
18951
19246
  issue: makeIssueResourceSchema(ids)
18952
19247
  });
18953
19248
  return {
19249
+ annotationJustifications: {
19250
+ destructiveHint: "Does not modify or remove the issue.",
19251
+ openWorldHint: "Reads the QA Wolf issue without changing linked external systems.",
19252
+ readOnlyHint: "Retrieves one issue and its associated details."
19253
+ },
18954
19254
  annotations: {
18955
19255
  destructiveHint: false,
18956
19256
  openWorldHint: false,
@@ -18968,11 +19268,22 @@ var makeGetIssueContract = (ids) => {
18968
19268
  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.';
18969
19269
  var makeInvestigationFindingSchema = (ids) => object({
18970
19270
  actual: string2().optional(),
18971
- commitHash: string2().optional(),
19271
+ commitHash: string2().optional().describe("The commit of a commit fix. Same as `fix.commitHash`."),
18972
19272
  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."),
18973
19273
  disputeReason: string2().optional().describe("Why a person disputed what the AI did. Present on a proposal the AI made again after that dispute."),
18974
19274
  expected: string2().optional(),
18975
19275
  findingId: string2(),
19276
+ fix: discriminatedUnion("type", [
19277
+ object({
19278
+ commitHash: string2().describe("The commit that changes the flow code."),
19279
+ type: literal("commit")
19280
+ }),
19281
+ object({
19282
+ baselineChangeId: string2().optional().describe('The baseline change that made the new screenshot the baseline, on a "fixed" finding. `run restoreScreenshotBaseline` undoes it.'),
19283
+ comparisonId: string2().describe("The failed screenshot comparison whose new screenshot becomes the baseline, as `run listScreenshotComparisons` names it."),
19284
+ type: literal("baseline")
19285
+ })
19286
+ ]).optional().describe('The fix of a "fixed" or "fix-proposed" finding: a commit to the flow code, or a new screenshot baseline.'),
18976
19287
  flowIds: array(ids.flow),
18977
19288
  headline: string2().optional(),
18978
19289
  issueId: ids.issue.optional(),
@@ -18983,8 +19294,9 @@ var makeInvestigationFindingSchema = (ids) => object({
18983
19294
  answers: array(object({
18984
19295
  description: string2().optional(),
18985
19296
  title: string2(),
18986
- value: string2().describe('What choosing this answer means. Known values: "apply", "dismiss", "report", "maintenance" and "bug". New values can appear.')
19297
+ value: string2().describe('What choosing this answer means. Known values: "apply", "dismiss", "report", "maintenance", "bug" and "baseline". New values can appear.')
18987
19298
  })),
19299
+ comparisonId: string2().optional().describe('The failed screenshot comparison a screenshot question is about, as `run listScreenshotComparisons` names it. Its answers are "bug" (the old screenshot is right), "maintenance" (both are right) and "baseline" (the new screenshot is right).'),
18988
19300
  text: string2()
18989
19301
  }).optional().describe("The question waiting for a person, with the answers offered."),
18990
19302
  response: object({
@@ -19004,12 +19316,22 @@ var makeInvestigationFindingSchema = (ids) => object({
19004
19316
  var makeGetInvestigationContract = (ids) => {
19005
19317
  const input = object({ runId: ids.run });
19006
19318
  const output = resource({
19319
+ baselineChanges: _enum(["automatic", "needs-approval"]).describe('How the investigation can make a new screenshot the baseline. "automatic": it can accept a baseline on its own. ' + '"needs-approval": it proposes the baseline on a fix-proposed finding, and accepts it only after a person applies the proposal.'),
19007
19320
  findings: array(makeInvestigationFindingSchema(ids)),
19008
19321
  runId: ids.run,
19009
19322
  sessionId: ids.chatSession.optional().describe("The investigation session. Absent when the run has none."),
19010
- status: _enum(["investigating", "finished", "not-investigated"]).describe('Whether the investigation session is still working. "not-investigated" when the run has no investigation.')
19323
+ status: _enum(["investigating", "finished", "not-investigated"]).describe('Whether the lead or any child investigator is still working. "not-investigated" when the run has no investigation.'),
19324
+ subSessions: array(object({
19325
+ sessionId: ids.chatSession,
19326
+ status: agentSessionStatusSchema
19327
+ })).optional().describe("All child investigators, including sessions not attached to findings yet. Send instructions to each sessionId with agent.send.")
19011
19328
  }, { urlFieldDescription: "The run in the QA Wolf app." });
19012
19329
  return {
19330
+ annotationJustifications: {
19331
+ destructiveHint: "Does not answer, dispute or change the investigation.",
19332
+ openWorldHint: "Reads recorded QA Wolf findings without changing the application under test.",
19333
+ readOnlyHint: "Retrieves an investigation's findings, open questions and pending answers."
19334
+ },
19013
19335
  annotations: {
19014
19336
  destructiveHint: false,
19015
19337
  openWorldHint: false,
@@ -19038,6 +19360,11 @@ var makeAddFlowsToIssueContract = (ids) => {
19038
19360
  issue: makeIssueResourceSchema(ids)
19039
19361
  });
19040
19362
  return {
19363
+ annotationJustifications: {
19364
+ destructiveHint: "Adds coverage associations without removing existing ones.",
19365
+ openWorldHint: "Changes private coverage associations without publishing an external issue update.",
19366
+ readOnlyHint: "Adds existing flows to a coverage request's covered-flow set."
19367
+ },
19041
19368
  annotations: {
19042
19369
  destructiveHint: false,
19043
19370
  openWorldHint: false,
@@ -19081,6 +19408,11 @@ var makeCreateIssueContract = (ids) => {
19081
19408
  issue: makeIssueResourceSchema(ids)
19082
19409
  });
19083
19410
  return {
19411
+ annotationJustifications: {
19412
+ destructiveHint: "Configured notifications can send irreversible messages even though the QA Wolf issue itself is new.",
19413
+ openWorldHint: "Issue creation can send messages or synchronize records through connected communication and issue-tracking services.",
19414
+ readOnlyHint: "Creates a bug or coverage request and can start configured issue notifications."
19415
+ },
19084
19416
  annotations: {
19085
19417
  destructiveHint: true,
19086
19418
  openWorldHint: true,
@@ -19097,19 +19429,25 @@ var makeCreateIssueContract = (ids) => {
19097
19429
  // node_modules/@qawolf/api-contracts/dist/v1/issue/removeFlows.js
19098
19430
  var makeRemoveFlowsFromIssueContract = (ids) => {
19099
19431
  const input = object({
19100
- 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."),
19432
+ environmentId: ids.environment.optional().describe("The environment whose bug or maintenance reproductions to remove. Required when a selected flow is linked in more than one environment."),
19433
+ flowIds: array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The flows to remove from the issue."),
19101
19434
  issueId: ids.issue
19102
19435
  });
19103
19436
  const output = object({
19104
19437
  issue: makeIssueResourceSchema(ids)
19105
19438
  });
19106
19439
  return {
19440
+ annotationJustifications: {
19441
+ destructiveHint: "Deletes existing coverage associations while leaving already-unassociated flows unchanged.",
19442
+ openWorldHint: "Changes private coverage associations without publishing to an external tracker.",
19443
+ readOnlyHint: "Removes selected flows from a coverage request's covered-flow set."
19444
+ },
19107
19445
  annotations: {
19108
19446
  destructiveHint: true,
19109
- openWorldHint: false,
19447
+ openWorldHint: true,
19110
19448
  readOnlyHint: false
19111
19449
  },
19112
- 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.",
19450
+ description: "Remove flows from a coverage request or remove bug/maintenance reproductions in an environment. " + "Unlinked flows are left alone. Reports auto-close when no active reproductions remain and auto-close is enabled. " + "For reports, omit environmentId only when each selected flow is linked in at most one environment.",
19113
19451
  input,
19114
19452
  kind: "write",
19115
19453
  name: "issue.removeFlows",
@@ -19134,6 +19472,11 @@ var makeUpdateIssueContract = (ids) => {
19134
19472
  issue: makeIssueResourceSchema(ids)
19135
19473
  });
19136
19474
  return {
19475
+ annotationJustifications: {
19476
+ destructiveHint: "Can overwrite existing issue fields or send irreversible integration messages.",
19477
+ openWorldHint: "Issue changes can update connected issue trackers and communication services.",
19478
+ readOnlyHint: "Updates issue details, priority or status and can trigger integration updates."
19479
+ },
19137
19480
  annotations: {
19138
19481
  destructiveHint: true,
19139
19482
  openWorldHint: true,
@@ -19210,6 +19553,11 @@ var makeFindLegacyTriggersContract = (ids) => {
19210
19553
  legacyTriggers: array(makeLegacyTriggerSchema(ids)).describe("The workspace's legacy triggers, by name.")
19211
19554
  });
19212
19555
  return {
19556
+ annotationJustifications: {
19557
+ destructiveHint: "Does not pause, resume or change any trigger.",
19558
+ openWorldHint: "Reads private QA Wolf trigger configuration without starting external work.",
19559
+ readOnlyHint: "Lists a workspace's legacy per-environment triggers."
19560
+ },
19213
19561
  annotations: {
19214
19562
  destructiveHint: false,
19215
19563
  openWorldHint: false,
@@ -19234,6 +19582,11 @@ var makeLifecycleShape = (ids) => ({
19234
19582
  var makePauseLegacyTriggerContract = (ids) => {
19235
19583
  const { input, output } = makeLifecycleShape(ids);
19236
19584
  return {
19585
+ annotationJustifications: {
19586
+ destructiveHint: "Disables future automatic execution for the legacy trigger and its pull request copies until it is resumed.",
19587
+ openWorldHint: "Changes private QA Wolf scheduling state without starting external work.",
19588
+ readOnlyHint: "Pauses an existing legacy trigger so it stops starting new work."
19589
+ },
19237
19590
  annotations: {
19238
19591
  destructiveHint: true,
19239
19592
  openWorldHint: false,
@@ -19249,6 +19602,11 @@ var makePauseLegacyTriggerContract = (ids) => {
19249
19602
  var makeResumeLegacyTriggerContract = (ids) => {
19250
19603
  const { input, output } = makeLifecycleShape(ids);
19251
19604
  return {
19605
+ annotationJustifications: {
19606
+ destructiveHint: "Enables automatic test execution that can overwrite or delete application data.",
19607
+ openWorldHint: "Resumed execution can change the application under test and update connected integrations.",
19608
+ readOnlyHint: "Reactivates a legacy trigger and its pull request copies so future schedules or deployments can start runs."
19609
+ },
19252
19610
  annotations: {
19253
19611
  destructiveHint: true,
19254
19612
  openWorldHint: true,
@@ -19269,6 +19627,54 @@ var makeLegacyTriggerContracts = (ids) => ({
19269
19627
  resume: makeResumeLegacyTriggerContract(ids)
19270
19628
  });
19271
19629
 
19630
+ // node_modules/@qawolf/api-contracts/dist/v1/run/investigationSessionId.js
19631
+ var investigationSessionId = string2().trim().min(1).max(100).optional();
19632
+
19633
+ // node_modules/@qawolf/api-contracts/dist/v1/run/acceptScreenshotBaseline.js
19634
+ var makeAcceptScreenshotBaselineContract = (ids) => {
19635
+ const input = object({
19636
+ chatSessionId: investigationSessionId.describe("The chat session of the investigation that accepts the baseline. A workspace or organization API key acts as an automation, so it must send the session that investigates the run. A person's call ignores it."),
19637
+ comparisonId: string2().trim().min(1).max(100).describe("The failed screenshot comparison whose new screenshot becomes the baseline, as `run.listScreenshotComparisons` names it."),
19638
+ runId: ids.run
19639
+ });
19640
+ const output = discriminatedUnion("outcome", [
19641
+ object({
19642
+ baselineChangeId: string2().describe("The baseline change. Record it on the fixed finding, and pass it to `run.restoreScreenshotBaseline` with this runId to put the old baseline back."),
19643
+ name: string2().describe("The screenshot name whose baseline changed."),
19644
+ outcome: literal("accepted").describe("The new screenshot is now the baseline. The old baseline is kept, so the change can be restored.")
19645
+ }),
19646
+ object({
19647
+ outcome: literal("baseline-changed").describe("The baseline is no longer the one the run compared with: someone changed or deleted it since. Nothing changed. List the comparisons again to see the current baseline.")
19648
+ }),
19649
+ object({
19650
+ outcome: literal("needs-approval").describe("Only a person can approve this change. Nothing changed. Propose the new baseline on a fix-proposed finding and wait for a person to apply it.")
19651
+ }),
19652
+ object({
19653
+ outcome: literal("not-investigation-session").describe("An API key that is not a person's can change a baseline only as the investigation of the run, and chatSessionId is missing or is not the session that investigates the run. Nothing changed.")
19654
+ }),
19655
+ object({
19656
+ outcome: literal("nothing-to-accept").describe("The comparison did not fail, or has no new screenshot to accept. Nothing changed.")
19657
+ })
19658
+ ]);
19659
+ return {
19660
+ annotationJustifications: {
19661
+ destructiveHint: "Replaces the workspace's screenshot baseline, which changes what every later run compares with.",
19662
+ openWorldHint: "Changes private QA Wolf baseline storage without starting external work.",
19663
+ readOnlyHint: "Makes the new screenshot of a failed comparison the baseline."
19664
+ },
19665
+ annotations: {
19666
+ destructiveHint: true,
19667
+ openWorldHint: false,
19668
+ readOnlyHint: false
19669
+ },
19670
+ description: "Make the new screenshot of a failed screenshot comparison the baseline, so later runs compare with it. " + "Use it only when the difference is an intended change of the app, not a bug, noise, or a page that was not ready. " + "Every later run of every environment of the workspace compares with the new baseline. " + "Refuses without changing anything when the baseline changed since the run.",
19671
+ input,
19672
+ kind: "write",
19673
+ name: "run.acceptScreenshotBaseline",
19674
+ output
19675
+ };
19676
+ };
19677
+
19272
19678
  // node_modules/@qawolf/api-contracts/dist/v1/run/diagnose.js
19273
19679
  var makeDiagnoseRunContract = (ids) => {
19274
19680
  const input = object({
@@ -19280,12 +19686,17 @@ var makeDiagnoseRunContract = (ids) => {
19280
19686
  issue: makeIssueResourceSchema(ids)
19281
19687
  });
19282
19688
  return {
19689
+ annotationJustifications: {
19690
+ destructiveHint: "Can replace a flow's existing diagnosis association and change externally reported run information.",
19691
+ openWorldHint: "Recorded diagnosis changes can update run-related messages in configured external integrations.",
19692
+ readOnlyHint: "Records failed flows as reproductions of a selected bug or maintenance issue."
19693
+ },
19283
19694
  annotations: {
19284
19695
  destructiveHint: true,
19285
19696
  openWorldHint: true,
19286
19697
  readOnlyHint: false
19287
19698
  },
19288
- description: "Diagnose failed flows in a run as reproductions of a bug or maintenance report owned by the caller's team. " + "The issue's type selects the diagnosis. " + "Each flow must have failed in the run. " + "A flow that is already diagnosed moves to this issue. " + "The diagnosis appears on the run, and the reproduction appears under the issue's reproductions. " + "Coverage requests cannot be diagnosed; use issue.addFlows to cover flows instead.",
19699
+ description: "Diagnose failed flows in a run as reproductions of a bug or maintenance report owned by the caller's team. " + "The issue's type selects the diagnosis. " + "Each flow must have failed in the run. " + "A flow that is already diagnosed in the run moves to this issue, and may stay linked to other open reports. " + "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.",
19289
19700
  input,
19290
19701
  kind: "write",
19291
19702
  name: "run.diagnose",
@@ -19310,6 +19721,11 @@ var makeFindRunsContract = (ids) => {
19310
19721
  }, { urlFieldDescription: "Absolute URL of the run page." })).describe("The environment's runs, newest first. Per-flow results are available via run.get.")
19311
19722
  });
19312
19723
  return {
19724
+ annotationJustifications: {
19725
+ destructiveHint: "Does not stop runs, overwrite results or change diagnoses.",
19726
+ openWorldHint: "Reads private run records without executing application actions.",
19727
+ readOnlyHint: "Lists recent environment runs without starting or retrying them."
19728
+ },
19313
19729
  annotations: {
19314
19730
  destructiveHint: false,
19315
19731
  openWorldHint: false,
@@ -19323,6 +19739,22 @@ var makeFindRunsContract = (ids) => {
19323
19739
  };
19324
19740
  };
19325
19741
 
19742
+ // node_modules/@qawolf/api-contracts/dist/v1/run/flowFailure.js
19743
+ var makeFlowFailureSchema = (ids) => {
19744
+ const diagnosis = object({
19745
+ issueId: ids.issue,
19746
+ type: _enum(["bug", "maintenance"])
19747
+ }).optional().describe("QA Wolf's investigation verdict for the failure: `bug` means the " + "application is broken, `maintenance` means the test needed an " + "update and the failure does not indicate an application problem. " + "Absent until the investigation reaches a verdict, and absent when " + "the flow was opted out of investigation. Pass issueId to issue.get " + "for details.");
19748
+ const optedOutOfInvestigation = object({
19749
+ by: _enum(["user", "system"]).describe("Who stopped the investigation: `user` is a person, in the app or " + "with a user API key, or the workspace's automation user for a " + "team or organization API key, for example through " + "run.optOutOfInvestigation; `system` is QA Wolf, when the " + "investigation expired.")
19750
+ }).optional().describe('Present when the failure was marked "do not investigate" (DNI): ' + "it will get no bug or maintenance verdict.");
19751
+ return object({
19752
+ diagnosis,
19753
+ error: string2(),
19754
+ optedOutOfInvestigation
19755
+ });
19756
+ };
19757
+
19326
19758
  // node_modules/@qawolf/api-contracts/dist/v1/run/get.js
19327
19759
  var makeGetRunContract = (ids) => {
19328
19760
  const flowStatus = _enum(publicRunStatusValues);
@@ -19355,6 +19787,7 @@ var makeGetRunContract = (ids) => {
19355
19787
  }),
19356
19788
  object({
19357
19789
  attemptId: ids.runAttempt.optional(),
19790
+ canceledReason: string2().min(1).optional().describe("Why the attempt was canceled. userCanceled means a person stopped it; do not immediately retry that activity."),
19358
19791
  completedAt: exports_iso.datetime().optional(),
19359
19792
  kind: automatedKind,
19360
19793
  startedAt: exports_iso.datetime().optional(),
@@ -19370,16 +19803,9 @@ var makeGetRunContract = (ids) => {
19370
19803
  });
19371
19804
  const attempt = union([automatedAttempt, manualAttempt]);
19372
19805
  const attempts = array(attempt).optional().describe("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.");
19373
- const diagnosis = object({
19374
- issueId: ids.issue,
19375
- type: _enum(["bug", "maintenance"])
19376
- }).optional().describe("QA Wolf's investigation verdict for the failure: `bug` means the " + "application is broken, `maintenance` means the test needed an " + "update and the failure does not indicate an application problem. " + "Absent until the investigation reaches a verdict. Pass issueId to " + "issue.get for details.");
19377
19806
  const failedFlow = object({
19378
19807
  attempts,
19379
- failure: object({
19380
- diagnosis,
19381
- error: string2()
19382
- }),
19808
+ failure: makeFlowFailureSchema(ids),
19383
19809
  flowId: ids.flow,
19384
19810
  name: string2(),
19385
19811
  status: literal("failed")
@@ -19398,6 +19824,11 @@ var makeGetRunContract = (ids) => {
19398
19824
  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.")
19399
19825
  }, { urlFieldDescription: "Absolute URL of the run page." });
19400
19826
  return {
19827
+ annotationJustifications: {
19828
+ destructiveHint: "Does not retry, cancel or alter the run.",
19829
+ openWorldHint: "Reads recorded QA Wolf results without changing the application under test.",
19830
+ readOnlyHint: "Retrieves a run's status, per-flow results and result links."
19831
+ },
19401
19832
  annotations: {
19402
19833
  destructiveHint: false,
19403
19834
  openWorldHint: false,
@@ -19475,6 +19906,11 @@ var makeGetRunAttemptArtifactsContract = (ids) => {
19475
19906
  })
19476
19907
  ]);
19477
19908
  return {
19909
+ annotationJustifications: {
19910
+ destructiveHint: "Does not retry, cancel or alter the run attempt.",
19911
+ openWorldHint: "Reads recorded QA Wolf artifacts without changing the application under test.",
19912
+ readOnlyHint: "Retrieves a finished attempt's metadata and signed artifact URLs."
19913
+ },
19478
19914
  annotations: {
19479
19915
  destructiveHint: false,
19480
19916
  openWorldHint: false,
@@ -19488,6 +19924,35 @@ var makeGetRunAttemptArtifactsContract = (ids) => {
19488
19924
  };
19489
19925
  };
19490
19926
 
19927
+ // node_modules/@qawolf/api-contracts/dist/v1/run/optOutOfInvestigation.js
19928
+ var makeOptOutOfInvestigationRunContract = (ids) => {
19929
+ const input = object({
19930
+ flowIds: array(ids.flow).min(1).max(100).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").describe("The failed flows to stop investigating. Every named flow must be " + "eligible or the whole request is rejected."),
19931
+ runId: ids.run
19932
+ });
19933
+ const output = resource({
19934
+ optedOutFlowIds: array(ids.flow).describe("The flows that no longer need investigation."),
19935
+ runId: ids.run
19936
+ }, { urlFieldDescription: "Absolute URL of the run page." });
19937
+ return {
19938
+ annotationJustifications: {
19939
+ destructiveHint: "Ends the investigation of the selected failures and changes externally reported run information.",
19940
+ openWorldHint: "Recorded opt-outs can update run-related messages in configured external integrations.",
19941
+ readOnlyHint: "Records failed flows as needing no bug or maintenance report."
19942
+ },
19943
+ annotations: {
19944
+ destructiveHint: true,
19945
+ openWorldHint: true,
19946
+ readOnlyHint: false
19947
+ },
19948
+ description: 'Mark failed flows in a run as "do not investigate" (DNI): the failures need no bug or maintenance report. ' + "Each flow must have failed in the run and still be under investigation. " + "A flow that already has a diagnosis cannot be opted out. " + "A team or organization key records the opt-out as the workspace's automation user. " + "To link a failure to a report instead, use run.diagnose.",
19949
+ input,
19950
+ kind: "write",
19951
+ name: "run.optOutOfInvestigation",
19952
+ output
19953
+ };
19954
+ };
19955
+
19491
19956
  // node_modules/@qawolf/api-contracts/dist/v1/run/reattempt.js
19492
19957
  var makeReattemptRunContract = (ids) => {
19493
19958
  const input = object({
@@ -19499,6 +19964,11 @@ var makeReattemptRunContract = (ids) => {
19499
19964
  runId: ids.run
19500
19965
  }, { urlFieldDescription: "Absolute URL of the run page." });
19501
19966
  return {
19967
+ annotationJustifications: {
19968
+ destructiveHint: "Repeated execution can overwrite or delete application data and creates additional billed work.",
19969
+ openWorldHint: "New attempts execute against the application under test and can affect connected services.",
19970
+ readOnlyHint: "Enqueues new attempts for eligible failed or canceled flows using the latest code."
19971
+ },
19502
19972
  annotations: {
19503
19973
  destructiveHint: true,
19504
19974
  openWorldHint: true,
@@ -19512,6 +19982,50 @@ var makeReattemptRunContract = (ids) => {
19512
19982
  };
19513
19983
  };
19514
19984
 
19985
+ // node_modules/@qawolf/api-contracts/dist/v1/run/restoreScreenshotBaseline.js
19986
+ var makeRestoreScreenshotBaselineContract = (ids) => {
19987
+ const input = object({
19988
+ baselineChangeId: string2().trim().min(1).max(100).describe("The baseline change to undo, as `run.acceptScreenshotBaseline` returned it for this run."),
19989
+ chatSessionId: investigationSessionId.describe("The chat session of the investigation that restores the baseline. A workspace or organization API key acts as an automation, so it must send the session that investigates the run. A person's call ignores it."),
19990
+ runId: ids.run
19991
+ });
19992
+ const output = discriminatedUnion("outcome", [
19993
+ object({
19994
+ name: string2().describe("The screenshot name whose baseline changed."),
19995
+ outcome: literal("restored").describe("The baseline the change replaced is the baseline again.")
19996
+ }),
19997
+ object({
19998
+ outcome: literal("baseline-changed").describe("The baseline changed again after this change, so restoring it would undo someone else's change. Nothing changed.")
19999
+ }),
20000
+ object({
20001
+ outcome: literal("needs-dispute").describe("Only a person can restore this change, unless a person disputed the finding that made it. Nothing changed.")
20002
+ }),
20003
+ object({
20004
+ outcome: literal("not-investigation-session").describe("An API key that is not a person's can change a baseline only as the investigation of the run, and chatSessionId is missing or is not the session that investigates the run. Nothing changed.")
20005
+ }),
20006
+ object({
20007
+ outcome: literal("nothing-to-restore").describe("The change was already restored, the name had no baseline before it, or the kept copy of the old baseline is missing or is not the baseline the change replaced. Nothing changed.")
20008
+ })
20009
+ ]);
20010
+ return {
20011
+ annotationJustifications: {
20012
+ destructiveHint: "Replaces the current screenshot baseline with the one it replaced, which changes what every later run compares with.",
20013
+ openWorldHint: "Changes private QA Wolf baseline storage without starting external work.",
20014
+ readOnlyHint: "Puts back the screenshot baseline that an accepted comparison replaced."
20015
+ },
20016
+ annotations: {
20017
+ destructiveHint: true,
20018
+ openWorldHint: false,
20019
+ readOnlyHint: false
20020
+ },
20021
+ description: "Undo a screenshot baseline change that accepted a failed comparison of the run: put back the baseline it replaced, so later runs compare with the old baseline again. " + "Use it when a person disputes a baseline the AI accepted. " + "Refuses without changing anything when the baseline changed again since.",
20022
+ input,
20023
+ kind: "write",
20024
+ name: "run.restoreScreenshotBaseline",
20025
+ output
20026
+ };
20027
+ };
20028
+
19515
20029
  // node_modules/@qawolf/api-contracts/dist/v1/run/stop.js
19516
20030
  var makeStopRunContract = (ids) => {
19517
20031
  const input = object({ runId: ids.run });
@@ -19520,6 +20034,11 @@ var makeStopRunContract = (ids) => {
19520
20034
  status: _enum(["accepted", "already-finished", "execution-not-found"]).describe('"accepted" means stopping was requested; poll run.get for the final result. "already-finished" means the run has already finished and its result is unchanged. "execution-not-found" means the run exists but no execution was found to stop; it may still be starting or may no longer be available. No stop request was accepted in that case.')
19521
20035
  }, { urlFieldDescription: "Absolute URL of the run page." });
19522
20036
  return {
20037
+ annotationJustifications: {
20038
+ destructiveHint: "Interrupts unfinished work, while finished results remain intact and repeated stop requests are supported.",
20039
+ openWorldHint: "Run status changes can update messages or commit statuses in configured external integrations.",
20040
+ readOnlyHint: "Requests asynchronous cancellation of a run, queued flows and automatic retries."
20041
+ },
19523
20042
  annotations: {
19524
20043
  destructiveHint: true,
19525
20044
  openWorldHint: true,
@@ -19558,6 +20077,11 @@ var makeEvaluateSnippetOnRunnerContract = (ids) => {
19558
20077
  ])
19559
20078
  ]);
19560
20079
  return {
20080
+ annotationJustifications: {
20081
+ destructiveHint: "Code can overwrite or delete runner or application data, and a timeout does not prove execution stopped.",
20082
+ openWorldHint: "Supplied code can submit application actions or contact and change external services.",
20083
+ readOnlyHint: "Executes supplied code against the interactive runner's current session."
20084
+ },
19561
20085
  annotations: {
19562
20086
  destructiveHint: true,
19563
20087
  openWorldHint: true,
@@ -19591,6 +20115,11 @@ var makeGetRunnerContract = (ids) => {
19591
20115
  })
19592
20116
  ]);
19593
20117
  return {
20118
+ annotationJustifications: {
20119
+ destructiveHint: "Does not stop the runner or change its execution.",
20120
+ openWorldHint: "Reads private runner placement state without acting on external applications.",
20121
+ readOnlyHint: "Checks whether a runner exists without starting it or refreshing its inactivity timer."
20122
+ },
19594
20123
  annotations: {
19595
20124
  destructiveHint: false,
19596
20125
  openWorldHint: false,
@@ -19634,6 +20163,11 @@ var makeHighlightSelectorOnRunnerContract = (ids) => {
19634
20163
  })
19635
20164
  ]);
19636
20165
  return {
20166
+ annotationJustifications: {
20167
+ destructiveHint: "Only replaces or clears the inspection overlay rather than deleting application data.",
20168
+ openWorldHint: "Draws a private inspection overlay without submitting an application form.",
20169
+ readOnlyHint: "Changes the visual selector highlight on the runner's live page."
20170
+ },
19637
20171
  annotations: {
19638
20172
  destructiveHint: false,
19639
20173
  openWorldHint: false,
@@ -19667,6 +20201,11 @@ var makeImportPackageOnRunnerContract = (ids) => {
19667
20201
  })
19668
20202
  ]);
19669
20203
  return {
20204
+ annotationJustifications: {
20205
+ destructiveHint: "Can replace existing dependencies or execute commands that overwrite or delete runner or application data.",
20206
+ openWorldHint: "Installation can contact external services and execute commands that change third-party systems.",
20207
+ readOnlyHint: "Installs caller-selected dependencies into a live runner and can execute commands with the runner's access."
20208
+ },
19670
20209
  annotations: {
19671
20210
  destructiveHint: true,
19672
20211
  openWorldHint: true,
@@ -19696,9 +20235,14 @@ var makeLaunchRunnerContract = (ids) => {
19696
20235
  outcome: literal("success")
19697
20236
  });
19698
20237
  return {
20238
+ annotationJustifications: {
20239
+ destructiveHint: "Starts billable resource consumption that cannot be undone by later termination.",
20240
+ openWorldHint: "Allocates a private QA Wolf runner without itself navigating to an application or submitting forms.",
20241
+ readOnlyHint: "Starts an interactive runner and allocates billed resources unless the requested runner is already running."
20242
+ },
19699
20243
  annotations: {
19700
20244
  destructiveHint: true,
19701
- openWorldHint: false,
20245
+ openWorldHint: true,
19702
20246
  readOnlyHint: false
19703
20247
  },
19704
20248
  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.",
@@ -19719,6 +20263,11 @@ var makeTerminateRunnerContract = (ids) => {
19719
20263
  wasRunning: boolean2().describe("False when no running runner had this id: it was already terminated, was never launched, or terminated on its own after inactivity. These are not distinguished, because the run system keeps no record of a runner once it is gone. Not an error, and a retry needs no special handling.")
19720
20264
  });
19721
20265
  return {
20266
+ annotationJustifications: {
20267
+ destructiveHint: "Terminates running work and discards the live session, while an absent runner is left absent.",
20268
+ openWorldHint: "Stops a private QA Wolf runner without itself publishing to third-party services.",
20269
+ readOnlyHint: "Ends a selected interactive runner and the resources hosting it."
20270
+ },
19722
20271
  annotations: {
19723
20272
  destructiveHint: true,
19724
20273
  openWorldHint: false,
@@ -19742,6 +20291,11 @@ var makeListRunnersContract = (ids) => {
19742
20291
  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.")
19743
20292
  });
19744
20293
  return {
20294
+ annotationJustifications: {
20295
+ destructiveHint: "Does not interrupt or terminate any listed runner.",
20296
+ openWorldHint: "Reads private runner state without acting on third-party applications.",
20297
+ readOnlyHint: "Lists running workspace runners without starting them or refreshing their inactivity timers."
20298
+ },
19745
20299
  annotations: {
19746
20300
  destructiveHint: false,
19747
20301
  openWorldHint: false,
@@ -19776,6 +20330,11 @@ var makePromoteSnapshotOnRunnerContract = (ids) => {
19776
20330
  })
19777
20331
  ]);
19778
20332
  return {
20333
+ annotationJustifications: {
20334
+ destructiveHint: "Overwrites an existing baseline, while a missing source snapshot leaves it unchanged.",
20335
+ openWorldHint: "Updates a stored test baseline rather than publishing to an external application.",
20336
+ readOnlyHint: "Replaces a named image-diff baseline with a screenshot produced by the runner."
20337
+ },
19779
20338
  annotations: {
19780
20339
  destructiveHint: true,
19781
20340
  openWorldHint: false,
@@ -19801,6 +20360,11 @@ var makeReadRunnerJournalContract = (ids) => {
19801
20360
  makeRunnerFailureSchema([runnerUnreachableFailureReason])
19802
20361
  ]);
19803
20362
  return {
20363
+ annotationJustifications: {
20364
+ destructiveHint: "Does not erase journal entries or change run results, although the activity refresh can extend billed runtime.",
20365
+ openWorldHint: "Reads private runner history without submitting actions to external applications.",
20366
+ readOnlyHint: "Retrieves journal entries and refreshes activity, which can cancel an inactivity shutdown."
20367
+ },
19804
20368
  annotations: {
19805
20369
  destructiveHint: false,
19806
20370
  openWorldHint: false,
@@ -19832,7 +20396,7 @@ var makeRunFlowOnRunnerContract = (ids) => {
19832
20396
  env: runEnvironmentSchema.optional().describe("Environment variables to make available to the run."),
19833
20397
  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."),
19834
20398
  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."),
19835
- 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`."),
20399
+ 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. Omitted, the flow whose file is at `entryPointPath` on the named environment's flow-code branch stands in; a file not in QA Wolf yet, or a run given no environment, leaves the run with no `QAWOLF_WORKFLOW_ID`."),
19836
20400
  id: runnerIdSchema.describe("Id of the runner to run the flow on."),
19837
20401
  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."),
19838
20402
  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."),
@@ -19879,6 +20443,11 @@ var makeRunFlowOnRunnerContract = (ids) => {
19879
20443
  failure
19880
20444
  ]);
19881
20445
  return {
20446
+ annotationJustifications: {
20447
+ destructiveHint: "Test code can overwrite or delete application data, and uncertain acceptance must be checked before resubmission.",
20448
+ openWorldHint: "Executed tests can submit forms and change the application under test or its connected services.",
20449
+ readOnlyHint: "Submits test files for full-flow or selected-line execution on an interactive runner."
20450
+ },
19882
20451
  annotations: {
19883
20452
  destructiveHint: true,
19884
20453
  openWorldHint: true,
@@ -19906,6 +20475,11 @@ var makeStopRunOnRunnerContract = (ids) => {
19906
20475
  makeRunnerFailureSchema([runnerUnreachableFailureReason])
19907
20476
  ]);
19908
20477
  return {
20478
+ annotationJustifications: {
20479
+ destructiveHint: "Stops unfinished work where it is, while an already-idle runner is left idle.",
20480
+ openWorldHint: "Changes private execution state without itself posting external messages.",
20481
+ readOnlyHint: "Interrupts current execution while leaving the runner available."
20482
+ },
19909
20483
  annotations: {
19910
20484
  destructiveHint: true,
19911
20485
  openWorldHint: false,
@@ -19936,6 +20510,11 @@ var makeTakeScreenshotOnRunnerContract = (ids) => {
19936
20510
  ])
19937
20511
  ]);
19938
20512
  return {
20513
+ annotationJustifications: {
20514
+ destructiveHint: "Does not change application data or stop execution, although the activity refresh can extend billed runtime.",
20515
+ openWorldHint: "Reads the private runner display without submitting an external application action.",
20516
+ readOnlyHint: "Captures the runner screen and refreshes activity, which can cancel an inactivity shutdown."
20517
+ },
19939
20518
  annotations: {
19940
20519
  destructiveHint: false,
19941
20520
  openWorldHint: false,
@@ -19987,6 +20566,11 @@ var makeListSkillsContract = () => {
19987
20566
  skills: array(skillSummary).describe("Every skill the server serves, in catalog order.")
19988
20567
  });
19989
20568
  return {
20569
+ annotationJustifications: {
20570
+ destructiveHint: "Does not change any skill or workspace data.",
20571
+ openWorldHint: "Reads the QA Wolf skill catalog without calling external services.",
20572
+ readOnlyHint: "Lists the QA Wolf skills with their names and descriptions."
20573
+ },
19990
20574
  annotations: readOnlyAnnotations,
19991
20575
  description: "List the QA Wolf skills, each with its name and the description that says when to use it. A skill is the instructions a coding agent follows for one kind of QA Wolf work, such as onboarding an application, creating a flow, repairing a failing flow, or setting up triggers. Call this before any QA Wolf work, pick the skill whose description matches the request, and read it with skill.get.",
19992
20576
  input,
@@ -20005,6 +20589,11 @@ var makeGetSkillContract = () => {
20005
20589
  })).describe("The files the skill links to under its directory.")
20006
20590
  });
20007
20591
  return {
20592
+ annotationJustifications: {
20593
+ destructiveHint: "Does not change any skill or workspace data.",
20594
+ openWorldHint: "Reads the QA Wolf skill catalog without calling external services.",
20595
+ readOnlyHint: "Retrieves one QA Wolf skill's instructions and reference files."
20596
+ },
20008
20597
  annotations: readOnlyAnnotations,
20009
20598
  description: "Read a QA Wolf skill: the instructions a coding agent follows for one kind of QA Wolf work. The reply carries the skill's SKILL.md and every file under its references directory, so nothing else has to be fetched for it. Read the skill before starting the work it covers and follow it. A link in the reply of the form ../<skill>/SKILL.md names another skill, which this call reads by that name.",
20010
20599
  input,
@@ -20033,6 +20622,11 @@ var makeListTagsContract = (ids) => {
20033
20622
  })).describe("The team's tags, alphabetical by name.")
20034
20623
  });
20035
20624
  return {
20625
+ annotationJustifications: {
20626
+ destructiveHint: "Does not create, rename or remove tags.",
20627
+ openWorldHint: "Reads private tag metadata without changing connected services.",
20628
+ readOnlyHint: "Lists existing workspace tags by name."
20629
+ },
20036
20630
  annotations: {
20037
20631
  destructiveHint: false,
20038
20632
  openWorldHint: false,
@@ -20099,12 +20693,16 @@ var makeContractsV1 = (ids) => {
20099
20693
  },
20100
20694
  legacyTrigger: makeLegacyTriggerContracts(resolvedIds),
20101
20695
  run: {
20696
+ acceptScreenshotBaseline: makeAcceptScreenshotBaselineContract(resolvedIds),
20102
20697
  create: makeCreateRunContract(resolvedIds),
20103
20698
  diagnose: makeDiagnoseRunContract(resolvedIds),
20104
20699
  find: makeFindRunsContract(resolvedIds),
20105
20700
  get: makeGetRunContract(resolvedIds),
20106
20701
  getAttemptArtifacts: makeGetRunAttemptArtifactsContract(resolvedIds),
20702
+ listScreenshotComparisons: makeListScreenshotComparisonsContract(resolvedIds),
20703
+ optOutOfInvestigation: makeOptOutOfInvestigationRunContract(resolvedIds),
20107
20704
  reattempt: makeReattemptRunContract(resolvedIds),
20705
+ restoreScreenshotBaseline: makeRestoreScreenshotBaselineContract(resolvedIds),
20108
20706
  stop: makeStopRunContract(resolvedIds)
20109
20707
  },
20110
20708
  runner: makeRunnerContracts(resolvedIds),
@@ -22621,7 +23219,7 @@ function startUpdateCheck(deps) {
22621
23219
  // package.json
22622
23220
  var package_default = {
22623
23221
  name: "@qawolf/cli",
22624
- version: "1.37.0",
23222
+ version: "1.39.0",
22625
23223
  description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
22626
23224
  keywords: [
22627
23225
  "automation",
@@ -22692,7 +23290,7 @@ var package_default = {
22692
23290
  "@clack/prompts": "1.5.1",
22693
23291
  "@napi-rs/keyring": "1.3.0",
22694
23292
  "@oxc-node/core": "0.1.0",
22695
- "@qawolf/api-contracts": "0.74.0",
23293
+ "@qawolf/api-contracts": "0.81.0",
22696
23294
  "@qawolf/emails": "1.1.1",
22697
23295
  "@qawolf/flow-targets": "1.0.0",
22698
23296
  "@qawolf/flows": "0.1.4",
@@ -36040,6 +36638,11 @@ function describeReason(step) {
36040
36638
  exitCode: exitCodes.invalidArgs,
36041
36639
  why: "has no touchscreen equivalent on a mobile runner."
36042
36640
  };
36641
+ case "action-not-supported-on-browser":
36642
+ return {
36643
+ exitCode: exitCodes.invalidArgs,
36644
+ why: "is a touchscreen action, which only a mobile runner performs."
36645
+ };
36043
36646
  case "screen-needs-a-run":
36044
36647
  return {
36045
36648
  exitCode: exitCodes.invalidArgs,
@@ -36277,19 +36880,13 @@ function buildRunnerAction(type, flags) {
36277
36880
  };
36278
36881
  return parseRunnerAction(candidate);
36279
36882
  }
36280
- function parseWith(schema, candidate) {
36281
- const parsed = schema.safeParse(candidate);
36883
+ function parseRunnerAction(candidate) {
36884
+ const parsed = runnerActionSchema.safeParse(candidate);
36282
36885
  if (!parsed.success) {
36283
36886
  return { error: prettifyError(parsed.error), ok: false };
36284
36887
  }
36285
36888
  return { action: parsed.data, ok: true };
36286
36889
  }
36287
- function parseRunnerAction(candidate) {
36288
- return parseWith(runnerActionSchema, candidate);
36289
- }
36290
- function parseBrowserAction(candidate) {
36291
- return parseWith(browserActionSchema, candidate);
36292
- }
36293
36890
 
36294
36891
  // src/domains/interactiveRunner/readActions.ts
36295
36892
  var stdinArgument = "-";
@@ -36309,7 +36906,7 @@ async function readActions(argument, deps) {
36309
36906
  ok: false
36310
36907
  };
36311
36908
  }
36312
- const built = parsed.items.map(parseBrowserAction);
36909
+ const built = parsed.items.map(parseRunnerAction);
36313
36910
  const firstRefused = built.findIndex((action) => !action.ok);
36314
36911
  const refused = built[firstRefused];
36315
36912
  if (refused !== undefined && !refused.ok) {
@@ -36831,7 +37428,11 @@ Examples:
36831
37428
  $ qawolf runner actions '[{"type":"click","button":"left","x":480,"y":260},{"type":"type","text":"hello@example.com"},{"type":"keypress","keys":["Enter"]}]' --screenshot after-login.jpg
36832
37429
  $ echo '[{"type":"click","button":"left","x":1,"y":2},{"type":"type","text":"hi"}]' | qawolf runner actions -
36833
37430
  $ qawolf runner actions '[{"type":"click","button":"left","x":480,"y":260},{"type":"type","text":"hello"}]' --screenshot-mode each --screenshot step.jpg
36834
- $ qawolf runner actions '[{"type":"scroll","x":480,"y":260,"scroll_x":0,"scroll_y":600},{"type":"click","button":"left","x":120,"y":700}]' --continue-on-failure`;
37431
+ $ qawolf runner actions '[{"type":"scroll","x":480,"y":260,"scroll_x":0,"scroll_y":600},{"type":"click","button":"left","x":120,"y":700}]' --continue-on-failure
37432
+
37433
+ Mobile:
37434
+ $ qawolf runner actions '[{"type":"tap","selector":"//*[@content-desc=\\"Email\\"]"},{"type":"type","text":"hello@example.com"},{"type":"tap","x":540,"y":1650}]' --screenshot after-login.jpg
37435
+ $ qawolf runner actions '[{"type":"fill","selector":"name == \\"Postal code\\"","strategy":"ios-predicate","text":"94107"},{"type":"swipe","from":{"x":540,"y":1600},"to":{"x":540,"y":600}}]'`;
36835
37436
  function registerRunnerActionsCommand(runner, signals) {
36836
37437
  declareCommandKind(runner.command("actions <sequence>"), "write").description("Perform a sequence of up to ten raw actions on a runner's screen in one request, as a JSON array of the same actions `runner act` takes. Use - to read the array from stdin. Actions run back to back, so batch only steps whose targets are on the screen you last saw, and end the sequence at the step that changes the page. Each result carries an effect: performed, not-performed, or unknown when the runner stopped answering and the action may have landed").option("--continue-on-failure", "Carry on past an action that reached the runner and did not take effect; a runner that cannot be reached or a screen that cannot serve still ends the sequence").option("--runner <id>", runnerFlagDescription).option("--screenshot <path>", "Save a JPEG of the screen after the last action to this file. With --screenshot-mode each, one file per action, with the action's index before the extension. - writes the final frame to stdout and moves the confirmation to stderr").addOption(new Option2("--screenshot-mode <mode>", "Defaults to final when --screenshot is given, none otherwise").choices([...screenshotModes])).addHelpText("after", actionsExamples).action((sequence, opts, command) => withAuthContext(signals, (ctx) => handleRunnerActions(ctx, {
36837
37438
  actions: sequence,
@@ -38943,4 +39544,4 @@ createProgram({ signals }).parseAsync().catch(() => {
38943
39544
  process.exitCode = 1;
38944
39545
  }).finally(() => exitWhenIdle(typeof process.exitCode === "number" ? process.exitCode : 0));
38945
39546
 
38946
- //# debugId=0EBF9D8CD8CB2E9E64756E2164756E21
39547
+ //# debugId=1A1CE11EA6A4398C64756E2164756E21