@qawolf/cli 1.7.3 → 1.7.4

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.
Files changed (2) hide show
  1. package/dist/cli.js +97 -43
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -144620,19 +144620,19 @@ async function takeScreenshotBidi(filepath, options) {
144620
144620
  type: imageFormat,
144621
144621
  quality
144622
144622
  };
144623
- const clip2 = options?.clip ? {
144623
+ const clip3 = options?.clip ? {
144624
144624
  type: "box",
144625
144625
  x: options.clip.x,
144626
144626
  y: options.clip.y,
144627
144627
  width: options.clip.width,
144628
144628
  height: options.clip.height
144629
144629
  } : undefined;
144630
- if (clip2) {
144631
- if (typeof clip2.x !== "number" || typeof clip2.y !== "number" || typeof clip2.width !== "number" || typeof clip2.height !== "number") {
144630
+ if (clip3) {
144631
+ if (typeof clip3.x !== "number" || typeof clip3.y !== "number" || typeof clip3.width !== "number" || typeof clip3.height !== "number") {
144632
144632
  throw new Error("Invalid clip, use an object with x, y, width and height properties");
144633
144633
  }
144634
144634
  }
144635
- const { data: data2 } = contextManager.findParentContext(context, tree.contexts) ? await browser.$("html").getElement().then((el) => this.takeElementScreenshot(el.elementId).then((data22) => ({ data: data22 }))) : await this.browsingContextCaptureScreenshot({ context, origin, format, clip: clip2 });
144635
+ const { data: data2 } = contextManager.findParentContext(context, tree.contexts) ? await browser.$("html").getElement().then((el) => this.takeElementScreenshot(el.elementId).then((data22) => ({ data: data22 }))) : await this.browsingContextCaptureScreenshot({ context, origin, format, clip: clip3 });
144636
144636
  return data2;
144637
144637
  }
144638
144638
  async function saveElementScreenshot(filepath) {
@@ -170194,49 +170194,86 @@ function createLoggingSystem(opts) {
170194
170194
  };
170195
170195
  }
170196
170196
 
170197
+ // src/shell/platform/parseErrorBody.ts
170198
+ var defaultMaxLength = 1024;
170199
+ function asRecord(value) {
170200
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
170201
+ }
170202
+ function asString(value) {
170203
+ return typeof value === "string" ? value : undefined;
170204
+ }
170205
+ function extractMessage(parsed) {
170206
+ const root = asRecord(parsed);
170207
+ if (!root)
170208
+ return;
170209
+ const flat = asString(root["error"]);
170210
+ if (flat !== undefined)
170211
+ return flat;
170212
+ const error51 = asRecord(root["error"]);
170213
+ if (!error51)
170214
+ return;
170215
+ const json2 = asRecord(error51["json"]);
170216
+ return asString(json2?.["message"]) ?? asString(error51["message"]);
170217
+ }
170218
+ function parseErrorBody(body, maxLength = defaultMaxLength) {
170219
+ if (!body)
170220
+ return "";
170221
+ let parsed;
170222
+ try {
170223
+ parsed = JSON.parse(body);
170224
+ } catch {
170225
+ return "";
170226
+ }
170227
+ const message = extractMessage(parsed)?.trim();
170228
+ if (!message)
170229
+ return "";
170230
+ return clip(message, maxLength);
170231
+ }
170232
+ function clip(message, maxLength) {
170233
+ if (message.length <= maxLength)
170234
+ return message;
170235
+ return maxLength < 1 ? "" : `${message.slice(0, maxLength - 1)}…`;
170236
+ }
170237
+
170197
170238
  // src/shell/platform/describeErrors.ts
170198
170239
  var m = authMessages.errors;
170240
+ var inlineReasonMaxLength = 200;
170199
170241
  function describeIdentityError(err) {
170200
170242
  if (err.kind === "http") {
170201
170243
  if (err.status === 401 || err.status === 403) {
170202
- return m.identity.invalidOrUnauthorized;
170244
+ return { error: m.identity.invalidOrUnauthorized };
170203
170245
  }
170204
- return m.identity.couldNotVerify(parseErrorBody(err.body), err.status);
170246
+ return {
170247
+ error: m.identity.couldNotVerify(parseErrorBody(err.body, inlineReasonMaxLength), err.status)
170248
+ };
170205
170249
  }
170206
170250
  if (err.kind === "network") {
170207
- return m.identity.couldNotVerifyNetwork(err.cause.message);
170251
+ return { error: m.identity.couldNotVerifyNetwork(err.cause.message) };
170208
170252
  }
170209
- if (err.kind === "timeout")
170210
- return m.identity.timedOut(err.timeoutMs);
170211
- return m.identity.unexpectedFormat;
170212
- }
170213
- function parseErrorBody(body) {
170214
- if (!body)
170215
- return "";
170216
- try {
170217
- const parsed = JSON.parse(body);
170218
- if (typeof parsed === "object" && parsed !== null && "error" in parsed && typeof parsed.error === "string") {
170219
- return parsed.error;
170220
- }
170221
- } catch {}
170222
- return "";
170253
+ if (err.kind === "timeout") {
170254
+ return { error: m.identity.timedOut(err.timeoutMs) };
170255
+ }
170256
+ return { error: m.identity.unexpectedFormat };
170223
170257
  }
170224
170258
  function describeRequestError(err, baseUrl, noun) {
170225
170259
  if (err.kind === "http") {
170260
+ const reason = parseErrorBody(err.body);
170261
+ const body = reason ? { errorBody: reason } : {};
170226
170262
  if (err.status === 401)
170227
- return m.request.rejected401(noun);
170263
+ return { error: m.request.rejected401(noun), ...body };
170228
170264
  if (err.status === 403)
170229
- return m.request.rejected403(noun);
170265
+ return { error: m.request.rejected403(noun), ...body };
170230
170266
  if (err.status === 404)
170231
- return m.request.notFound404(noun);
170232
- return m.request.failedWithStatus(err.status, noun);
170267
+ return { error: m.request.notFound404(noun), ...body };
170268
+ return { error: m.request.failedWithStatus(err.status, noun), ...body };
170233
170269
  }
170234
170270
  if (err.kind === "network") {
170235
- return m.request.networkUnreachable(baseUrl, noun);
170271
+ return { error: m.request.networkUnreachable(baseUrl, noun) };
170236
170272
  }
170237
- if (err.kind === "timeout")
170238
- return m.request.timedOut(err.timeoutMs, noun);
170239
- return m.request.unexpectedResponse(noun);
170273
+ if (err.kind === "timeout") {
170274
+ return { error: m.request.timedOut(err.timeoutMs, noun) };
170275
+ }
170276
+ return { error: m.request.unexpectedResponse(noun) };
170240
170277
  }
170241
170278
  function describeBundleDownloadError(err) {
170242
170279
  if (err.kind === "http") {
@@ -170271,6 +170308,9 @@ import { setTimeout as setTimeout2 } from "node:timers/promises";
170271
170308
  var sleep = (ms) => setTimeout2(ms);
170272
170309
 
170273
170310
  // src/shell/platform/requestWithRetry.ts
170311
+ function failureFields(failure) {
170312
+ return failure.errorBody ? { error: failure.error, errorBody: failure.errorBody } : { error: failure.error };
170313
+ }
170274
170314
  async function requestWithRetry(args) {
170275
170315
  const sleep2 = args.sleep ?? sleep;
170276
170316
  for (let attempt = 0;; attempt++) {
@@ -170280,7 +170320,7 @@ async function requestWithRetry(args) {
170280
170320
  const backoff = args.backoffMs[attempt];
170281
170321
  const retryable = result.error.kind === "network" || result.error.kind === "timeout";
170282
170322
  if (backoff === undefined || !retryable) {
170283
- return { ok: false, error: args.describe(result.error) };
170323
+ return { ok: false, ...args.describe(result.error) };
170284
170324
  }
170285
170325
  await sleep2(backoff);
170286
170326
  }
@@ -171185,15 +171225,15 @@ function createTrpcClient(apiKey, deps) {
171185
171225
  }
171186
171226
  };
171187
171227
  }
171188
- function clip(text) {
171228
+ function clip2(text) {
171189
171229
  return text.length > 200 ? text.slice(0, 200) + "…" : text;
171190
171230
  }
171191
171231
  function summarize(error51) {
171192
171232
  if (error51.kind === "http")
171193
- return `${error51.status} ${clip(error51.body)}`;
171233
+ return `${error51.status} ${clip2(error51.body)}`;
171194
171234
  if (error51.kind === "timeout")
171195
171235
  return `timed out after ${error51.timeoutMs}ms`;
171196
- return clip(error51.cause.message);
171236
+ return clip2(error51.cause.message);
171197
171237
  }
171198
171238
 
171199
171239
  // src/shell/platform/downloadBundle.ts
@@ -174626,7 +174666,7 @@ function startUpdateCheck(deps) {
174626
174666
  // package.json
174627
174667
  var package_default = {
174628
174668
  name: "@qawolf/cli",
174629
- version: "1.7.3",
174669
+ version: "1.7.4",
174630
174670
  description: "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
174631
174671
  keywords: [
174632
174672
  "automation",
@@ -177089,9 +177129,8 @@ async function flowsListRemote(ctx, pattern, options) {
177089
177129
  environmentId: options.env,
177090
177130
  includeDrafts: options.includeDrafts
177091
177131
  });
177092
- if (!result.ok) {
177093
- return { error: result.error };
177094
- }
177132
+ if (!result.ok)
177133
+ return failureFields(result);
177095
177134
  const matches = pattern ? import_picomatch2.default(pattern) : undefined;
177096
177135
  const items = result.value.flows.filter((f2) => !matches || matches(f2.path)).map((f2) => ({
177097
177136
  flowId: f2.flowId,
@@ -180963,7 +181002,7 @@ var findContract = publicContractsV1.environment.find;
180963
181002
  async function pickEnvironment(deps) {
180964
181003
  const fetched = await fetchAllEnvironments(deps.platformClient);
180965
181004
  if (!fetched.ok)
180966
- return { kind: "error", error: fetched.error };
181005
+ return { ...failureFields(fetched), kind: "error" };
180967
181006
  const environments = fetched.environments;
180968
181007
  if (environments.length === 0) {
180969
181008
  return { kind: "error", error: environmentsMessages.noEnvironments };
@@ -181056,6 +181095,7 @@ async function resolveRef2(deps, ref) {
181056
181095
  });
181057
181096
  if (!result.ok) {
181058
181097
  return {
181098
+ ...failureFields(result),
181059
181099
  kind: "error",
181060
181100
  error: environmentsMessages.couldNotResolve(ref, result.error)
181061
181101
  };
@@ -181089,7 +181129,7 @@ function withResolvedEnv(signals, args, fn2) {
181089
181129
  return;
181090
181130
  }
181091
181131
  if (outcome.kind === "error") {
181092
- return { error: outcome.error };
181132
+ return failureFields(outcome);
181093
181133
  }
181094
181134
  return fn2(ctx, outcome.env);
181095
181135
  })(opts, command);
@@ -184753,7 +184793,7 @@ async function handlePublicApiCommand(ctx, spec, options) {
184753
184793
  return { error: exports_external.prettifyError(parsed.error) };
184754
184794
  const result = await ctx.platformClient.callPublicApi(spec.contract, parsed.data);
184755
184795
  if (!result.ok)
184756
- return { error: result.error };
184796
+ return failureFields(result);
184757
184797
  ctx.ui.output(result.value, renderHuman(result.value));
184758
184798
  return;
184759
184799
  }
@@ -184765,8 +184805,16 @@ var groupDescriptions = {
184765
184805
  var handWrittenContractNames = new Set(["flow.list"]);
184766
184806
  var skippedContractNames = new Set([
184767
184807
  ...handWrittenContractNames,
184768
- "issue.update"
184808
+ "issue.update",
184809
+ "runner.performAction"
184769
184810
  ]);
184811
+ var optionEnvironmentVariables = new Map([
184812
+ ["environmentId", "QAWOLF_ENVIRONMENT"],
184813
+ ["public.run.create.aiTaskId", "QAWOLF_AI_TASK_ID"]
184814
+ ]);
184815
+ function optionEnvironmentVariable(spec, field) {
184816
+ return optionEnvironmentVariables.get(`${spec.trpcPath}.${field}`) ?? optionEnvironmentVariables.get(field);
184817
+ }
184770
184818
  function resolveGroup(parent2, segment) {
184771
184819
  const existing = parent2.commands.find((command) => command.name() === segment);
184772
184820
  return existing ?? parent2.command(segment).description(groupDescriptions[segment] ?? `QA Wolf public API ${segment} commands`);
@@ -184783,7 +184831,13 @@ function registerSpec(program2, signals, spec, authDeps) {
184783
184831
  }
184784
184832
  const command = declareCommandKind(parent2.command(leafName), spec.kind).description(spec.description);
184785
184833
  for (const flag of spec.flags) {
184786
- if (flag.required) {
184834
+ const environmentVariable = optionEnvironmentVariable(spec, flag.field);
184835
+ if (environmentVariable) {
184836
+ const option = new Option(flag.flag, flag.description).env(environmentVariable);
184837
+ if (flag.required)
184838
+ option.makeOptionMandatory();
184839
+ command.addOption(option);
184840
+ } else if (flag.required) {
184787
184841
  command.requiredOption(flag.flag, flag.description);
184788
184842
  } else {
184789
184843
  command.option(flag.flag, flag.description);
@@ -184835,4 +184889,4 @@ createProgram({ signals }).parseAsync().catch(() => {
184835
184889
  process.exitCode = 1;
184836
184890
  }).finally(() => flushAndExit(typeof process.exitCode === "number" ? process.exitCode : 0));
184837
184891
 
184838
- //# debugId=C0B1B96CCF6C4A9564756E2164756E21
184892
+ //# debugId=6CBE0567ED2CC02E64756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qawolf/cli",
3
- "version": "1.7.3",
3
+ "version": "1.7.4",
4
4
  "description": "Run and manage QA Wolf flows from the terminal, CI, or an AI agent",
5
5
  "keywords": [
6
6
  "automation",