@qawolf/cli 1.13.0 → 1.15.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
@@ -326186,6 +326186,7 @@ var interactiveRunnerMessages = {
326186
326186
  };
326187
326187
  // src/core/messages/runner.ts
326188
326188
  var maxListedNames = 5;
326189
+ var allowNoMatchHint = "Pass --allow-no-match to exit 0 instead.";
326189
326190
  function listNames(names) {
326190
326191
  const shown = names.slice(0, maxListedNames).join(", ");
326191
326192
  const rest = names.length - maxListedNames;
@@ -326195,6 +326196,10 @@ var runnerMessages = {
326195
326196
  playwrightLoadFailed: (envDir, detail) => packageLoadFailed("Playwright", envDir, detail),
326196
326197
  androidWorkersUnsupported: "Android flows are not yet supported with --workers > 1; rerun Android flows with --workers 1.",
326197
326198
  noFlowsMatched: "No flows matched.",
326199
+ noFlowsMatchedPattern: (pattern) => pattern === undefined ? `No flows found. ${allowNoMatchHint}` : `No flows matched '${pattern}'. ${allowNoMatchHint}`,
326200
+ noFlowsMatchedInEnv: (env, pattern) => pattern === undefined ? `No flows found in env '${env}'. ${allowNoMatchHint}` : `No flows matched '${pattern}' in env '${env}'. ${allowNoMatchHint}`,
326201
+ noTargetedFlows: `No matched flow declares a target. ${allowNoMatchHint}`,
326202
+ noRunnableFlows: `No matched flow has a target the CLI can run locally. ${allowNoMatchHint}`,
326198
326203
  androidBootFailed: "Android boot failed",
326199
326204
  preparingEnvironment: "Preparing environment",
326200
326205
  environmentReady: "Environment ready",
@@ -341006,7 +341011,10 @@ var inlineReasonMaxLength = 200;
341006
341011
  function describeIdentityError(err) {
341007
341012
  if (err.kind === "http") {
341008
341013
  if (err.status === 401 || err.status === 403) {
341009
- return { error: m.identity.invalidOrUnauthorized };
341014
+ return {
341015
+ error: m.identity.invalidOrUnauthorized,
341016
+ ...err.status === 401 ? { exitCode: exitCodes.auth } : {}
341017
+ };
341010
341018
  }
341011
341019
  return {
341012
341020
  error: m.identity.couldNotVerify(parseErrorBody(err.body, inlineReasonMaxLength), err.status)
@@ -341025,7 +341033,11 @@ function describeRequestError(err, baseUrl, noun) {
341025
341033
  const reason = parseErrorBody(err.body);
341026
341034
  const body = reason ? { errorBody: reason } : {};
341027
341035
  if (err.status === 401)
341028
- return { error: m.request.rejected401(noun), ...body };
341036
+ return {
341037
+ error: m.request.rejected401(noun),
341038
+ exitCode: exitCodes.auth,
341039
+ ...body
341040
+ };
341029
341041
  if (err.status === 403)
341030
341042
  return { error: m.request.rejected403(noun), ...body };
341031
341043
  if (err.status === 404)
@@ -341074,7 +341086,11 @@ var sleep = (ms) => setTimeout2(ms);
341074
341086
 
341075
341087
  // src/shell/platform/requestWithRetry.ts
341076
341088
  function failureFields(failure) {
341077
- return failure.errorBody ? { error: failure.error, errorBody: failure.errorBody } : { error: failure.error };
341089
+ return {
341090
+ error: failure.error,
341091
+ ...failure.errorBody ? { errorBody: failure.errorBody } : {},
341092
+ ...failure.exitCode === undefined ? {} : { exitCode: failure.exitCode }
341093
+ };
341078
341094
  }
341079
341095
  async function requestWithRetry(args) {
341080
341096
  const sleep2 = args.sleep ?? sleep;
@@ -342171,7 +342187,14 @@ var makeCreateRunContract = (ids) => {
342171
342187
  pullRequestNumber: exports_external.number().int().positive().describe("The number of the pull request to associate with the run.").optional(),
342172
342188
  repository: exports_external.string().min(1).describe('The owner/name of the repository, e.g. "acme/web".').optional()
342173
342189
  }).and(makeFlowSelectionSchema(ids));
342174
- const output = resource({ runId: ids.run }, { urlFieldDescription: "Absolute URL of the run page." });
342190
+ const output = resource({
342191
+ excludedFlows: exports_external.array(exports_external.object({
342192
+ flowId: ids.flow,
342193
+ name: exports_external.string().describe("The name of the flow."),
342194
+ reason: exports_external.enum(["deleted", "not-on-branch"]).describe('Why the flow cannot run: "deleted" means the flow was deleted, "not-on-branch" means the flow has no file at the commit the run was created from.')
342195
+ })).describe("Explicitly requested flows that were left out of the run, each with the reason. Flows selected through tags are not reported here."),
342196
+ runId: ids.run
342197
+ }, { urlFieldDescription: "Absolute URL of the run page." });
342175
342198
  return {
342176
342199
  description: "Create a run for the selected flows and/or tags in an environment.",
342177
342200
  input,
@@ -342531,7 +342554,7 @@ var makeEnvironmentResourceSchema = (ids) => resource({
342531
342554
  kind: exports_external.enum(["static", "preview"]).describe("Whether the environment is static or a preview."),
342532
342555
  name: exports_external.string(),
342533
342556
  runConcurrencyLimit: exports_external.string().describe('Maximum number of concurrent runs: a whole number, "unlimited", or a concurrency expression.'),
342534
- status: exports_external.enum(["blocked", "needs-investigation", "ready", "running"]).describe("Standing health across the environment's runs: blocked (open blocking bugs), needs-investigation (failures awaiting triage), running (flows executing), ready (none of the above — the greenlit state)."),
342557
+ status: exports_external.enum(["blocked", "needs-investigation", "ready", "running"]).describe("Standing health across the environment's runs, not its Git reconciliation state: blocked (open blocking bugs), needs-investigation (failures awaiting triage), running (flows executing), ready (none of the above — the greenlit state)."),
342535
342558
  terminatedAt: exports_external.iso.datetime().optional().describe("When the environment was terminated, if it has been.")
342536
342559
  }, { urlFieldDescription: "Absolute URL of the environment page." });
342537
342560
 
@@ -342540,6 +342563,7 @@ var makeFindEnvironmentsContract = (ids) => {
342540
342563
  const input = exports_external.object({
342541
342564
  includeTerminated: exports_external.boolean().default(false).describe("Also list terminated environments. By default only environments that have not been terminated are listed."),
342542
342565
  kind: exports_external.enum(["static", "preview"]).optional().describe("Only list environments of this kind. Omit to list both."),
342566
+ workspaceId: ids.workspace.optional().describe("The workspace to list environments from. Required when authenticating with an organization or user API key."),
342543
342567
  ...makePaginationInputFields({ defaultLimit: 20, maxLimit: 100 })
342544
342568
  });
342545
342569
  const output = exports_external.object({
@@ -342585,7 +342609,7 @@ var makeGetEnvironmentContract = (ids) => {
342585
342609
  });
342586
342610
  const output = makeEnvironmentResourceSchema(ids);
342587
342611
  return {
342588
- description: "Read a single environment's name, kind, health status, run concurrency limit, and termination state.",
342612
+ description: "Read a single environment's name, kind, standing run health, flow-code branch and reconciliation state, run concurrency limit, and termination state. If flowCodeBranch exists, use its syncStatus for Git reconciliation and read lastSyncedCommitHash only when syncStatus is reconciled.",
342589
342613
  input,
342590
342614
  kind: "read",
342591
342615
  name: "environment.get",
@@ -342627,7 +342651,7 @@ var makeSetEnvironmentVariableContract = (ids) => {
342627
342651
  var makeCreateEnvironmentContract = (ids) => {
342628
342652
  const input = exports_external.object({
342629
342653
  name: exports_external.string().min(1).max(255).regex(/\S/, "Environment name cannot be blank.").describe("Display name of the new environment."),
342630
- workspaceId: ids.workspace.optional().describe("The workspace to create the environment in. Required when authenticating with an organization API key.")
342654
+ workspaceId: ids.workspace.optional().describe("The workspace to create the environment in. Required when authenticating with an organization or user API key.")
342631
342655
  });
342632
342656
  const output = makeEnvironmentResourceSchema(ids);
342633
342657
  return {
@@ -342667,9 +342691,10 @@ var makeTagResourceSchema = () => resource({
342667
342691
  }, {
342668
342692
  urlFieldDescription: "Absolute URL of the team's tag settings page."
342669
342693
  });
342670
- var makeCreateTagContract = () => {
342694
+ var makeCreateTagContract = (ids) => {
342671
342695
  const input = exports_external.object({
342672
- name: exports_external.string().trim().min(1).max(255).refine((name) => !name.includes(","), "Tag names cannot include commas.")
342696
+ name: exports_external.string().trim().min(1).max(255).refine((name) => !name.includes(","), "Tag names cannot include commas."),
342697
+ workspaceId: ids.workspace.optional().describe("The workspace to create the tag in. Required when authenticating with an organization or user API key.")
342673
342698
  });
342674
342699
  const output = makeTagResourceSchema();
342675
342700
  return {
@@ -342793,7 +342818,7 @@ var makeFindIssuesContract = (ids) => {
342793
342818
  ...makePaginationInputFields({ defaultLimit: 20, maxLimit: 100 }),
342794
342819
  statuses: exports_external.array(issueStatusSchema).min(1).default([...openIssueStatuses]).describe("Issue statuses to include. Defaults to pending, in-progress, and paused issues."),
342795
342820
  type: publicIssueTypeSchema.describe("The issue type to include: bug report, maintenance report, or coverage request."),
342796
- workspaceId: ids.workspace.optional().describe("The workspace whose issues to list. Required when authenticating with an organization API key.")
342821
+ workspaceId: ids.workspace.optional().describe("The workspace whose issues to list. Required when authenticating with an organization or user API key.")
342797
342822
  });
342798
342823
  const output = exports_external.object({
342799
342824
  issues: exports_external.array(makeIssueResourceSchema(ids)).describe("The team's bug reports, maintenance reports, or coverage requests, newest first."),
@@ -342847,7 +342872,7 @@ var makeCreateIssueContract = (ids) => {
342847
342872
  description: exports_external.string().optional().describe("The issue description as plain text; each line becomes a paragraph. Markdown is not parsed."),
342848
342873
  name: exports_external.string().trim().min(1).max(255),
342849
342874
  priority: issuePrioritySchema.optional().describe('Defaults to "unprioritized".'),
342850
- workspaceId: ids.workspace.optional().describe("The workspace to create the issue in. Required when authenticating with an organization API key.")
342875
+ workspaceId: ids.workspace.optional().describe("The workspace to create the issue in. Required when authenticating with an organization or user API key.")
342851
342876
  };
342852
342877
  const input = exports_external.discriminatedUnion("type", [
342853
342878
  exports_external.object({
@@ -343009,6 +343034,25 @@ var makeGetRunContract = (ids) => {
343009
343034
  };
343010
343035
  };
343011
343036
 
343037
+ // node_modules/@qawolf/api-contracts/dist/v1/run/reattempt.js
343038
+ var makeReattemptRunContract = (ids) => {
343039
+ const input = exports_external.object({
343040
+ flowIds: exports_external.array(ids.flow).min(1).max(300).refine((flowIds) => new Set(flowIds).size === flowIds.length, "flowIds must be unique").optional().describe("The flows to reattempt. Every named flow must be eligible or the " + "whole request is rejected. Omit to reattempt every eligible flow."),
343041
+ runId: ids.run
343042
+ });
343043
+ const output = resource({
343044
+ reattemptedFlowIds: exports_external.array(ids.flow).describe("The flows a new attempt was requested for."),
343045
+ runId: ids.run
343046
+ }, { urlFieldDescription: "Absolute URL of the run page." });
343047
+ return {
343048
+ description: "Request new attempts for a run's flows, in the same run. " + "A flow is eligible once its result is failed or canceled and QA Wolf's " + "automatic retries have finished. " + "A fully investigated run no longer accepts reattempts. " + "Attempts run with the latest flow code. Poll run.get for results.",
343049
+ input,
343050
+ kind: "write",
343051
+ name: "run.reattempt",
343052
+ output
343053
+ };
343054
+ };
343055
+
343012
343056
  // node_modules/@qawolf/api-contracts/dist/v1/runner/evaluateSnippet.js
343013
343057
  var maxSnippetCodeLength = 64 * 1024;
343014
343058
  var makeEvaluateSnippetOnRunnerContract = () => {
@@ -343237,6 +343281,7 @@ var makeListTagsContract = (ids) => {
343237
343281
  const input = exports_external.object({
343238
343282
  includeFlowIds: exports_external.boolean().default(false).describe("Also return the ids of the flows that carry each tag."),
343239
343283
  names: exports_external.array(exports_external.string().trim().min(1)).min(1).max(100).optional().describe("Only list tags with these names. Matching is case sensitive. Omit to list all tags."),
343284
+ workspaceId: ids.workspace.optional().describe("The workspace to list tags from. Required when authenticating with an organization or user API key."),
343240
343285
  ...makePaginationInputFields({ defaultLimit: 20, maxLimit: 100 })
343241
343286
  });
343242
343287
  const output = exports_external.object({
@@ -343284,7 +343329,8 @@ var makeContractsV1 = (ids) => {
343284
343329
  run: {
343285
343330
  create: makeCreateRunContract(resolvedIds),
343286
343331
  find: makeFindRunsContract(resolvedIds),
343287
- get: makeGetRunContract(resolvedIds)
343332
+ get: makeGetRunContract(resolvedIds),
343333
+ reattempt: makeReattemptRunContract(resolvedIds)
343288
343334
  },
343289
343335
  runner: {
343290
343336
  evaluateSnippet: makeEvaluateSnippetOnRunnerContract(),
@@ -343299,7 +343345,7 @@ var makeContractsV1 = (ids) => {
343299
343345
  terminate: makeTerminateRunnerContract()
343300
343346
  },
343301
343347
  tag: {
343302
- create: makeCreateTagContract(),
343348
+ create: makeCreateTagContract(resolvedIds),
343303
343349
  list: makeListTagsContract(resolvedIds)
343304
343350
  }
343305
343351
  };
@@ -345820,7 +345866,7 @@ function startUpdateCheck(deps) {
345820
345866
  // package.json
345821
345867
  var package_default = {
345822
345868
  name: "@qawolf/cli",
345823
- version: "1.13.0",
345869
+ version: "1.15.0",
345824
345870
  description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
345825
345871
  keywords: [
345826
345872
  "automation",
@@ -345880,7 +345926,7 @@ var package_default = {
345880
345926
  "@clack/prompts": "1.5.1",
345881
345927
  "@napi-rs/keyring": "1.3.0",
345882
345928
  "@oxc-node/core": "0.1.0",
345883
- "@qawolf/api-contracts": "0.27.0",
345929
+ "@qawolf/api-contracts": "0.30.0",
345884
345930
  "@qawolf/emails": "1.1.1",
345885
345931
  "@qawolf/flow-targets": "1.0.0",
345886
345932
  "@qawolf/flows": "0.1.4",
@@ -346114,7 +346160,7 @@ async function handleWhoami(ctx, deps = {}) {
346114
346160
  } else {
346115
346161
  ctx.ui.output({ authenticated: false, source: undefined }, authMessages.notAuthenticated);
346116
346162
  }
346117
- return { error: "not authenticated" };
346163
+ return { error: "not authenticated", exitCode: exitCodes.auth };
346118
346164
  }
346119
346165
  const platformClient = (deps.createPlatform ?? createPlatformClient)(resolved.key, {
346120
346166
  baseUrl: ctx.apiBaseUrl,
@@ -346134,7 +346180,10 @@ async function handleWhoami(ctx, deps = {}) {
346134
346180
  valid: false
346135
346181
  }, authMessages.whoami.authFailed(resolved.source, identity.error));
346136
346182
  }
346137
- return { error: "invalid key" };
346183
+ return {
346184
+ error: "invalid key",
346185
+ ...identity.exitCode === undefined ? {} : { exitCode: identity.exitCode }
346186
+ };
346138
346187
  }
346139
346188
  const { value } = identity;
346140
346189
  if ("user" in value) {
@@ -352872,6 +352921,16 @@ async function executeFlows(args) {
352872
352921
  }
352873
352922
  }
352874
352923
 
352924
+ // src/domains/runner/noMatch.ts
352925
+ function noMatchResult(ctx, args) {
352926
+ if (!args.allowNoMatch) {
352927
+ return { error: args.error, exitCode: exitCodes.invalidArgs };
352928
+ }
352929
+ if (args.notice !== undefined)
352930
+ ctx.ui.info(args.notice);
352931
+ return;
352932
+ }
352933
+
352875
352934
  // src/domains/runner/run.ts
352876
352935
  async function flowsRun(ctx, files, flags, deps) {
352877
352936
  const flows = [];
@@ -352907,10 +352966,12 @@ async function flowsRun(ctx, files, flags, deps) {
352907
352966
  }
352908
352967
  flows.sort((a2, b3) => a2.file.localeCompare(b3.file));
352909
352968
  if (flows.length === 0) {
352910
- if (skippedByType.size === 0) {
352911
- ctx.ui.info(runnerMessages.noFlowsMatched);
352912
- }
352913
- return;
352969
+ const skipped = skippedByType.size > 0;
352970
+ return noMatchResult(ctx, {
352971
+ allowNoMatch: flags.allowNoMatch,
352972
+ error: skipped ? runnerMessages.noRunnableFlows : runnerMessages.noTargetedFlows,
352973
+ notice: skipped ? undefined : runnerMessages.noFlowsMatched
352974
+ });
352914
352975
  }
352915
352976
  const webFlows = flows.filter((f3) => f3.kind === "web");
352916
352977
  const browsers = [
@@ -355280,8 +355341,11 @@ async function handleFlowsRun(ctx, pattern, flags, deps) {
355280
355341
  const expandedFiles = await resolvedDeps.expandPatterns(buildPatternArgs(pattern), cwd, ctx.log("flows"));
355281
355342
  ctx.log("flows").debug(`discovered ${pluralize(expandedFiles.length, "flow")}`);
355282
355343
  if (expandedFiles.length === 0) {
355283
- ctx.ui.info(runnerMessages.noFlowsMatched);
355284
- return;
355344
+ return noMatchResult(ctx, {
355345
+ allowNoMatch: flags.allowNoMatch,
355346
+ error: runnerMessages.noFlowsMatchedPattern(pattern),
355347
+ notice: runnerMessages.noFlowsMatched
355348
+ });
355285
355349
  }
355286
355350
  return runStagedFlows({
355287
355351
  ctx,
@@ -355321,10 +355385,11 @@ async function handleHybridFlowsRun(ctx, pattern, flags, deps) {
355321
355385
  return pullResult;
355322
355386
  files = await globFlows();
355323
355387
  if (files.length === 0) {
355324
- return {
355325
- error: pattern !== undefined ? `No flows matched '${pattern}' in env '${flags.env}'` : `No flows found in env '${flags.env}'`,
355326
- exitCode: 2
355327
- };
355388
+ return noMatchResult(ctx, {
355389
+ allowNoMatch: flags.allowNoMatch,
355390
+ error: runnerMessages.noFlowsMatchedInEnv(flags.env, pattern),
355391
+ notice: runnerMessages.noFlowsMatched
355392
+ });
355328
355393
  }
355329
355394
  }
355330
355395
  return runStagedFlows({ ctx, files, flags, envDir, deps: resolvedDeps });
@@ -355348,7 +355413,7 @@ Examples:
355348
355413
  function registerFlowsRunCommand(flows, signals) {
355349
355414
  declareCommandKind(flows.command("run [pattern]"), "local", {
355350
355415
  kindNote: "read with --env"
355351
- }).description("Run flows matching [pattern], or every flow when omitted; with --env, pull missing flows from that QA Wolf environment").option("--retries <n>", "Retry each failing flow up to this many times", parseInteger("--retries", { min: 0 }), 0).option("--bail", "Stop the run after the first failure", false).option("--workers <n>", "Parallel worker count for web flows", parseInteger("--workers", { min: 1 }), 1).option("--timeout <ms>", "Default timeout for actions and assertions, in milliseconds", parseInteger("--timeout", { min: 0 }), 30000).option("--video <mode>", "Record video: on | off | retain-on-failure", parseEnum("--video", videoModes), videoDefault).option("--trace <mode>", "Record Playwright trace: on | off | retain-on-failure", parseEnum("--trace", traceModes), traceDefault).option("--har <mode>", "Record HAR network log: on | off | retain-on-failure", parseEnum("--har", harModes), harDefault).option("--har-content <mode>", "HAR response bodies: omit | full (full uses more memory)", parseEnum("--har-content", harContentModes), harContentDefault).option("--output-dir <path>", "Directory for run artifacts (videos, traces, HAR)", defaultOutputDir).option("--junit [path]", "Write a JUnit XML report (default: <output-dir>/junit-report.xml)").option("--headed", "Show the browser window instead of headless", false).option("--env <env>", "Pull and run a flow from this environment (UUID or slug) if not cached locally").option("--deps <dir>", "Use this prepared dependency directory instead of auto-installing the runtime; or set QAWOLF_RUNTIME_DIR to relocate the managed runtime").option("--no-browser-deps", "Skip installing OS-level browser dependencies (Linux --with-deps, which needs root); requires the system libraries to already be present").addHelpText("after", runExamples).action((pattern, opts, command) => {
355416
+ }).description("Run flows matching [pattern], or every flow when omitted; with --env, pull missing flows from that QA Wolf environment").option("--retries <n>", "Retry each failing flow up to this many times", parseInteger("--retries", { min: 0 }), 0).option("--bail", "Stop the run after the first failure", false).option("--workers <n>", "Parallel worker count for web flows", parseInteger("--workers", { min: 1 }), 1).option("--timeout <ms>", "Default timeout for actions and assertions, in milliseconds", parseInteger("--timeout", { min: 0 }), 30000).option("--video <mode>", "Record video: on | off | retain-on-failure", parseEnum("--video", videoModes), videoDefault).option("--trace <mode>", "Record Playwright trace: on | off | retain-on-failure", parseEnum("--trace", traceModes), traceDefault).option("--har <mode>", "Record HAR network log: on | off | retain-on-failure", parseEnum("--har", harModes), harDefault).option("--har-content <mode>", "HAR response bodies: omit | full (full uses more memory)", parseEnum("--har-content", harContentModes), harContentDefault).option("--output-dir <path>", "Directory for run artifacts (videos, traces, HAR)", defaultOutputDir).option("--junit [path]", "Write a JUnit XML report (default: <output-dir>/junit-report.xml)").option("--headed", "Show the browser window instead of headless", false).option("--env <env>", "Pull and run a flow from this environment (UUID or slug) if not cached locally").option("--deps <dir>", "Use this prepared dependency directory instead of auto-installing the runtime; or set QAWOLF_RUNTIME_DIR to relocate the managed runtime").option("--allow-no-match", "Exit 0 instead of 2 when the pattern selects no runnable flow", false).option("--no-browser-deps", "Skip installing OS-level browser dependencies (Linux --with-deps, which needs root); requires the system libraries to already be present").addHelpText("after", runExamples).action((pattern, opts, command) => {
355352
355417
  if (opts.env !== undefined) {
355353
355418
  return withResolvedEnv(signals, {
355354
355419
  explicit: opts.env,
@@ -358159,4 +358224,4 @@ createProgram({ signals }).parseAsync().catch(() => {
358159
358224
  process.exitCode = 1;
358160
358225
  }).finally(() => flushAndExit(typeof process.exitCode === "number" ? process.exitCode : 0));
358161
358226
 
358162
- //# debugId=23E147B93341D71864756E2164756E21
358227
+ //# debugId=DD39A64EAC42A5D564756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qawolf/cli",
3
- "version": "1.13.0",
3
+ "version": "1.15.0",
4
4
  "description": "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
5
5
  "keywords": [
6
6
  "automation",
@@ -60,7 +60,7 @@
60
60
  "@clack/prompts": "1.5.1",
61
61
  "@napi-rs/keyring": "1.3.0",
62
62
  "@oxc-node/core": "0.1.0",
63
- "@qawolf/api-contracts": "0.27.0",
63
+ "@qawolf/api-contracts": "0.30.0",
64
64
  "@qawolf/emails": "1.1.1",
65
65
  "@qawolf/flow-targets": "1.0.0",
66
66
  "@qawolf/flows": "0.1.4",
@@ -118,7 +118,7 @@ current branch.
118
118
  | `qawolf environment create` | write | Create an environment on the caller's team and return it in the environment.get shape. |
119
119
  | `qawolf environment deleteVariable` | write | Remove one environment variable by name. Succeeds whether or not the variable existed. |
120
120
  | `qawolf environment find` | read | List the team's environments, newest first. |
121
- | `qawolf environment get` | read | Read a single environment's name, kind, health status, run concurrency limit, and termination state. |
121
+ | `qawolf environment get` | read | Read a single environment's name, kind, standing run health, flow-code branch and reconciliation state, run concurrency limit, and termination state. If flowCodeBranch exists, use its syncStatus for Git reconciliation and read lastSyncedCommitHash only when syncStatus is reconciled. |
122
122
  | `qawolf environment getVariable` | read | Read the values of named environment variables in one call. Values are secrets. Names that do not exist go to missingNames and do not fail the call. |
123
123
  | `qawolf environment listVariableNames` | read | Use this to answer which QA Wolf environment variables are available to test code. Returns names only; values never leave the server. |
124
124
  | `qawolf environment setVariable` | write | Create or replace an environment variable. If the user asks to create one for "my email" without naming it, use DEFAULT_EMAIL. The value is never returned. |
@@ -141,6 +141,7 @@ current branch.
141
141
  | `qawolf run create` | write | Create a run for the selected flows and/or tags in an environment. |
142
142
  | `qawolf run find` | read | List an environment's recent runs, newest first. |
143
143
  | `qawolf run get` | read | Get a run's status, per-flow results, and links. |
144
+ | `qawolf run reattempt` | write | Request new attempts for a run's flows, in the same run. A flow is eligible once its result is failed or canceled and QA Wolf's automatic retries have finished. A fully investigated run no longer accepts reattempts. Attempts run with the latest flow code. Poll run.get for results. |
144
145
  | `qawolf runner act` | write | Perform one raw action on a runner's screen: click, double_click, scroll, move, drag, keypress, navigate or type. Use - to read a whole action as JSON from stdin |
145
146
  | `qawolf runner events` | read | Print a runner's journal, one entry per line. QA Wolf writes console, recorder, run-events, run-logs, run-status |
146
147
  | `qawolf runner exec` | write | Evaluate a snippet against a runner's live page. Use - to read the snippet from stdin |