@bugbug-io/cli 13.39.3 → 14.0.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.
@@ -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.0",
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 };
@@ -57269,17 +57270,26 @@ var SuitesModule = class {
57269
57270
  * @param options.pageSize - Items per page.
57270
57271
  * @param options.query - Search query matched against suite name.
57271
57272
  * @param options.ordering - Sort key; prefix with `-` for descending.
57273
+ * @param options.latestRun - Include the latest run summary for each suite.
57272
57274
  * @returns Paginated `SuitesListResponse` envelope (validated via Zod).
57273
57275
  * @throws {UnexpectedResponseError} On Zod validation failure.
57274
57276
  */
57275
57277
  list = async (options = {}) => {
57276
- const { cursor, pageSize, query: searchQuery, ordering, ...requestOptions } = options;
57278
+ const {
57279
+ cursor,
57280
+ pageSize,
57281
+ query: searchQuery,
57282
+ ordering,
57283
+ latestRun,
57284
+ ...requestOptions
57285
+ } = options;
57277
57286
  return this.#client.get("/suites/", {
57278
57287
  queryParams: {
57279
57288
  cursor,
57280
57289
  page_size: pageSize,
57281
57290
  query: searchQuery,
57282
- ordering
57291
+ ordering,
57292
+ latestRun
57283
57293
  },
57284
57294
  ...requestOptions
57285
57295
  });
@@ -57530,17 +57540,26 @@ var TestsModule = class {
57530
57540
  * @param options.pageSize - Number of items per page.
57531
57541
  * @param options.query - Search query matched against test name.
57532
57542
  * @param options.ordering - Sort key; prefix with `-` for descending.
57543
+ * @param options.latestRun - Include the latest run summary for each test.
57533
57544
  * @returns Paginated `TestsListResponse` envelope (validated via Zod).
57534
57545
  * @throws {UnexpectedResponseError} When the server response fails Zod validation.
57535
57546
  */
57536
57547
  list = async (options = {}) => {
57537
- const { cursor, pageSize, query: searchQuery, ordering, ...requestOptions } = options;
57548
+ const {
57549
+ cursor,
57550
+ pageSize,
57551
+ query: searchQuery,
57552
+ ordering,
57553
+ latestRun,
57554
+ ...requestOptions
57555
+ } = options;
57538
57556
  return this.#client.get("/tests/", {
57539
57557
  queryParams: {
57540
57558
  cursor,
57541
57559
  page_size: pageSize,
57542
57560
  query: searchQuery,
57543
- ordering
57561
+ ordering,
57562
+ latestRun
57544
57563
  },
57545
57564
  ...requestOptions
57546
57565
  });
@@ -58170,7 +58189,7 @@ var readEnvFiles2 = (cwd) => {
58170
58189
  var buildUserAgent2 = (clientType, version) => `BugBug ${clientType.toUpperCase()} ${version}`;
58171
58190
  var package_default2 = {
58172
58191
  name: "@bugbug-io/core",
58173
- version: "13.39.1",
58192
+ version: "14.0.0",
58174
58193
  private: true,
58175
58194
  type: "module",
58176
58195
  main: "dist/index.js",
@@ -64072,13 +64091,13 @@ var showError = (message, exitCode = 1) => {
64072
64091
  };
64073
64092
  var renderInteractiveError = async (message, exitCode) => {
64074
64093
  const React = await import("react");
64075
- const { Box: Box10, render } = await import("ink");
64076
- const { StatusMessage: StatusMessage3 } = await import("@inkjs/ui");
64094
+ const { Box, render } = await import("ink");
64095
+ const { StatusMessage } = await import("@inkjs/ui");
64077
64096
  const { unmount } = render(
64078
64097
  React.createElement(
64079
- Box10,
64098
+ Box,
64080
64099
  { padding: 1 },
64081
- React.createElement(StatusMessage3, { variant: "error", children: message })
64100
+ React.createElement(StatusMessage, { variant: "error", children: message })
64082
64101
  )
64083
64102
  );
64084
64103
  setTimeout(() => {
@@ -64211,10 +64230,32 @@ var runClientCommand = (argv, options = {}) => {
64211
64230
  };
64212
64231
 
64213
64232
  // src/utils/external.ts
64233
+ var OPENABLE_URL_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
64234
+ var toOpenableUrl = (url) => {
64235
+ let parsedUrl;
64236
+ try {
64237
+ parsedUrl = new URL(url);
64238
+ } catch {
64239
+ throw new Error(`Cannot open "${url}" - it is not a valid URL.`);
64240
+ }
64241
+ if (!OPENABLE_URL_PROTOCOLS.has(parsedUrl.protocol)) {
64242
+ throw new Error(`Cannot open "${url}" - only http and https URLs can be opened.`);
64243
+ }
64244
+ return parsedUrl.toString();
64245
+ };
64214
64246
  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" });
64247
+ let openableUrl;
64248
+ try {
64249
+ openableUrl = toOpenableUrl(url);
64250
+ } catch (error3) {
64251
+ reject(error3);
64252
+ return;
64253
+ }
64254
+ const spawnOptions = { detached: true, stdio: "ignore" };
64255
+ const child = process.platform === "win32" ? spawn("cmd.exe", ["/d", "/s", "/c", `start "" "${openableUrl}"`], {
64256
+ ...spawnOptions,
64257
+ windowsVerbatimArguments: true
64258
+ }) : spawn(process.platform === "darwin" ? "open" : "xdg-open", [openableUrl], spawnOptions);
64218
64259
  child.once("error", reject);
64219
64260
  child.once("spawn", () => {
64220
64261
  child.unref();
@@ -64245,7 +64286,7 @@ var browserAuthorize = async (timeoutMs = DEFAULT_LOGIN_TIMEOUT_MS) => {
64245
64286
  state
64246
64287
  });
64247
64288
  try {
64248
- await openExternalUrl(authorizeUrl);
64289
+ await announceAuthorizeUrl(authorizeUrl);
64249
64290
  const code = await callbackServer.codePromise;
64250
64291
  const { token } = await sdk.auth.exchangeCode({
64251
64292
  grantType: "authorization_code",
@@ -64260,6 +64301,21 @@ var browserAuthorize = async (timeoutMs = DEFAULT_LOGIN_TIMEOUT_MS) => {
64260
64301
  throw error3;
64261
64302
  }
64262
64303
  };
64304
+ var announceAuthorizeUrl = async (authorizeUrl) => {
64305
+ process.stderr.write(
64306
+ `Opening your browser to authorize BugBug:
64307
+ ${authorizeUrl}
64308
+ If the browser does not open, copy the whole URL above and open it manually.
64309
+ `
64310
+ );
64311
+ try {
64312
+ await openExternalUrl(authorizeUrl);
64313
+ } catch (error3) {
64314
+ const reason = error3 instanceof Error ? error3.message : String(error3);
64315
+ process.stderr.write(`Could not open the browser automatically: ${reason}
64316
+ `);
64317
+ }
64318
+ };
64263
64319
  var createLoginCallbackServer = async (expectedState, timeoutMs) => {
64264
64320
  let finish;
64265
64321
  let fail;
@@ -64397,7 +64453,7 @@ var toRunState = (run) => {
64397
64453
  var listSuiteRuns = async (opts = {}) => {
64398
64454
  const response = await getSdk().suites.listRuns({
64399
64455
  pageSize: opts.pageSize ?? 50,
64400
- ordering: opts.ordering ?? "-started"
64456
+ ordering: opts.ordering ?? "-created"
64401
64457
  });
64402
64458
  return response.results ?? [];
64403
64459
  };
@@ -64419,43 +64475,6 @@ var stopSuiteRun = async (runId) => {
64419
64475
  };
64420
64476
  var getSuiteRunJunitReport = async (runId) => getSdk().suites.downloadRunJunitReport(runId, { timeout: 6e5 });
64421
64477
 
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
64478
  // ../core/dist/utils/variables.js
64460
64479
  var parseVariables = (entries) => entries.map((entry) => {
64461
64480
  const idx = entry.indexOf("=");
@@ -64482,24 +64501,19 @@ var toOverrideArray = (vars) => {
64482
64501
  };
64483
64502
 
64484
64503
  // src/features/suites/suites.service.ts
64485
- var listSuites = async (options = {}) => getSdk().suites.getAll({ query: options.query });
64504
+ var listSuites = async (options = {}) => getSdk().suites.getAll(options);
64486
64505
  var getSuite = async (suiteId) => getSdk().suites.get(suiteId);
64487
64506
  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 {
64507
+ const suites = await listSuites({ query: query || void 0, latestRun: true });
64508
+ const resources = suites.map(
64509
+ (suite) => ({
64496
64510
  id: suite.id,
64497
64511
  name: suite.name ?? void 0,
64498
- status: lastRun?.status,
64499
- lastRunId: lastRun?.id,
64500
- lastRunUrl: lastRun?.webappUrl
64501
- };
64502
- });
64512
+ status: suite.latestRun?.status,
64513
+ lastRunId: suite.latestRun?.id,
64514
+ lastRunUrl: suite.latestRun?.webappUrl
64515
+ })
64516
+ );
64503
64517
  return resources.toSorted(
64504
64518
  (a, b2) => (a.name ?? a.id).localeCompare(b2.name ?? b2.id, void 0, { sensitivity: "base" })
64505
64519
  );
@@ -64548,14 +64562,62 @@ var waitForSuiteRun = async (runId, intervalMs = 4e3, onStatusChange, timeoutMs)
64548
64562
  return toRunState(result);
64549
64563
  };
64550
64564
 
64565
+ // src/features/testRuns/testRuns.service.ts
64566
+ var listTestRuns = async (opts = {}) => {
64567
+ const response = await getSdk().tests.listRuns({
64568
+ pageSize: opts.pageSize ?? 50,
64569
+ ordering: opts.ordering ?? "-created",
64570
+ testId: opts.testId
64571
+ });
64572
+ const all = response.results ?? [];
64573
+ if (opts.suiteRunId) {
64574
+ return all.filter((run) => run.suiteRunId === opts.suiteRunId);
64575
+ }
64576
+ return all;
64577
+ };
64578
+ var getTestRunDetails = async (runId) => getSdk().tests.getRun(runId).catch((error3) => {
64579
+ if (isNotFoundError(error3)) return void 0;
64580
+ throw error3;
64581
+ });
64582
+ var getTestRunLogs = async (runId) => getSdk().tests.getRunLogs(runId);
64583
+ var getTestRun = async (runId) => {
64584
+ const run = await getSdk().tests.getRun(runId);
64585
+ return toRunState(run);
64586
+ };
64587
+ var stopTestRun = async (runId) => {
64588
+ const run = await getSdk().tests.stopRun(runId);
64589
+ return toRunState(run);
64590
+ };
64591
+ var getTestRunJunitReport = async (runId) => getSdk().tests.downloadRunJunitReport(runId, { timeout: 3e5 });
64592
+ var listTestRunDebugArtifacts = async (runId) => getSdk().tests.listRunDebugArtifacts(runId);
64593
+
64551
64594
  // src/features/tests/tests.service.ts
64552
64595
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
64553
64596
  import { extname, resolve as resolve7 } from "path";
64554
- var listTests = async (options = {}) => getSdk().tests.getAll({ query: options.query });
64597
+ var listTests = async (options = {}) => getSdk().tests.getAll(options);
64555
64598
  var getTest = async (testId) => getSdk().tests.get(testId);
64556
- var toTestTableResource = async (test) => {
64599
+ var toTestTableResource = (test) => ({
64600
+ id: test.id,
64601
+ name: test.name,
64602
+ status: test.latestRun?.status,
64603
+ lastRunId: test.latestRun?.id,
64604
+ lastRunUrl: test.latestRun?.webappUrl
64605
+ });
64606
+ var loadTestTableResources = async (query) => {
64607
+ const tests = await listTests({ query: query || void 0, latestRun: true });
64608
+ const resources = tests.map(toTestTableResource);
64609
+ return resources.toSorted(
64610
+ (a, b2) => (a.name ?? a.id).localeCompare(b2.name ?? b2.id, void 0, { sensitivity: "base" })
64611
+ );
64612
+ };
64613
+ var getTestDetails = async (testId) => {
64614
+ const test = await getTest(testId).catch((error3) => {
64615
+ if (isNotFoundError(error3)) return void 0;
64616
+ throw error3;
64617
+ });
64618
+ if (!test) return void 0;
64557
64619
  const response = await getSdk().tests.listRuns({
64558
- testId: test.id,
64620
+ testId,
64559
64621
  pageSize: 1,
64560
64622
  ordering: "-started"
64561
64623
  });
@@ -64568,21 +64630,6 @@ var toTestTableResource = async (test) => {
64568
64630
  lastRunUrl: lastRun?.webappUrl
64569
64631
  };
64570
64632
  };
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
64633
  var runTest = async (testId, options = {}) => {
64587
64634
  const result = await getSdk().tests.startRun(testId, {
64588
64635
  profileName: options.profile,
@@ -64633,35 +64680,6 @@ var importTest = async (file, options = {}) => {
64633
64680
  });
64634
64681
  };
64635
64682
 
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
64683
  // src/utils/reporter.utils.ts
64666
64684
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync6 } from "fs";
64667
64685
  import { dirname as dirname6, resolve as resolve8 } from "path";
@@ -64690,8 +64708,8 @@ var writeReportXml = (xml, output) => {
64690
64708
 
64691
64709
  // src/utils/runReport.ts
64692
64710
  var TITLES = {
64693
- test: "Test run report",
64694
- suite: "Suite run report"
64711
+ test: "Test run result",
64712
+ suite: "Suite run result"
64695
64713
  };
64696
64714
  var formatInlineRunReport = (kind, state) => {
64697
64715
  const lines = [TITLES[kind], `Run id: ${state.id}`, `Status: ${state.status}`];
@@ -64729,850 +64747,6 @@ var getRunErrorMessage = (state) => {
64729
64747
  return null;
64730
64748
  };
64731
64749
 
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
64750
  export {
65577
64751
  PLUGIN_PACKAGE_NAME,
65578
64752
  PLUGIN_REPO_SOURCE,
@@ -65595,6 +64769,8 @@ export {
65595
64769
  exitWith,
65596
64770
  isAuthenticationError,
65597
64771
  isAuthorizationError,
64772
+ isRunningStatus,
64773
+ isCompletedStatus,
65598
64774
  runClientCommand,
65599
64775
  openExternalUrl,
65600
64776
  formatRunStatus,
@@ -65614,6 +64790,8 @@ export {
65614
64790
  defaultJunitReportPath,
65615
64791
  writeReportXml,
65616
64792
  formatInlineRunReport,
64793
+ formatFinalResults,
64794
+ getRunErrorMessage,
65617
64795
  listSuiteRuns,
65618
64796
  getSuiteRunDetails,
65619
64797
  getSuiteRunTestRuns,
@@ -65621,28 +64799,19 @@ export {
65621
64799
  stopSuiteRun,
65622
64800
  getSuiteRunJunitReport,
65623
64801
  getVariablesMap,
65624
- formatDuration,
65625
- useTheme,
65626
- Status,
65627
- ROUTES,
65628
64802
  listSuites,
65629
64803
  getSuite,
65630
64804
  loadSuiteTableResources,
65631
64805
  getSuiteDetails,
65632
64806
  runSuite,
65633
64807
  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,
64808
+ listTestRuns,
64809
+ getTestRunDetails,
64810
+ getTestRunLogs,
64811
+ getTestRun,
64812
+ stopTestRun,
64813
+ getTestRunJunitReport,
64814
+ listTestRunDebugArtifacts,
65646
64815
  listTests,
65647
64816
  getTest,
65648
64817
  loadTestTableResources,
@@ -65652,15 +64821,7 @@ export {
65652
64821
  detectFormat,
65653
64822
  exportTest,
65654
64823
  importTest,
65655
- BaseTestRunDetails,
65656
- listTestRuns,
65657
- getTestRunDetails,
65658
- getTestRunLogs,
65659
- getTestRun,
65660
- stopTestRun,
65661
- getTestRunJunitReport,
65662
- listTestRunDebugArtifacts,
65663
64824
  formatErrorMessage,
65664
64825
  showError
65665
64826
  };
65666
- //# sourceMappingURL=chunk-GNCJ7Y4W.js.map
64827
+ //# sourceMappingURL=chunk-4IJVD32G.js.map