@bugbug-io/cli 13.39.3 → 14.0.1

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.
@@ -8923,7 +8923,7 @@ var require_main = __commonJS({
8923
8923
  // ../core/package.json
8924
8924
  var package_default = {
8925
8925
  name: "@bugbug-io/core",
8926
- version: "13.39.1",
8926
+ version: "14.0.1",
8927
8927
  private: true,
8928
8928
  type: "module",
8929
8929
  main: "dist/index.js",
@@ -48320,13 +48320,14 @@ var getCommandArgsConfig = () => {
48320
48320
  token = arg.slice("--token=".length);
48321
48321
  continue;
48322
48322
  }
48323
- if (arg === "--project-id") {
48323
+ if (arg === "-p" || arg === "--project-id") {
48324
48324
  projectId = args[i + 1];
48325
48325
  i++;
48326
48326
  continue;
48327
48327
  }
48328
48328
  if (arg.startsWith("--project-id=")) {
48329
48329
  projectId = arg.slice("--project-id=".length);
48330
+ continue;
48330
48331
  }
48331
48332
  }
48332
48333
  return { token, projectId, verbose, disableTelemetry, outputModeOptions };
@@ -56418,32 +56419,48 @@ var require_dist2 = __commonJS2({
56418
56419
  exports.visitAsync = visit2.visitAsync;
56419
56420
  }
56420
56421
  });
56422
+ var DEFAULT_CONFIG_FILE_NAME2 = "bugbug.yaml";
56423
+ var DEFAULT_API_URL2 = "https://app.bugbug.io/api/v2";
56424
+ var DEFAULT_YAML_SCHEMA_URL2 = `${DEFAULT_API_URL2}/schema/yaml/v1/`;
56425
+ var DEFAULT_MCP_URL2 = "https://mcp.bugbug.io";
56426
+ var DEFAULT_MCP_ACCESS_PATH2 = "/mcp";
56427
+ var DEFAULT_MCP_ACCESS_URL2 = `${DEFAULT_MCP_URL2}${DEFAULT_MCP_ACCESS_PATH2}`;
56428
+ var DOCS_BASE_URL2 = "https://docs.bugbug.io";
56429
+ var DOCS_ASK_URL2 = `${DOCS_BASE_URL2}/master.md`;
56430
+ var CREDENTIALS_DIR_NAME2 = ".bugbug";
56431
+ var GLOBAL_CONFIG_FILE_NAME2 = "config.yaml";
56432
+ var DEFAULT_ROOT_CONFIG_FILE_NAME2 = `~/${CREDENTIALS_DIR_NAME2}/${GLOBAL_CONFIG_FILE_NAME2}`;
56433
+ var DEFAULT_ROOT_CONFIG_TEMP2 = `~/${CREDENTIALS_DIR_NAME2}/tmp`;
56421
56434
  var AuthModule = class {
56422
56435
  #client;
56423
56436
  constructor(client) {
56424
56437
  this.#client = client;
56425
56438
  }
56439
+ #oauthPath = (path3) => !process.env.BUGBUG_APP_URL && this.#client.getConfig().apiUrl === DEFAULT_API_URL2 ? `/rest${path3}` : path3;
56426
56440
  getAuth = async (params, options = {}) => {
56427
- const response = await this.#client.getAppRoot("/auth/authorize-url", {
56428
- ...options,
56429
- authenticated: false,
56430
- acceptRedirect: true,
56431
- redirect: "manual",
56432
- queryParams: {
56433
- client_id: params.clientId,
56434
- redirect_uri: params.redirectUri,
56435
- code_challenge: params.codeChallenge,
56436
- code_challenge_method: params.codeChallengeMethod,
56437
- state: params.state
56441
+ const response = await this.#client.getAppRoot(
56442
+ this.#oauthPath("/auth/authorize-url"),
56443
+ {
56444
+ ...options,
56445
+ authenticated: false,
56446
+ acceptRedirect: true,
56447
+ redirect: "manual",
56448
+ queryParams: {
56449
+ client_id: params.clientId,
56450
+ redirect_uri: params.redirectUri,
56451
+ code_challenge: params.codeChallenge,
56452
+ code_challenge_method: params.codeChallengeMethod,
56453
+ state: params.state
56454
+ }
56438
56455
  }
56439
- });
56456
+ );
56440
56457
  const authorizeUrl = response instanceof Response ? response.headers.get("location") : void 0;
56441
56458
  if (!authorizeUrl) {
56442
56459
  throw new Error("BugBug OAuth authorize response did not include a redirect URL.");
56443
56460
  }
56444
56461
  return { authorizeUrl: new URL(authorizeUrl, response.url).toString() };
56445
56462
  };
56446
- exchangeCode = async (payload, options = {}) => this.#client.postAppRoot("/auth/oauth/token/", {
56463
+ exchangeCode = async (payload, options = {}) => this.#client.postAppRoot(this.#oauthPath("/auth/oauth/token/"), {
56447
56464
  ...options,
56448
56465
  authenticated: false,
56449
56466
  body: {
@@ -56454,7 +56471,7 @@ var AuthModule = class {
56454
56471
  code_verifier: payload.codeVerifier
56455
56472
  }
56456
56473
  });
56457
- identity = async (options = {}) => this.#client.getAppRoot("/auth/identity", options);
56474
+ identity = async (options = {}) => this.#client.getAppRoot(this.#oauthPath("/auth/identity"), options);
56458
56475
  };
56459
56476
  var ComponentsModule = class {
56460
56477
  #client;
@@ -57269,17 +57286,26 @@ var SuitesModule = class {
57269
57286
  * @param options.pageSize - Items per page.
57270
57287
  * @param options.query - Search query matched against suite name.
57271
57288
  * @param options.ordering - Sort key; prefix with `-` for descending.
57289
+ * @param options.latestRun - Include the latest run summary for each suite.
57272
57290
  * @returns Paginated `SuitesListResponse` envelope (validated via Zod).
57273
57291
  * @throws {UnexpectedResponseError} On Zod validation failure.
57274
57292
  */
57275
57293
  list = async (options = {}) => {
57276
- const { cursor, pageSize, query: searchQuery, ordering, ...requestOptions } = options;
57294
+ const {
57295
+ cursor,
57296
+ pageSize,
57297
+ query: searchQuery,
57298
+ ordering,
57299
+ latestRun,
57300
+ ...requestOptions
57301
+ } = options;
57277
57302
  return this.#client.get("/suites/", {
57278
57303
  queryParams: {
57279
57304
  cursor,
57280
57305
  page_size: pageSize,
57281
57306
  query: searchQuery,
57282
- ordering
57307
+ ordering,
57308
+ latestRun
57283
57309
  },
57284
57310
  ...requestOptions
57285
57311
  });
@@ -57530,17 +57556,26 @@ var TestsModule = class {
57530
57556
  * @param options.pageSize - Number of items per page.
57531
57557
  * @param options.query - Search query matched against test name.
57532
57558
  * @param options.ordering - Sort key; prefix with `-` for descending.
57559
+ * @param options.latestRun - Include the latest run summary for each test.
57533
57560
  * @returns Paginated `TestsListResponse` envelope (validated via Zod).
57534
57561
  * @throws {UnexpectedResponseError} When the server response fails Zod validation.
57535
57562
  */
57536
57563
  list = async (options = {}) => {
57537
- const { cursor, pageSize, query: searchQuery, ordering, ...requestOptions } = options;
57564
+ const {
57565
+ cursor,
57566
+ pageSize,
57567
+ query: searchQuery,
57568
+ ordering,
57569
+ latestRun,
57570
+ ...requestOptions
57571
+ } = options;
57538
57572
  return this.#client.get("/tests/", {
57539
57573
  queryParams: {
57540
57574
  cursor,
57541
57575
  page_size: pageSize,
57542
57576
  query: searchQuery,
57543
- ordering
57577
+ ordering,
57578
+ latestRun
57544
57579
  },
57545
57580
  ...requestOptions
57546
57581
  });
@@ -58014,18 +58049,6 @@ var VisualRegressionModule = class {
58014
58049
  };
58015
58050
  };
58016
58051
  var import_dotenv2 = __toESM2(require_main2(), 1);
58017
- var DEFAULT_CONFIG_FILE_NAME2 = "bugbug.yaml";
58018
- var DEFAULT_API_URL2 = "https://app.bugbug.io/api/v2";
58019
- var DEFAULT_YAML_SCHEMA_URL2 = `${DEFAULT_API_URL2}/schema/yaml/v1/`;
58020
- var DEFAULT_MCP_URL2 = "https://mcp.bugbug.io";
58021
- var DEFAULT_MCP_ACCESS_PATH2 = "/mcp";
58022
- var DEFAULT_MCP_ACCESS_URL2 = `${DEFAULT_MCP_URL2}${DEFAULT_MCP_ACCESS_PATH2}`;
58023
- var DOCS_BASE_URL2 = "https://docs.bugbug.io";
58024
- var DOCS_ASK_URL2 = `${DOCS_BASE_URL2}/master.md`;
58025
- var CREDENTIALS_DIR_NAME2 = ".bugbug";
58026
- var GLOBAL_CONFIG_FILE_NAME2 = "config.yaml";
58027
- var DEFAULT_ROOT_CONFIG_FILE_NAME2 = `~/${CREDENTIALS_DIR_NAME2}/${GLOBAL_CONFIG_FILE_NAME2}`;
58028
- var DEFAULT_ROOT_CONFIG_TEMP2 = `~/${CREDENTIALS_DIR_NAME2}/tmp`;
58029
58052
  var import_yaml4 = __toESM2(require_dist2(), 1);
58030
58053
  var globalConfigFilePath2 = (home = homedir2()) => resolve5(home, CREDENTIALS_DIR_NAME2, GLOBAL_CONFIG_FILE_NAME2);
58031
58054
  var readGlobalConfig2 = (home = homedir2()) => {
@@ -58170,7 +58193,7 @@ var readEnvFiles2 = (cwd) => {
58170
58193
  var buildUserAgent2 = (clientType, version) => `BugBug ${clientType.toUpperCase()} ${version}`;
58171
58194
  var package_default2 = {
58172
58195
  name: "@bugbug-io/core",
58173
- version: "13.39.1",
58196
+ version: "14.0.1",
58174
58197
  private: true,
58175
58198
  type: "module",
58176
58199
  main: "dist/index.js",
@@ -64072,13 +64095,13 @@ var showError = (message, exitCode = 1) => {
64072
64095
  };
64073
64096
  var renderInteractiveError = async (message, exitCode) => {
64074
64097
  const React = await import("react");
64075
- const { Box: Box10, render } = await import("ink");
64076
- const { StatusMessage: StatusMessage3 } = await import("@inkjs/ui");
64098
+ const { Box, render } = await import("ink");
64099
+ const { StatusMessage } = await import("@inkjs/ui");
64077
64100
  const { unmount } = render(
64078
64101
  React.createElement(
64079
- Box10,
64102
+ Box,
64080
64103
  { padding: 1 },
64081
- React.createElement(StatusMessage3, { variant: "error", children: message })
64104
+ React.createElement(StatusMessage, { variant: "error", children: message })
64082
64105
  )
64083
64106
  );
64084
64107
  setTimeout(() => {
@@ -64211,10 +64234,32 @@ var runClientCommand = (argv, options = {}) => {
64211
64234
  };
64212
64235
 
64213
64236
  // src/utils/external.ts
64237
+ var OPENABLE_URL_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
64238
+ var toOpenableUrl = (url) => {
64239
+ let parsedUrl;
64240
+ try {
64241
+ parsedUrl = new URL(url);
64242
+ } catch {
64243
+ throw new Error(`Cannot open "${url}" - it is not a valid URL.`);
64244
+ }
64245
+ if (!OPENABLE_URL_PROTOCOLS.has(parsedUrl.protocol)) {
64246
+ throw new Error(`Cannot open "${url}" - only http and https URLs can be opened.`);
64247
+ }
64248
+ return parsedUrl.toString();
64249
+ };
64214
64250
  var openExternalUrl = (url) => new Promise((resolveFn, reject) => {
64215
- const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
64216
- const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
64217
- const child = spawn(command, args, { detached: true, stdio: "ignore" });
64251
+ let openableUrl;
64252
+ try {
64253
+ openableUrl = toOpenableUrl(url);
64254
+ } catch (error3) {
64255
+ reject(error3);
64256
+ return;
64257
+ }
64258
+ const spawnOptions = { detached: true, stdio: "ignore" };
64259
+ const child = process.platform === "win32" ? spawn("cmd.exe", ["/d", "/s", "/c", `start "" "${openableUrl}"`], {
64260
+ ...spawnOptions,
64261
+ windowsVerbatimArguments: true
64262
+ }) : spawn(process.platform === "darwin" ? "open" : "xdg-open", [openableUrl], spawnOptions);
64218
64263
  child.once("error", reject);
64219
64264
  child.once("spawn", () => {
64220
64265
  child.unref();
@@ -64245,7 +64290,7 @@ var browserAuthorize = async (timeoutMs = DEFAULT_LOGIN_TIMEOUT_MS) => {
64245
64290
  state
64246
64291
  });
64247
64292
  try {
64248
- await openExternalUrl(authorizeUrl);
64293
+ await announceAuthorizeUrl(authorizeUrl);
64249
64294
  const code = await callbackServer.codePromise;
64250
64295
  const { token } = await sdk.auth.exchangeCode({
64251
64296
  grantType: "authorization_code",
@@ -64260,6 +64305,21 @@ var browserAuthorize = async (timeoutMs = DEFAULT_LOGIN_TIMEOUT_MS) => {
64260
64305
  throw error3;
64261
64306
  }
64262
64307
  };
64308
+ var announceAuthorizeUrl = async (authorizeUrl) => {
64309
+ process.stderr.write(
64310
+ `Opening your browser to authorize BugBug:
64311
+ ${authorizeUrl}
64312
+ If the browser does not open, copy the whole URL above and open it manually.
64313
+ `
64314
+ );
64315
+ try {
64316
+ await openExternalUrl(authorizeUrl);
64317
+ } catch (error3) {
64318
+ const reason = error3 instanceof Error ? error3.message : String(error3);
64319
+ process.stderr.write(`Could not open the browser automatically: ${reason}
64320
+ `);
64321
+ }
64322
+ };
64263
64323
  var createLoginCallbackServer = async (expectedState, timeoutMs) => {
64264
64324
  let finish;
64265
64325
  let fail;
@@ -64397,7 +64457,7 @@ var toRunState = (run) => {
64397
64457
  var listSuiteRuns = async (opts = {}) => {
64398
64458
  const response = await getSdk().suites.listRuns({
64399
64459
  pageSize: opts.pageSize ?? 50,
64400
- ordering: opts.ordering ?? "-started"
64460
+ ordering: opts.ordering ?? "-created"
64401
64461
  });
64402
64462
  return response.results ?? [];
64403
64463
  };
@@ -64419,43 +64479,6 @@ var stopSuiteRun = async (runId) => {
64419
64479
  };
64420
64480
  var getSuiteRunJunitReport = async (runId) => getSdk().suites.downloadRunJunitReport(runId, { timeout: 6e5 });
64421
64481
 
64422
- // src/app/routes.ts
64423
- var ROUTES = {
64424
- root: () => "/",
64425
- view: (viewKey) => `/${viewKey}`,
64426
- action: (viewKey, actionKey) => `/${viewKey}/${actionKey}`,
64427
- tests: {
64428
- list: () => "/tests/list",
64429
- details: (testId) => `/tests/${testId}`,
64430
- run: (testId) => `/tests/${testId}/run`,
64431
- lastRun: (testId) => `/tests/${testId}/lastRun`,
64432
- export: (testId) => `/tests/${testId}/export`,
64433
- open: (testId) => `/tests/${testId}/open`
64434
- },
64435
- testRuns: {
64436
- root: () => "/testruns",
64437
- list: () => "/testruns/list",
64438
- details: (runId) => `/testruns/${runId}`,
64439
- debugArtifacts: (runId) => `/testruns/${runId}/debugArtifacts`,
64440
- junitReport: (runId) => `/testruns/${runId}/junitReport`,
64441
- open: (runId) => `/testruns/${runId}/open`
64442
- },
64443
- suites: {
64444
- list: () => "/suites/list",
64445
- details: (suiteId) => `/suites/${suiteId}`,
64446
- run: (suiteId) => `/suites/${suiteId}/run`,
64447
- lastRun: (suiteId) => `/suites/${suiteId}/lastRun`,
64448
- open: (suiteId) => `/suites/${suiteId}/open`
64449
- },
64450
- suiteRuns: {
64451
- root: () => "/suiteruns",
64452
- list: () => "/suiteruns/list",
64453
- details: (runId) => `/suiteruns/${runId}`,
64454
- showTestRuns: (runId) => `/suiteruns/${runId}/showTestRuns`,
64455
- open: (runId) => `/suiteruns/${runId}/open`
64456
- }
64457
- };
64458
-
64459
64482
  // ../core/dist/utils/variables.js
64460
64483
  var parseVariables = (entries) => entries.map((entry) => {
64461
64484
  const idx = entry.indexOf("=");
@@ -64482,24 +64505,19 @@ var toOverrideArray = (vars) => {
64482
64505
  };
64483
64506
 
64484
64507
  // src/features/suites/suites.service.ts
64485
- var listSuites = async (options = {}) => getSdk().suites.getAll({ query: options.query });
64508
+ var listSuites = async (options = {}) => getSdk().suites.getAll(options);
64486
64509
  var getSuite = async (suiteId) => getSdk().suites.get(suiteId);
64487
64510
  var loadSuiteTableResources = async (query) => {
64488
- const [suites, runsResponse] = await Promise.all([
64489
- listSuites({ query: query || void 0 }),
64490
- getSdk().suites.listRuns({ pageSize: 100, ordering: "-started" })
64491
- ]);
64492
- const suiteRuns = runsResponse.results ?? [];
64493
- const resources = suites.map((suite) => {
64494
- const lastRun = suiteRuns.find((run) => run.name && run.name === suite.name);
64495
- return {
64511
+ const suites = await listSuites({ query: query || void 0, latestRun: true });
64512
+ const resources = suites.map(
64513
+ (suite) => ({
64496
64514
  id: suite.id,
64497
64515
  name: suite.name ?? void 0,
64498
- status: lastRun?.status,
64499
- lastRunId: lastRun?.id,
64500
- lastRunUrl: lastRun?.webappUrl
64501
- };
64502
- });
64516
+ status: suite.latestRun?.status,
64517
+ lastRunId: suite.latestRun?.id,
64518
+ lastRunUrl: suite.latestRun?.webappUrl
64519
+ })
64520
+ );
64503
64521
  return resources.toSorted(
64504
64522
  (a, b2) => (a.name ?? a.id).localeCompare(b2.name ?? b2.id, void 0, { sensitivity: "base" })
64505
64523
  );
@@ -64548,14 +64566,62 @@ var waitForSuiteRun = async (runId, intervalMs = 4e3, onStatusChange, timeoutMs)
64548
64566
  return toRunState(result);
64549
64567
  };
64550
64568
 
64569
+ // src/features/testRuns/testRuns.service.ts
64570
+ var listTestRuns = async (opts = {}) => {
64571
+ const response = await getSdk().tests.listRuns({
64572
+ pageSize: opts.pageSize ?? 50,
64573
+ ordering: opts.ordering ?? "-created",
64574
+ testId: opts.testId
64575
+ });
64576
+ const all = response.results ?? [];
64577
+ if (opts.suiteRunId) {
64578
+ return all.filter((run) => run.suiteRunId === opts.suiteRunId);
64579
+ }
64580
+ return all;
64581
+ };
64582
+ var getTestRunDetails = async (runId) => getSdk().tests.getRun(runId).catch((error3) => {
64583
+ if (isNotFoundError(error3)) return void 0;
64584
+ throw error3;
64585
+ });
64586
+ var getTestRunLogs = async (runId) => getSdk().tests.getRunLogs(runId);
64587
+ var getTestRun = async (runId) => {
64588
+ const run = await getSdk().tests.getRun(runId);
64589
+ return toRunState(run);
64590
+ };
64591
+ var stopTestRun = async (runId) => {
64592
+ const run = await getSdk().tests.stopRun(runId);
64593
+ return toRunState(run);
64594
+ };
64595
+ var getTestRunJunitReport = async (runId) => getSdk().tests.downloadRunJunitReport(runId, { timeout: 3e5 });
64596
+ var listTestRunDebugArtifacts = async (runId) => getSdk().tests.listRunDebugArtifacts(runId);
64597
+
64551
64598
  // src/features/tests/tests.service.ts
64552
64599
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
64553
64600
  import { extname, resolve as resolve7 } from "path";
64554
- var listTests = async (options = {}) => getSdk().tests.getAll({ query: options.query });
64601
+ var listTests = async (options = {}) => getSdk().tests.getAll(options);
64555
64602
  var getTest = async (testId) => getSdk().tests.get(testId);
64556
- var toTestTableResource = async (test) => {
64603
+ var toTestTableResource = (test) => ({
64604
+ id: test.id,
64605
+ name: test.name,
64606
+ status: test.latestRun?.status,
64607
+ lastRunId: test.latestRun?.id,
64608
+ lastRunUrl: test.latestRun?.webappUrl
64609
+ });
64610
+ var loadTestTableResources = async (query) => {
64611
+ const tests = await listTests({ query: query || void 0, latestRun: true });
64612
+ const resources = tests.map(toTestTableResource);
64613
+ return resources.toSorted(
64614
+ (a, b2) => (a.name ?? a.id).localeCompare(b2.name ?? b2.id, void 0, { sensitivity: "base" })
64615
+ );
64616
+ };
64617
+ var getTestDetails = async (testId) => {
64618
+ const test = await getTest(testId).catch((error3) => {
64619
+ if (isNotFoundError(error3)) return void 0;
64620
+ throw error3;
64621
+ });
64622
+ if (!test) return void 0;
64557
64623
  const response = await getSdk().tests.listRuns({
64558
- testId: test.id,
64624
+ testId,
64559
64625
  pageSize: 1,
64560
64626
  ordering: "-started"
64561
64627
  });
@@ -64568,21 +64634,6 @@ var toTestTableResource = async (test) => {
64568
64634
  lastRunUrl: lastRun?.webappUrl
64569
64635
  };
64570
64636
  };
64571
- var loadTestTableResources = async (query) => {
64572
- const tests = await listTests({ query: query || void 0 });
64573
- const resources = await Promise.all(tests.map(toTestTableResource));
64574
- return resources.toSorted(
64575
- (a, b2) => (a.name ?? a.id).localeCompare(b2.name ?? b2.id, void 0, { sensitivity: "base" })
64576
- );
64577
- };
64578
- var getTestDetails = async (testId) => {
64579
- const test = await getTest(testId).catch((error3) => {
64580
- if (isNotFoundError(error3)) return void 0;
64581
- throw error3;
64582
- });
64583
- if (!test) return void 0;
64584
- return toTestTableResource({ id: test.id, name: test.name });
64585
- };
64586
64637
  var runTest = async (testId, options = {}) => {
64587
64638
  const result = await getSdk().tests.startRun(testId, {
64588
64639
  profileName: options.profile,
@@ -64633,35 +64684,6 @@ var importTest = async (file, options = {}) => {
64633
64684
  });
64634
64685
  };
64635
64686
 
64636
- // src/features/testRuns/testRuns.service.ts
64637
- var listTestRuns = async (opts = {}) => {
64638
- const response = await getSdk().tests.listRuns({
64639
- pageSize: opts.pageSize ?? 50,
64640
- ordering: opts.ordering ?? "-started",
64641
- testId: opts.testId
64642
- });
64643
- const all = response.results ?? [];
64644
- if (opts.suiteRunId) {
64645
- return all.filter((run) => run.suiteRunId === opts.suiteRunId);
64646
- }
64647
- return all;
64648
- };
64649
- var getTestRunDetails = async (runId) => getSdk().tests.getRun(runId).catch((error3) => {
64650
- if (isNotFoundError(error3)) return void 0;
64651
- throw error3;
64652
- });
64653
- var getTestRunLogs = async (runId) => getSdk().tests.getRunLogs(runId);
64654
- var getTestRun = async (runId) => {
64655
- const run = await getSdk().tests.getRun(runId);
64656
- return toRunState(run);
64657
- };
64658
- var stopTestRun = async (runId) => {
64659
- const run = await getSdk().tests.stopRun(runId);
64660
- return toRunState(run);
64661
- };
64662
- var getTestRunJunitReport = async (runId) => getSdk().tests.downloadRunJunitReport(runId, { timeout: 3e5 });
64663
- var listTestRunDebugArtifacts = async (runId) => getSdk().tests.listRunDebugArtifacts(runId);
64664
-
64665
64687
  // src/utils/reporter.utils.ts
64666
64688
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync6 } from "fs";
64667
64689
  import { dirname as dirname6, resolve as resolve8 } from "path";
@@ -64690,8 +64712,8 @@ var writeReportXml = (xml, output) => {
64690
64712
 
64691
64713
  // src/utils/runReport.ts
64692
64714
  var TITLES = {
64693
- test: "Test run report",
64694
- suite: "Suite run report"
64715
+ test: "Test run result",
64716
+ suite: "Suite run result"
64695
64717
  };
64696
64718
  var formatInlineRunReport = (kind, state) => {
64697
64719
  const lines = [TITLES[kind], `Run id: ${state.id}`, `Status: ${state.status}`];
@@ -64729,850 +64751,6 @@ var getRunErrorMessage = (state) => {
64729
64751
  return null;
64730
64752
  };
64731
64753
 
64732
- // src/features/tui/ShortcutController.tsx
64733
- import { useInput } from "ink";
64734
- import { createContext, useContext, useEffect, useRef } from "react";
64735
- import { jsx } from "react/jsx-runtime";
64736
- var ShortcutContext = createContext(null);
64737
- var ShortcutProvider = ({ children }) => {
64738
- const entriesRef = useRef([]);
64739
- const blockerCountRef = useRef(0);
64740
- const nextOrderRef = useRef(0);
64741
- const register2 = (handler, options = {}) => {
64742
- const entry = {
64743
- handler,
64744
- priority: options.priority ?? 0,
64745
- order: nextOrderRef.current
64746
- };
64747
- nextOrderRef.current += 1;
64748
- entriesRef.current.push(entry);
64749
- return () => {
64750
- entriesRef.current = entriesRef.current.filter((current) => current !== entry);
64751
- };
64752
- };
64753
- const block = () => {
64754
- blockerCountRef.current += 1;
64755
- return () => {
64756
- blockerCountRef.current = Math.max(0, blockerCountRef.current - 1);
64757
- };
64758
- };
64759
- useInput((input, key) => {
64760
- if (blockerCountRef.current > 0) return;
64761
- const entries = entriesRef.current.toSorted((a, b2) => {
64762
- if (a.priority !== b2.priority) return b2.priority - a.priority;
64763
- return b2.order - a.order;
64764
- });
64765
- for (const entry of entries) {
64766
- if (entry.handler({ input, key })) return;
64767
- }
64768
- });
64769
- return /* @__PURE__ */ jsx(ShortcutContext.Provider, { value: { register: register2, block }, children });
64770
- };
64771
- var useShortcutHandler = (handler, options = {}) => {
64772
- const registry = useContext(ShortcutContext);
64773
- const handlerRef = useRef(handler);
64774
- const priorityRef = useRef(options.priority);
64775
- handlerRef.current = handler;
64776
- priorityRef.current = options.priority;
64777
- useEffect(() => {
64778
- if (!registry) return void 0;
64779
- return registry.register((event) => handlerRef.current(event), {
64780
- priority: priorityRef.current
64781
- });
64782
- }, [registry]);
64783
- };
64784
- var useShortcutBlocker = (enabled = true) => {
64785
- const registry = useContext(ShortcutContext);
64786
- useEffect(() => {
64787
- if (!registry || !enabled) return void 0;
64788
- return registry.block();
64789
- }, [registry, enabled]);
64790
- };
64791
-
64792
- // src/features/tui/components/MenuList/MenuList.tsx
64793
- import { useNavigate } from "react-router";
64794
-
64795
- // src/features/tui/components/VirtualizedList/VirtualizedList.tsx
64796
- import { Box, Text, useInput as useInput2, useStdout } from "ink";
64797
- import { useRef as useRef2, useState } from "react";
64798
-
64799
- // src/features/tui/components/VirtualizedList/VirtualizedList.constants.ts
64800
- var DEFAULT_RESERVED_TERMINAL_ROWS = 2;
64801
- var MIN_VIEWPORT_ROWS = 3;
64802
- var FALLBACK_TERMINAL_ROWS = 24;
64803
-
64804
- // src/features/tui/components/VirtualizedList/VirtualizedList.utils.ts
64805
- var getVirtualizedListRange = ({
64806
- itemCount,
64807
- activeIndex,
64808
- viewportSize,
64809
- previousStart = 0
64810
- }) => {
64811
- const maxStart = Math.max(0, itemCount - viewportSize);
64812
- let start = Math.min(previousStart, maxStart);
64813
- if (activeIndex < start) start = activeIndex;
64814
- else if (activeIndex >= start + viewportSize) start = activeIndex - viewportSize + 1;
64815
- start = Math.max(0, Math.min(start, maxStart));
64816
- const end = Math.min(itemCount, start + viewportSize);
64817
- return {
64818
- start,
64819
- end,
64820
- hiddenAbove: start,
64821
- hiddenBelow: itemCount - end
64822
- };
64823
- };
64824
-
64825
- // src/features/tui/components/VirtualizedList/VirtualizedList.tsx
64826
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
64827
- var VirtualizedList = ({
64828
- items,
64829
- initialSelectedIndex = 0,
64830
- getKey,
64831
- renderItem,
64832
- onSelect,
64833
- reservedTerminalRows = DEFAULT_RESERVED_TERMINAL_ROWS,
64834
- navigationDisabled = false
64835
- }) => {
64836
- const [internalIndex, setInternalIndex] = useState(initialSelectedIndex);
64837
- const activeIndex = internalIndex;
64838
- useInput2((_input, key) => {
64839
- if (navigationDisabled) return;
64840
- if (key.upArrow) {
64841
- setInternalIndex((index) => Math.max(0, index - 1));
64842
- } else if (key.downArrow) {
64843
- setInternalIndex((index) => Math.min(Math.max(0, items.length - 1), index + 1));
64844
- } else if (key.return && onSelect) {
64845
- const item = items[activeIndex];
64846
- if (item) onSelect(item, activeIndex);
64847
- }
64848
- });
64849
- const { stdout } = useStdout();
64850
- const terminalRows = stdout?.rows ?? FALLBACK_TERMINAL_ROWS;
64851
- const viewportSize = Math.max(
64852
- MIN_VIEWPORT_ROWS,
64853
- Math.min(items.length, terminalRows - reservedTerminalRows)
64854
- );
64855
- const startRef = useRef2(0);
64856
- const { start, end, hiddenAbove, hiddenBelow } = getVirtualizedListRange({
64857
- itemCount: items.length,
64858
- activeIndex,
64859
- viewportSize,
64860
- previousStart: startRef.current
64861
- });
64862
- startRef.current = start;
64863
- const visibleItems = items.slice(start, end);
64864
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
64865
- hiddenAbove > 0 && /* @__PURE__ */ jsx2(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }, "virtualized-list-hidden-above"),
64866
- visibleItems.map((item, offset) => {
64867
- const index = start + offset;
64868
- return /* @__PURE__ */ jsx2(Box, { children: renderItem(item, index, index === activeIndex) }, getKey(item, index));
64869
- }),
64870
- hiddenBelow > 0 && /* @__PURE__ */ jsx2(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }, "virtualized-list-hidden-below")
64871
- ] });
64872
- };
64873
-
64874
- // src/features/tui/components/MenuList/MenuListItem.tsx
64875
- import { Box as Box2, Text as Text4 } from "ink";
64876
-
64877
- // src/features/tui/components/SelectableOption/SelectableOption.tsx
64878
- import { Text as Text3 } from "ink";
64879
-
64880
- // src/features/tui/theme.ts
64881
- var colors = {
64882
- brand: "#4c2b8b",
64883
- primary: "#521ec9",
64884
- primarySoft: "#8466CA",
64885
- accent: "#ffcd1c",
64886
- accentSoft: "#FFF8EA",
64887
- primaryActive: "#6029df",
64888
- primaryInactive: "#a489e2",
64889
- common: {
64890
- transparent: "transparent",
64891
- white: "#ffffff",
64892
- black: "#000000",
64893
- muted: "#f4f3fb"
64894
- },
64895
- background: {
64896
- primary: "#E8E9FF",
64897
- primary97: "#F4F3FB",
64898
- primary99: "#F9F9FF",
64899
- accent: "#FFF8EA",
64900
- surface: "#FFFFFF",
64901
- success: "#D1FBE2",
64902
- failure: "#FFF0F0",
64903
- neutral: "#FAFAFA",
64904
- highlight: "#F4F3FB",
64905
- highlightLight: "#F9F9FF"
64906
- },
64907
- text: {
64908
- normal: "#2b2b2b",
64909
- secondary: "#666666",
64910
- subtle: "#7A7F86",
64911
- lighter: "#8B8B8B",
64912
- secondaryAllCaps: "#A2A1A1",
64913
- emptyState: "#999999"
64914
- },
64915
- border: {
64916
- normal: "#2B2B2B",
64917
- dark: "#AAAAAA",
64918
- important: "#CCC9C9",
64919
- medium: "#E5E5E5",
64920
- semi: "#EBEBEB",
64921
- light: "#EFEFEF",
64922
- superLight: "#F1F1F3"
64923
- },
64924
- neutrals: {
64925
- "40": "#666666",
64926
- "80": "#CCCBCB",
64927
- "92": "#EAEAEA",
64928
- "94": "#EFEFEF",
64929
- "96": "#F5F5F5",
64930
- "97": "#F7F7F7"
64931
- },
64932
- status: {
64933
- success: "#4dbf8b",
64934
- success90: "#D1FBE2",
64935
- failure: "#e85b5b",
64936
- stopped: "#898989",
64937
- info: "blue",
64938
- debugging: "#ffcd1c",
64939
- warning: "#FFB100",
64940
- initialized: "#999999",
64941
- recording: "#EF2E51",
64942
- paused: "#ffcd1c",
64943
- skipped: "#8A8A8A"
64944
- },
64945
- code: {
64946
- blue: "#82aaff",
64947
- violet: "#c792ea",
64948
- yellow: "#d4c612",
64949
- red: "#ff5370",
64950
- ruby: "#f17c83"
64951
- },
64952
- block: {
64953
- if: {
64954
- background: "#f2f8fc",
64955
- marker: "#cfeeff"
64956
- }
64957
- }
64958
- };
64959
- var theme = {
64960
- colors
64961
- };
64962
- var useTheme = () => ({ theme });
64963
-
64964
- // src/features/tui/components/SelectableOption/SelectableOption.utils.ts
64965
- var SELECTION_PREFIX = "\u25BA ";
64966
- var SELECTION_PREFIX_EMPTY = " ";
64967
- var getSelectableColors = (selected, theme2) => ({
64968
- color: selected ? "white" : void 0,
64969
- backgroundColor: selected ? theme2.colors.primary : void 0
64970
- });
64971
-
64972
- // src/features/tui/components/SelectableOption/SelectionPrefix.tsx
64973
- import { Text as Text2 } from "ink";
64974
- import { jsx as jsx3 } from "react/jsx-runtime";
64975
- var SelectionPrefix = ({ selected }) => {
64976
- const { theme: theme2 } = useTheme();
64977
- const { color, backgroundColor } = getSelectableColors(selected, theme2);
64978
- return /* @__PURE__ */ jsx3(Text2, { color, backgroundColor, children: selected ? SELECTION_PREFIX : SELECTION_PREFIX_EMPTY });
64979
- };
64980
-
64981
- // src/features/tui/components/SelectableOption/SelectableOption.tsx
64982
- import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
64983
- var SelectableOption = ({ selected, children }) => {
64984
- const { theme: theme2 } = useTheme();
64985
- const { color, backgroundColor } = getSelectableColors(selected, theme2);
64986
- if (typeof children === "function") {
64987
- return /* @__PURE__ */ jsx4(Fragment, { children: children({ selected, color, backgroundColor }) });
64988
- }
64989
- return /* @__PURE__ */ jsxs2(Text3, { color, backgroundColor, children: [
64990
- /* @__PURE__ */ jsx4(SelectionPrefix, { selected }),
64991
- children
64992
- ] });
64993
- };
64994
-
64995
- // src/features/tui/components/MenuList/MenuListItem.tsx
64996
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
64997
- var MenuListItem = ({ item, selected }) => /* @__PURE__ */ jsxs3(Box2, { children: [
64998
- SelectableOption({ selected, children: item.label }),
64999
- item.description && selected && /* @__PURE__ */ jsx5(Text4, { dimColor: true, children: ` \u2014 ${item.description}` })
65000
- ] });
65001
-
65002
- // src/features/tui/components/MenuList/MenuList.tsx
65003
- import { jsx as jsx6 } from "react/jsx-runtime";
65004
- var MenuList = ({ options, onSelect }) => {
65005
- const navigate = useNavigate();
65006
- const handleSelectItem = (item) => {
65007
- if (item.to) {
65008
- navigate(item.to, { state: item.state });
65009
- return;
65010
- }
65011
- onSelect?.(item);
65012
- };
65013
- useShortcutHandler(({ input }) => {
65014
- const item = options.find((option) => option.shortcut === input);
65015
- if (!item) return false;
65016
- handleSelectItem(item);
65017
- return true;
65018
- });
65019
- return /* @__PURE__ */ jsx6(
65020
- VirtualizedList,
65021
- {
65022
- items: options,
65023
- getKey: (item) => item.key ?? item.to ?? item.label,
65024
- renderItem: (item, _index, selected) => /* @__PURE__ */ jsx6(MenuListItem, { item, selected }),
65025
- onSelect: handleSelectItem
65026
- }
65027
- );
65028
- };
65029
-
65030
- // src/features/tui/EscController.tsx
65031
- import { useInput as useInput3 } from "ink";
65032
- import { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useRef as useRef3 } from "react";
65033
- import { jsx as jsx7 } from "react/jsx-runtime";
65034
- var EscContext = createContext2(null);
65035
- var EscProvider = ({
65036
- onUnhandled,
65037
- canGoBack = true,
65038
- children
65039
- }) => {
65040
- const handlersRef = useRef3([]);
65041
- const register2 = (handler) => {
65042
- handlersRef.current.push(handler);
65043
- return () => {
65044
- handlersRef.current = handlersRef.current.filter((h) => h !== handler);
65045
- };
65046
- };
65047
- useInput3((_input, key) => {
65048
- if (!key.escape) return;
65049
- for (let i = handlersRef.current.length - 1; i >= 0; i -= 1) {
65050
- if (handlersRef.current[i]()) return;
65051
- }
65052
- onUnhandled();
65053
- });
65054
- return /* @__PURE__ */ jsx7(EscContext.Provider, { value: { register: register2, canGoBack }, children });
65055
- };
65056
- var useEscHandler = (handler) => {
65057
- const registry = useContext2(EscContext);
65058
- const handlerRef = useRef3(handler);
65059
- handlerRef.current = handler;
65060
- useEffect2(() => {
65061
- if (!registry) return void 0;
65062
- return registry.register(() => handlerRef.current());
65063
- }, [registry]);
65064
- };
65065
- var useCanGoBack = () => {
65066
- const registry = useContext2(EscContext);
65067
- return registry?.canGoBack ?? false;
65068
- };
65069
-
65070
- // src/features/tui/layouts/ViewLayout/ViewLayout.tsx
65071
- import { Box as Box3, Text as Text5, useInput as useInput4 } from "ink";
65072
- import { useEffect as useEffect3, useState as useState2 } from "react";
65073
-
65074
- // src/features/tui/layouts/ViewLayout/ViewLayout.constants.ts
65075
- var GO_BACK = "Esc to go back";
65076
- var CLOSE = "q to close";
65077
- var NAVIGATION = "\u2191/\u2193 to navigate";
65078
- var SELECT = "Enter to select";
65079
- var SEARCH = "/ search";
65080
- var HELP = "? for shortcuts";
65081
- var VIEW_HINTS = {
65082
- GO_BACK,
65083
- CLOSE,
65084
- SELECT,
65085
- SEARCH,
65086
- HELP,
65087
- SEARCH_MODE_DEFAULT: "type to search \xB7 Enter to search \xB7 Esc to clear",
65088
- NAVIGATION_SELECT: `${NAVIGATION} \xB7 ${SELECT}`,
65089
- CONFIRM: "Enter to confirm",
65090
- NAVIGATION_OPEN_SELECT: `${NAVIGATION} \xB7 Enter to open/select`
65091
- };
65092
- var HINT_TEXT = {
65093
- confirm: VIEW_HINTS.CONFIRM,
65094
- navigationOpenSelect: VIEW_HINTS.NAVIGATION_OPEN_SELECT,
65095
- navigationSelect: VIEW_HINTS.NAVIGATION_SELECT
65096
- };
65097
-
65098
- // src/features/tui/layouts/ViewLayout/ViewLayout.tsx
65099
- import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
65100
- var ViewLayout = ({
65101
- title,
65102
- hints: hintsOverride,
65103
- hintsHidden = false,
65104
- hintsPosition = "top",
65105
- searchable = false,
65106
- onSearch,
65107
- onSearchModeChange,
65108
- children
65109
- }) => {
65110
- const canGoBack = useCanGoBack();
65111
- const [searchMode, setSearchMode] = useState2(false);
65112
- const [searchText, setSearchText] = useState2("");
65113
- const defaultHints = [VIEW_HINTS.NAVIGATION_SELECT, searchable ? VIEW_HINTS.SEARCH : null];
65114
- const localHints = hintsOverride === "none" ? [] : hintsOverride !== void 0 ? [HINT_TEXT[hintsOverride]] : defaultHints;
65115
- const hintsParts = [
65116
- ...hintsHidden ? [] : localHints,
65117
- VIEW_HINTS.HELP,
65118
- canGoBack ? VIEW_HINTS.GO_BACK : VIEW_HINTS.CLOSE
65119
- ];
65120
- const hints = hintsHidden ? hintsParts.filter(Boolean).join(" \xB7 ") : searchMode ? VIEW_HINTS.SEARCH_MODE_DEFAULT : hintsParts.filter(Boolean).join(" \xB7 ");
65121
- const showSearch = searchable && (searchMode || searchText);
65122
- const showTopHints = hints && hintsPosition === "top";
65123
- const showBottomHints = hints && hintsPosition === "bottom";
65124
- useEffect3(() => {
65125
- onSearchModeChange?.(searchMode);
65126
- }, [onSearchModeChange, searchMode]);
65127
- useShortcutBlocker(searchMode);
65128
- useEscHandler(() => {
65129
- if (!searchable) return false;
65130
- if (searchMode) {
65131
- setSearchMode(false);
65132
- setSearchText("");
65133
- if (onSearch && searchText) onSearch("");
65134
- return true;
65135
- }
65136
- if (searchText) {
65137
- setSearchText("");
65138
- onSearch?.("");
65139
- return true;
65140
- }
65141
- return false;
65142
- });
65143
- useInput4((input, key) => {
65144
- if (!searchable) return;
65145
- if (searchMode) {
65146
- if (key.return) {
65147
- setSearchMode(false);
65148
- onSearch?.(searchText);
65149
- return;
65150
- }
65151
- if (key.backspace || key.delete) {
65152
- setSearchText((current) => current.slice(0, -1));
65153
- return;
65154
- }
65155
- if (input && !key.ctrl && !key.meta && !key.escape) {
65156
- setSearchText((current) => current + input);
65157
- }
65158
- return;
65159
- }
65160
- if (input === "/") setSearchMode(true);
65161
- });
65162
- return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", children: [
65163
- title && /* @__PURE__ */ jsx8(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text5, { bold: true, children: title }) }),
65164
- showTopHints && /* @__PURE__ */ jsx8(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text5, { dimColor: true, children: hints }) }),
65165
- showSearch && /* @__PURE__ */ jsx8(Box3, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text5, { children: `Search: ${searchText}${searchMode ? "\u2588" : ""}` }) }),
65166
- /* @__PURE__ */ jsx8(Box3, { flexDirection: "column", children }),
65167
- showBottomHints && /* @__PURE__ */ jsx8(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text5, { dimColor: true, children: hints }) })
65168
- ] });
65169
- };
65170
-
65171
- // src/app/components/BaseSuiteRunDetails/BaseSuiteRunDetails.tsx
65172
- import { Spinner as Spinner2, StatusMessage } from "@inkjs/ui";
65173
- import { Box as Box8, useApp } from "ink";
65174
- import { useEffect as useEffect4, useState as useState3 } from "react";
65175
-
65176
- // ../core/dist/utils/duration.js
65177
- var formatDuration = (duration, fallback) => {
65178
- let totalSeconds = null;
65179
- if (duration != null && duration !== "") {
65180
- totalSeconds = typeof duration === "number" ? duration : parseDurationString(duration);
65181
- }
65182
- if (totalSeconds == null && fallback?.started && fallback?.ended) {
65183
- const start = Date.parse(fallback.started);
65184
- const end = Date.parse(fallback.ended);
65185
- if (Number.isFinite(start) && Number.isFinite(end) && end >= start) {
65186
- totalSeconds = (end - start) / 1e3;
65187
- }
65188
- }
65189
- if (totalSeconds == null || !Number.isFinite(totalSeconds) || totalSeconds < 0) {
65190
- return "-";
65191
- }
65192
- const hours = Math.floor(totalSeconds / 3600);
65193
- const minutes = Math.floor(totalSeconds % 3600 / 60);
65194
- const seconds = totalSeconds - hours * 3600 - minutes * 60;
65195
- const secondsStr = `${seconds.toFixed(2).padStart(5, "0")}s`;
65196
- if (hours > 0) {
65197
- return `${String(hours).padStart(2, "0")}h ${String(minutes).padStart(2, "0")}m ${secondsStr}`;
65198
- }
65199
- if (minutes > 0) {
65200
- return `${String(minutes).padStart(2, "0")}m ${secondsStr}`;
65201
- }
65202
- return secondsStr;
65203
- };
65204
- var parseDurationString = (value) => {
65205
- const trimmed = value.trim();
65206
- if (trimmed === "") {
65207
- return null;
65208
- }
65209
- const numeric = Number(trimmed);
65210
- if (Number.isFinite(numeric)) {
65211
- return numeric;
65212
- }
65213
- const iso = /^P(?:(\d+(?:\.\d+)?)D)?(?:T(?:(\d+(?:\.\d+)?)H)?(?:(\d+(?:\.\d+)?)M)?(?:(\d+(?:\.\d+)?)S)?)?$/i.exec(trimmed);
65214
- if (iso) {
65215
- const days = Number(iso[1] ?? 0);
65216
- const hours = Number(iso[2] ?? 0);
65217
- const minutes = Number(iso[3] ?? 0);
65218
- const seconds = Number(iso[4] ?? 0);
65219
- return days * 86400 + hours * 3600 + minutes * 60 + seconds;
65220
- }
65221
- const hms = /^(?:(\d+):)?(\d{1,2}):(\d{1,2}(?:\.\d+)?)$/.exec(trimmed);
65222
- if (hms) {
65223
- const hours = Number(hms[1] ?? 0);
65224
- const minutes = Number(hms[2]);
65225
- const seconds = Number(hms[3]);
65226
- return hours * 3600 + minutes * 60 + seconds;
65227
- }
65228
- return null;
65229
- };
65230
-
65231
- // src/app/components/RunBody/RunBody.tsx
65232
- import { Box as Box7, Text as Text9 } from "ink";
65233
-
65234
- // src/app/components/RunProgress/RunProgress.tsx
65235
- import { Box as Box4, Text as Text6 } from "ink";
65236
-
65237
- // src/app/components/RunProgress/RunProgress.constants.ts
65238
- var BAR_WIDTH = 20;
65239
-
65240
- // src/app/components/RunProgress/RunProgress.utils.ts
65241
- var renderBar = (finished, total) => {
65242
- if (!total) return "";
65243
- const filled = Math.min(BAR_WIDTH, Math.round(finished / total * BAR_WIDTH));
65244
- return `[${"\u2588".repeat(filled)}${"\u2591".repeat(BAR_WIDTH - filled)}]`;
65245
- };
65246
-
65247
- // src/app/components/RunProgress/RunProgress.tsx
65248
- import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
65249
- var RunProgress = ({ runState, isRunning }) => {
65250
- if (!isRunning) return null;
65251
- const { progress, resultsSummary: summary } = runState;
65252
- if (progress && progress.total > 0) {
65253
- const pct = Math.round(progress.finished / progress.total * 100);
65254
- return /* @__PURE__ */ jsx9(Box4, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsxs5(Text6, { children: [
65255
- progress.unit === "steps" ? "Steps" : "Tests",
65256
- ": ",
65257
- progress.finished,
65258
- "/",
65259
- progress.total,
65260
- " ",
65261
- renderBar(progress.finished, progress.total),
65262
- " ",
65263
- pct,
65264
- "%"
65265
- ] }) });
65266
- }
65267
- if (!summary) return null;
65268
- const passed = summary.passedSteps ?? 0;
65269
- const failed = summary.failedSteps ?? 0;
65270
- const skipped = summary.skippedSteps ?? 0;
65271
- const total = summary.totalSteps;
65272
- return /* @__PURE__ */ jsxs5(Box4, { marginTop: 1, flexDirection: "column", children: [
65273
- /* @__PURE__ */ jsxs5(Text6, { children: [
65274
- "Progress: ",
65275
- passed,
65276
- " passed",
65277
- failed ? `, ${failed} failed` : "",
65278
- skipped ? `, ${skipped} skipped` : "",
65279
- total ? ` / ${total} total` : ""
65280
- ] }),
65281
- total ? /* @__PURE__ */ jsxs5(Text6, { dimColor: true, children: [
65282
- "Completion: ",
65283
- Math.round((passed + failed) / total * 100),
65284
- "%"
65285
- ] }) : null
65286
- ] });
65287
- };
65288
-
65289
- // src/app/components/Status/Status.tsx
65290
- import { Box as Box6, Text as Text8 } from "ink";
65291
-
65292
- // src/app/components/StatusIndicator/StatusIndicator.tsx
65293
- import { Spinner } from "@inkjs/ui";
65294
- import { Box as Box5, Text as Text7 } from "ink";
65295
-
65296
- // src/app/components/StatusIndicator/StatusIndicator.constants.ts
65297
- var DOT = "\u25CF";
65298
-
65299
- // src/app/components/StatusIndicator/StatusIndicator.tsx
65300
- import { jsx as jsx10 } from "react/jsx-runtime";
65301
- var StatusIndicator = ({ status, autoRetried = false }) => {
65302
- const { theme: theme2 } = useTheme();
65303
- if (autoRetried) {
65304
- return /* @__PURE__ */ jsx10(Text7, { color: theme2.colors.status.failure, children: DOT });
65305
- }
65306
- switch (status) {
65307
- case "running":
65308
- case "queued":
65309
- case "recording":
65310
- case "auto_retrying":
65311
- return /* @__PURE__ */ jsx10(Box5, { children: /* @__PURE__ */ jsx10(Spinner, {}) });
65312
- case "passed":
65313
- return /* @__PURE__ */ jsx10(Text7, { color: theme2.colors.status.success, children: DOT });
65314
- case "failed":
65315
- case "error":
65316
- return /* @__PURE__ */ jsx10(Text7, { color: theme2.colors.status.failure, children: DOT });
65317
- case "skipped":
65318
- case "stopped":
65319
- return /* @__PURE__ */ jsx10(Text7, { color: theme2.colors.status.stopped, children: DOT });
65320
- case "paused":
65321
- return /* @__PURE__ */ jsx10(Text7, { color: theme2.colors.status.paused, children: DOT });
65322
- default:
65323
- return /* @__PURE__ */ jsx10(Text7, { color: theme2.colors.status.info, children: DOT });
65324
- }
65325
- };
65326
-
65327
- // src/app/components/Status/Status.tsx
65328
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
65329
- var ERROR_CODE_STATUSES = /* @__PURE__ */ new Set([
65330
- "failed",
65331
- "error",
65332
- "passed-with-issues",
65333
- "passed_with_issues"
65334
- ]);
65335
- var Status = ({
65336
- status,
65337
- color,
65338
- backgroundColor,
65339
- autoRetried = false,
65340
- errorCode
65341
- }) => {
65342
- const label = status ? formatRunStatus(status, autoRetried) : "-";
65343
- const shouldShowErrorCode = Boolean(errorCode) && status !== void 0 && (autoRetried || ERROR_CODE_STATUSES.has(status));
65344
- return /* @__PURE__ */ jsxs6(Box6, { backgroundColor, width: "100%", children: [
65345
- status && /* @__PURE__ */ jsxs6(Fragment2, { children: [
65346
- /* @__PURE__ */ jsx11(StatusIndicator, { status, autoRetried }),
65347
- /* @__PURE__ */ jsx11(Text8, { backgroundColor, children: " " })
65348
- ] }),
65349
- /* @__PURE__ */ jsxs6(Text8, { color, backgroundColor, children: [
65350
- label,
65351
- shouldShowErrorCode ? ` (${errorCode})` : ""
65352
- ] })
65353
- ] });
65354
- };
65355
-
65356
- // src/app/components/RunBody/RunBody.tsx
65357
- import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
65358
- var RunBody = ({ runState, isRunning, isCompleted = !isRunning }) => {
65359
- const duration = formatDuration(runState.duration, {
65360
- started: runState.started,
65361
- ended: runState.ended
65362
- });
65363
- const finalResults = isCompleted ? formatFinalResults(runState) : null;
65364
- const errorMessage = isCompleted ? getRunErrorMessage(runState) : null;
65365
- return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
65366
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
65367
- /* @__PURE__ */ jsx12(Box7, { children: /* @__PURE__ */ jsxs7(Text9, { children: [
65368
- "Run id: ",
65369
- runState.id
65370
- ] }) }),
65371
- /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", rowGap: 2, children: [
65372
- /* @__PURE__ */ jsx12(Text9, { children: "Status: " }),
65373
- /* @__PURE__ */ jsx12(
65374
- Status,
65375
- {
65376
- status: runState.status,
65377
- autoRetried: runState.isAutoRetried,
65378
- errorCode: runState.errorCode
65379
- }
65380
- )
65381
- ] }),
65382
- /* @__PURE__ */ jsx12(Box7, { children: /* @__PURE__ */ jsxs7(Text9, { dimColor: true, children: [
65383
- "Duration: ",
65384
- duration
65385
- ] }) }),
65386
- finalResults ? /* @__PURE__ */ jsx12(Box7, { children: /* @__PURE__ */ jsx12(Text9, { children: finalResults }) }) : null,
65387
- errorMessage ? /* @__PURE__ */ jsx12(Box7, { children: /* @__PURE__ */ jsxs7(Text9, { children: [
65388
- "Error: ",
65389
- errorMessage
65390
- ] }) }) : null
65391
- ] }),
65392
- /* @__PURE__ */ jsx12(RunProgress, { runState, isRunning })
65393
- ] });
65394
- };
65395
-
65396
- // src/app/components/BaseSuiteRunDetails/BaseSuiteRunDetails.tsx
65397
- import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
65398
- var menuOptions = (runId, state) => [
65399
- {
65400
- label: "Show test runs",
65401
- shortcut: "t",
65402
- description: "Drill into the test runs that belong to this suite run",
65403
- to: ROUTES.suiteRuns.showTestRuns(runId),
65404
- state
65405
- },
65406
- {
65407
- label: "Open in BugBug",
65408
- shortcut: "o",
65409
- description: "Open the suite run page in your browser",
65410
- to: ROUTES.suiteRuns.open(runId),
65411
- state
65412
- }
65413
- ];
65414
- var BaseSuiteRunDetails = ({
65415
- runId,
65416
- title,
65417
- menuState,
65418
- headless = false,
65419
- intervalMs = 4e3,
65420
- timeoutMs,
65421
- exitDelayMs = 300,
65422
- onComplete,
65423
- onError: onError2
65424
- }) => {
65425
- const { exit } = useApp();
65426
- const [runState, setRunState] = useState3(null);
65427
- const [error3, setError] = useState3(null);
65428
- useEffect4(() => {
65429
- let cancelled = false;
65430
- void (async () => {
65431
- try {
65432
- const finalStatus = await waitForSuiteRun(
65433
- runId,
65434
- intervalMs,
65435
- (status) => {
65436
- if (!cancelled) setRunState(status);
65437
- },
65438
- timeoutMs
65439
- );
65440
- if (!cancelled) {
65441
- setRunState(finalStatus);
65442
- onComplete?.(finalStatus);
65443
- if (headless) setTimeout(exit, exitDelayMs);
65444
- }
65445
- } catch (err) {
65446
- if (!cancelled) {
65447
- const nextError = err instanceof Error ? err : new Error("Unknown error occurred");
65448
- setError(nextError.message);
65449
- onError2?.(nextError);
65450
- if (headless) setTimeout(exit, exitDelayMs);
65451
- }
65452
- }
65453
- })();
65454
- return () => {
65455
- cancelled = true;
65456
- };
65457
- }, [runId, intervalMs, timeoutMs, headless, exitDelayMs, exit, onComplete, onError2]);
65458
- const isRunning = runState ? isRunningStatus(runState.status) : false;
65459
- const isCompleted = runState ? isCompletedStatus(runState.status) : false;
65460
- const body = /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
65461
- error3 && /* @__PURE__ */ jsx13(StatusMessage, { variant: "error", children: `Failed to complete suite run: ${error3}` }),
65462
- !error3 && !runState && /* @__PURE__ */ jsx13(Spinner2, { label: "Initializing..." }),
65463
- !error3 && runState && /* @__PURE__ */ jsx13(RunBody, { runState, isRunning, isCompleted })
65464
- ] });
65465
- if (headless) return body;
65466
- return /* @__PURE__ */ jsxs8(
65467
- ViewLayout,
65468
- {
65469
- title,
65470
- hints: isCompleted ? "navigationSelect" : "none",
65471
- hintsHidden: !isCompleted,
65472
- hintsPosition: "bottom",
65473
- children: [
65474
- body,
65475
- isCompleted && /* @__PURE__ */ jsx13(MenuList, { options: menuOptions(runId, menuState) })
65476
- ]
65477
- }
65478
- );
65479
- };
65480
-
65481
- // src/app/components/BaseTestRunDetails/BaseTestRunDetails.tsx
65482
- import { Spinner as Spinner3, StatusMessage as StatusMessage2 } from "@inkjs/ui";
65483
- import { Box as Box9, useApp as useApp2 } from "ink";
65484
- import { useEffect as useEffect5, useState as useState4 } from "react";
65485
- import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
65486
- var getMenuOptions = (runId, state) => [
65487
- {
65488
- label: "Show run artifacts",
65489
- shortcut: "a",
65490
- description: "Browse console logs and downloadable debug artifacts",
65491
- to: ROUTES.testRuns.debugArtifacts(runId),
65492
- state
65493
- },
65494
- {
65495
- label: "Download JUnit report",
65496
- shortcut: "j",
65497
- description: "Save the JUnit XML report to the current directory",
65498
- to: ROUTES.testRuns.junitReport(runId),
65499
- state
65500
- },
65501
- {
65502
- label: "Open in BugBug",
65503
- shortcut: "o",
65504
- description: "Open the run page in your browser",
65505
- to: ROUTES.testRuns.open(runId),
65506
- state
65507
- }
65508
- ];
65509
- var BaseTestRunDetails = ({
65510
- runId,
65511
- title,
65512
- menuState,
65513
- headless = false,
65514
- intervalMs = 4e3,
65515
- timeoutMs,
65516
- exitDelayMs = 300,
65517
- onComplete,
65518
- onError: onError2
65519
- }) => {
65520
- const { exit } = useApp2();
65521
- const [runState, setRunState] = useState4(null);
65522
- const [error3, setError] = useState4(null);
65523
- useEffect5(() => {
65524
- let cancelled = false;
65525
- void (async () => {
65526
- try {
65527
- const finalStatus = await waitForTestRun(
65528
- runId,
65529
- intervalMs,
65530
- (status) => {
65531
- if (!cancelled) setRunState(status);
65532
- },
65533
- timeoutMs
65534
- );
65535
- if (!cancelled) {
65536
- setRunState(finalStatus);
65537
- onComplete?.(finalStatus);
65538
- if (headless) setTimeout(exit, exitDelayMs);
65539
- }
65540
- } catch (err) {
65541
- if (!cancelled) {
65542
- const nextError = err instanceof Error ? err : new Error("Unknown error occurred");
65543
- setError(nextError.message);
65544
- onError2?.(nextError);
65545
- if (headless) setTimeout(exit, exitDelayMs);
65546
- }
65547
- }
65548
- })();
65549
- return () => {
65550
- cancelled = true;
65551
- };
65552
- }, [runId, intervalMs, timeoutMs, headless, exitDelayMs, exit, onComplete, onError2]);
65553
- const isRunning = runState ? isRunningStatus(runState.status) : false;
65554
- const isCompleted = runState ? isCompletedStatus(runState.status) : false;
65555
- const body = /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
65556
- error3 && /* @__PURE__ */ jsx14(StatusMessage2, { variant: "error", children: `Failed to complete test run: ${error3}` }),
65557
- !error3 && !runState && /* @__PURE__ */ jsx14(Spinner3, { label: "Initializing..." }),
65558
- !error3 && runState && /* @__PURE__ */ jsx14(RunBody, { runState, isRunning })
65559
- ] });
65560
- if (headless) return body;
65561
- return /* @__PURE__ */ jsxs9(
65562
- ViewLayout,
65563
- {
65564
- title,
65565
- hints: isCompleted ? "navigationSelect" : "none",
65566
- hintsHidden: !isCompleted,
65567
- hintsPosition: "bottom",
65568
- children: [
65569
- body,
65570
- isCompleted && /* @__PURE__ */ jsx14(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx14(MenuList, { options: getMenuOptions(runId, menuState) }) })
65571
- ]
65572
- }
65573
- );
65574
- };
65575
-
65576
64754
  export {
65577
64755
  PLUGIN_PACKAGE_NAME,
65578
64756
  PLUGIN_REPO_SOURCE,
@@ -65595,6 +64773,8 @@ export {
65595
64773
  exitWith,
65596
64774
  isAuthenticationError,
65597
64775
  isAuthorizationError,
64776
+ isRunningStatus,
64777
+ isCompletedStatus,
65598
64778
  runClientCommand,
65599
64779
  openExternalUrl,
65600
64780
  formatRunStatus,
@@ -65614,6 +64794,8 @@ export {
65614
64794
  defaultJunitReportPath,
65615
64795
  writeReportXml,
65616
64796
  formatInlineRunReport,
64797
+ formatFinalResults,
64798
+ getRunErrorMessage,
65617
64799
  listSuiteRuns,
65618
64800
  getSuiteRunDetails,
65619
64801
  getSuiteRunTestRuns,
@@ -65621,28 +64803,19 @@ export {
65621
64803
  stopSuiteRun,
65622
64804
  getSuiteRunJunitReport,
65623
64805
  getVariablesMap,
65624
- formatDuration,
65625
- useTheme,
65626
- Status,
65627
- ROUTES,
65628
64806
  listSuites,
65629
64807
  getSuite,
65630
64808
  loadSuiteTableResources,
65631
64809
  getSuiteDetails,
65632
64810
  runSuite,
65633
64811
  waitForSuiteRun,
65634
- ShortcutProvider,
65635
- useShortcutHandler,
65636
- useShortcutBlocker,
65637
- DEFAULT_RESERVED_TERMINAL_ROWS,
65638
- VirtualizedList,
65639
- SelectionPrefix,
65640
- SelectableOption,
65641
- MenuList,
65642
- EscProvider,
65643
- useEscHandler,
65644
- ViewLayout,
65645
- BaseSuiteRunDetails,
64812
+ listTestRuns,
64813
+ getTestRunDetails,
64814
+ getTestRunLogs,
64815
+ getTestRun,
64816
+ stopTestRun,
64817
+ getTestRunJunitReport,
64818
+ listTestRunDebugArtifacts,
65646
64819
  listTests,
65647
64820
  getTest,
65648
64821
  loadTestTableResources,
@@ -65652,15 +64825,7 @@ export {
65652
64825
  detectFormat,
65653
64826
  exportTest,
65654
64827
  importTest,
65655
- BaseTestRunDetails,
65656
- listTestRuns,
65657
- getTestRunDetails,
65658
- getTestRunLogs,
65659
- getTestRun,
65660
- stopTestRun,
65661
- getTestRunJunitReport,
65662
- listTestRunDebugArtifacts,
65663
64828
  formatErrorMessage,
65664
64829
  showError
65665
64830
  };
65666
- //# sourceMappingURL=chunk-GNCJ7Y4W.js.map
64831
+ //# sourceMappingURL=chunk-NSSHRCIM.js.map