@flakiness/sdk 2.2.2 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,8 @@ The Flakiness SDK provides a comprehensive set of tools for creating and managin
10
10
  npm i @flakiness/sdk @flakiness/flakiness-report
11
11
  ```
12
12
 
13
+ Requires Node.js ^20.17.0 or >=22.9.0.
14
+
13
15
  ## Quick Start
14
16
 
15
17
  Here's a minimal example of creating a Flakiness JSON Report:
@@ -96,6 +98,7 @@ Use this entry point when you need to process or manipulate reports in browser-b
96
98
  ### Working with Reports
97
99
  - **`readReport()`** - Read a Flakiness report and its attachments from disk
98
100
  - **`showReport()`** - Start a local server and open the report in your browser
101
+ - **`showReportCommand()`** - Build a shell command for opening the report later with the Flakiness CLI
99
102
  - **`uploadReport()`** - Upload reports and attachments to Flakiness.io
100
103
  - **`writeReport()`** - Write reports to disk in the standard Flakiness report format
101
104
 
@@ -125,4 +128,3 @@ Use this entry point when you need to process or manipulate reports in browser-b
125
128
  ```
126
129
 
127
130
  If neither method is available, the upload is skipped with a `'skipped'` status.
128
-
package/lib/browser.js CHANGED
@@ -13,155 +13,8 @@ __export(reportUtilsBrowser_exports, {
13
13
  visitTests: () => visitTests
14
14
  });
15
15
 
16
- // node_modules/.pnpm/@flakiness+flakiness-report@0.27.0_zod@4.3.5/node_modules/@flakiness/flakiness-report/lib/flakinessReport.js
17
- var FlakinessReport;
18
- ((FlakinessReport22) => {
19
- FlakinessReport22.CATEGORY_PLAYWRIGHT = "playwright";
20
- FlakinessReport22.CATEGORY_PYTEST = "pytest";
21
- FlakinessReport22.CATEGORY_JUNIT = "junit";
22
- FlakinessReport22.STREAM_STDOUT = 1;
23
- FlakinessReport22.STREAM_STDERR = 2;
24
- })(FlakinessReport || (FlakinessReport = {}));
25
-
26
- // node_modules/.pnpm/@flakiness+flakiness-report@0.27.0_zod@4.3.5/node_modules/@flakiness/flakiness-report/lib/schema.js
27
- import z from "zod/v4";
28
- var Schema;
29
- ((Schema2) => {
30
- Schema2.CommitId = z.string().min(40).max(40);
31
- Schema2.AttachmentId = z.string().min(1).max(1024);
32
- Schema2.UnixTimestampMS = z.number().min(0);
33
- Schema2.DurationMS = z.number().min(0);
34
- Schema2.Number1Based = z.number();
35
- Schema2.GitFilePath = z.string().min(0);
36
- Schema2.Location = z.object({
37
- file: Schema2.GitFilePath,
38
- line: Schema2.Number1Based,
39
- // Note: Locations for file suites are (0, 0).
40
- column: Schema2.Number1Based
41
- });
42
- Schema2.TestStatus = z.enum(["passed", "failed", "timedOut", "skipped", "interrupted"]);
43
- Schema2.Environment = z.object({
44
- name: z.string().min(1).max(512),
45
- systemData: z.object({
46
- osName: z.string().optional(),
47
- osVersion: z.string().optional(),
48
- osArch: z.string().optional()
49
- }).optional(),
50
- metadata: z.any().optional(),
51
- userSuppliedData: z.any().optional()
52
- });
53
- Schema2.STDIOEntry = z.union([
54
- z.object({ text: z.string() }),
55
- z.object({ buffer: z.string() })
56
- ]);
57
- Schema2.STREAM_STDOUT = z.literal(FlakinessReport.STREAM_STDOUT);
58
- Schema2.STREAM_STDERR = z.literal(FlakinessReport.STREAM_STDERR);
59
- Schema2.TimedSTDIOEntry = z.object({
60
- stream: z.union([Schema2.STREAM_STDOUT, Schema2.STREAM_STDERR]).optional(),
61
- dts: Schema2.DurationMS
62
- }).and(z.union([
63
- z.object({ text: z.string() }),
64
- z.object({ buffer: z.string() })
65
- ]));
66
- Schema2.ReportError = z.object({
67
- location: Schema2.Location.optional(),
68
- message: z.string().optional(),
69
- stack: z.string().optional(),
70
- snippet: z.string().optional(),
71
- value: z.string().optional()
72
- });
73
- Schema2.SuiteType = z.enum(["file", "anonymous suite", "suite"]);
74
- Schema2.TestStep = z.object({
75
- title: z.string(),
76
- duration: Schema2.DurationMS.optional(),
77
- location: Schema2.Location.optional(),
78
- snippet: z.string().optional(),
79
- error: Schema2.ReportError.optional(),
80
- get steps() {
81
- return z.array(Schema2.TestStep).optional();
82
- }
83
- });
84
- Schema2.Attachment = z.object({
85
- name: z.string(),
86
- contentType: z.string(),
87
- id: Schema2.AttachmentId
88
- });
89
- Schema2.Annotation = z.object({
90
- type: z.string(),
91
- description: z.string().optional(),
92
- location: Schema2.Location.optional()
93
- });
94
- Schema2.RunAttempt = z.object({
95
- // Index of the environment in the environments array (must be >= 0).
96
- environmentIdx: z.number().min(0).optional(),
97
- expectedStatus: Schema2.TestStatus.optional(),
98
- status: Schema2.TestStatus.optional(),
99
- startTimestamp: Schema2.UnixTimestampMS,
100
- duration: Schema2.DurationMS.optional(),
101
- timeout: Schema2.DurationMS.optional(),
102
- annotations: z.array(Schema2.Annotation).optional(),
103
- errors: z.array(Schema2.ReportError).optional(),
104
- parallelIndex: z.number().optional(),
105
- steps: z.array(Schema2.TestStep).optional(),
106
- stdio: z.array(Schema2.TimedSTDIOEntry).optional(),
107
- stdout: z.array(Schema2.STDIOEntry).optional(),
108
- stderr: z.array(Schema2.STDIOEntry).optional(),
109
- attachments: z.array(Schema2.Attachment).optional()
110
- });
111
- Schema2.Suite = z.object({
112
- type: Schema2.SuiteType,
113
- title: z.string(),
114
- location: Schema2.Location.optional(),
115
- get suites() {
116
- return z.array(Schema2.Suite).optional();
117
- },
118
- get tests() {
119
- return z.array(Schema2.Test).optional();
120
- }
121
- });
122
- Schema2.Test = z.object({
123
- title: z.string(),
124
- location: Schema2.Location.optional(),
125
- tags: z.array(z.string()).optional(),
126
- attempts: z.array(Schema2.RunAttempt)
127
- });
128
- Schema2.SystemUtilizationSample = z.object({
129
- dts: Schema2.DurationMS,
130
- // Must be between 0 and 100 (inclusive). Can be a rational number.
131
- cpuUtilization: z.number().min(0).max(100),
132
- // Must be between 0 and 100 (inclusive). Can be a rational number.
133
- memoryUtilization: z.number().min(0).max(100)
134
- });
135
- Schema2.SystemUtilization = z.object({
136
- totalMemoryBytes: z.number().min(0),
137
- startTimestamp: Schema2.UnixTimestampMS,
138
- samples: z.array(Schema2.SystemUtilizationSample)
139
- });
140
- Schema2.UtilizationTelemetry = z.tuple([Schema2.DurationMS, z.number().min(0).max(100)]);
141
- Schema2.FlakinessProject = z.string();
142
- Schema2.Report = z.object({
143
- flakinessProject: Schema2.FlakinessProject.optional(),
144
- category: z.string().min(1).max(100),
145
- commitId: Schema2.CommitId,
146
- relatedCommitIds: z.array(Schema2.CommitId).optional(),
147
- configPath: Schema2.GitFilePath.optional(),
148
- url: z.string().optional(),
149
- environments: z.array(Schema2.Environment).min(1),
150
- suites: z.array(Schema2.Suite).optional(),
151
- tests: z.array(Schema2.Test).optional(),
152
- unattributedErrors: z.array(Schema2.ReportError).optional(),
153
- startTimestamp: Schema2.UnixTimestampMS,
154
- duration: Schema2.DurationMS,
155
- systemUtilization: z.optional(Schema2.SystemUtilization),
156
- cpuCount: z.number().min(0).optional(),
157
- cpuAvg: z.array(Schema2.UtilizationTelemetry).optional(),
158
- cpuMax: z.array(Schema2.UtilizationTelemetry).optional(),
159
- ram: z.array(Schema2.UtilizationTelemetry).optional(),
160
- ramBytes: z.number().min(0).optional()
161
- });
162
- })(Schema || (Schema = {}));
163
-
164
16
  // src/normalizeReport.ts
17
+ import { FlakinessReport } from "@flakiness/flakiness-report";
165
18
  import stableObjectHash from "stable-hash";
166
19
  var Multimap = class {
167
20
  _map = /* @__PURE__ */ new Map();
@@ -320,7 +173,8 @@ function computeTestId(test, suiteId) {
320
173
  }
321
174
 
322
175
  // src/validateReport.ts
323
- import z2 from "zod/v4";
176
+ import { Schema } from "@flakiness/flakiness-report";
177
+ import z from "zod/v4";
324
178
  function validateReport(report) {
325
179
  const validation = Schema.Report.safeParse(report);
326
180
  if (!validation.success) {
@@ -328,7 +182,7 @@ function validateReport(report) {
328
182
  const allIssues = validation.error.issues;
329
183
  const shownIssues = allIssues.slice(0, MAX_ISSUES);
330
184
  const remaining = allIssues.length - shownIssues.length;
331
- const base = [z2.prettifyError(new z2.ZodError(shownIssues))];
185
+ const base = [z.prettifyError(new z.ZodError(shownIssues))];
332
186
  if (remaining > 0)
333
187
  base.push(`... and ${remaining} more issue${remaining === 1 ? "" : "s"} ...`);
334
188
  return base.join("\n");
package/lib/index.js CHANGED
@@ -679,155 +679,8 @@ function createEnvironment(options) {
679
679
  };
680
680
  }
681
681
 
682
- // node_modules/.pnpm/@flakiness+flakiness-report@0.27.0_zod@4.3.5/node_modules/@flakiness/flakiness-report/lib/flakinessReport.js
683
- var FlakinessReport;
684
- ((FlakinessReport22) => {
685
- FlakinessReport22.CATEGORY_PLAYWRIGHT = "playwright";
686
- FlakinessReport22.CATEGORY_PYTEST = "pytest";
687
- FlakinessReport22.CATEGORY_JUNIT = "junit";
688
- FlakinessReport22.STREAM_STDOUT = 1;
689
- FlakinessReport22.STREAM_STDERR = 2;
690
- })(FlakinessReport || (FlakinessReport = {}));
691
-
692
- // node_modules/.pnpm/@flakiness+flakiness-report@0.27.0_zod@4.3.5/node_modules/@flakiness/flakiness-report/lib/schema.js
693
- import z from "zod/v4";
694
- var Schema;
695
- ((Schema2) => {
696
- Schema2.CommitId = z.string().min(40).max(40);
697
- Schema2.AttachmentId = z.string().min(1).max(1024);
698
- Schema2.UnixTimestampMS = z.number().min(0);
699
- Schema2.DurationMS = z.number().min(0);
700
- Schema2.Number1Based = z.number();
701
- Schema2.GitFilePath = z.string().min(0);
702
- Schema2.Location = z.object({
703
- file: Schema2.GitFilePath,
704
- line: Schema2.Number1Based,
705
- // Note: Locations for file suites are (0, 0).
706
- column: Schema2.Number1Based
707
- });
708
- Schema2.TestStatus = z.enum(["passed", "failed", "timedOut", "skipped", "interrupted"]);
709
- Schema2.Environment = z.object({
710
- name: z.string().min(1).max(512),
711
- systemData: z.object({
712
- osName: z.string().optional(),
713
- osVersion: z.string().optional(),
714
- osArch: z.string().optional()
715
- }).optional(),
716
- metadata: z.any().optional(),
717
- userSuppliedData: z.any().optional()
718
- });
719
- Schema2.STDIOEntry = z.union([
720
- z.object({ text: z.string() }),
721
- z.object({ buffer: z.string() })
722
- ]);
723
- Schema2.STREAM_STDOUT = z.literal(FlakinessReport.STREAM_STDOUT);
724
- Schema2.STREAM_STDERR = z.literal(FlakinessReport.STREAM_STDERR);
725
- Schema2.TimedSTDIOEntry = z.object({
726
- stream: z.union([Schema2.STREAM_STDOUT, Schema2.STREAM_STDERR]).optional(),
727
- dts: Schema2.DurationMS
728
- }).and(z.union([
729
- z.object({ text: z.string() }),
730
- z.object({ buffer: z.string() })
731
- ]));
732
- Schema2.ReportError = z.object({
733
- location: Schema2.Location.optional(),
734
- message: z.string().optional(),
735
- stack: z.string().optional(),
736
- snippet: z.string().optional(),
737
- value: z.string().optional()
738
- });
739
- Schema2.SuiteType = z.enum(["file", "anonymous suite", "suite"]);
740
- Schema2.TestStep = z.object({
741
- title: z.string(),
742
- duration: Schema2.DurationMS.optional(),
743
- location: Schema2.Location.optional(),
744
- snippet: z.string().optional(),
745
- error: Schema2.ReportError.optional(),
746
- get steps() {
747
- return z.array(Schema2.TestStep).optional();
748
- }
749
- });
750
- Schema2.Attachment = z.object({
751
- name: z.string(),
752
- contentType: z.string(),
753
- id: Schema2.AttachmentId
754
- });
755
- Schema2.Annotation = z.object({
756
- type: z.string(),
757
- description: z.string().optional(),
758
- location: Schema2.Location.optional()
759
- });
760
- Schema2.RunAttempt = z.object({
761
- // Index of the environment in the environments array (must be >= 0).
762
- environmentIdx: z.number().min(0).optional(),
763
- expectedStatus: Schema2.TestStatus.optional(),
764
- status: Schema2.TestStatus.optional(),
765
- startTimestamp: Schema2.UnixTimestampMS,
766
- duration: Schema2.DurationMS.optional(),
767
- timeout: Schema2.DurationMS.optional(),
768
- annotations: z.array(Schema2.Annotation).optional(),
769
- errors: z.array(Schema2.ReportError).optional(),
770
- parallelIndex: z.number().optional(),
771
- steps: z.array(Schema2.TestStep).optional(),
772
- stdio: z.array(Schema2.TimedSTDIOEntry).optional(),
773
- stdout: z.array(Schema2.STDIOEntry).optional(),
774
- stderr: z.array(Schema2.STDIOEntry).optional(),
775
- attachments: z.array(Schema2.Attachment).optional()
776
- });
777
- Schema2.Suite = z.object({
778
- type: Schema2.SuiteType,
779
- title: z.string(),
780
- location: Schema2.Location.optional(),
781
- get suites() {
782
- return z.array(Schema2.Suite).optional();
783
- },
784
- get tests() {
785
- return z.array(Schema2.Test).optional();
786
- }
787
- });
788
- Schema2.Test = z.object({
789
- title: z.string(),
790
- location: Schema2.Location.optional(),
791
- tags: z.array(z.string()).optional(),
792
- attempts: z.array(Schema2.RunAttempt)
793
- });
794
- Schema2.SystemUtilizationSample = z.object({
795
- dts: Schema2.DurationMS,
796
- // Must be between 0 and 100 (inclusive). Can be a rational number.
797
- cpuUtilization: z.number().min(0).max(100),
798
- // Must be between 0 and 100 (inclusive). Can be a rational number.
799
- memoryUtilization: z.number().min(0).max(100)
800
- });
801
- Schema2.SystemUtilization = z.object({
802
- totalMemoryBytes: z.number().min(0),
803
- startTimestamp: Schema2.UnixTimestampMS,
804
- samples: z.array(Schema2.SystemUtilizationSample)
805
- });
806
- Schema2.UtilizationTelemetry = z.tuple([Schema2.DurationMS, z.number().min(0).max(100)]);
807
- Schema2.FlakinessProject = z.string();
808
- Schema2.Report = z.object({
809
- flakinessProject: Schema2.FlakinessProject.optional(),
810
- category: z.string().min(1).max(100),
811
- commitId: Schema2.CommitId,
812
- relatedCommitIds: z.array(Schema2.CommitId).optional(),
813
- configPath: Schema2.GitFilePath.optional(),
814
- url: z.string().optional(),
815
- environments: z.array(Schema2.Environment).min(1),
816
- suites: z.array(Schema2.Suite).optional(),
817
- tests: z.array(Schema2.Test).optional(),
818
- unattributedErrors: z.array(Schema2.ReportError).optional(),
819
- startTimestamp: Schema2.UnixTimestampMS,
820
- duration: Schema2.DurationMS,
821
- systemUtilization: z.optional(Schema2.SystemUtilization),
822
- cpuCount: z.number().min(0).optional(),
823
- cpuAvg: z.array(Schema2.UtilizationTelemetry).optional(),
824
- cpuMax: z.array(Schema2.UtilizationTelemetry).optional(),
825
- ram: z.array(Schema2.UtilizationTelemetry).optional(),
826
- ramBytes: z.number().min(0).optional()
827
- });
828
- })(Schema || (Schema = {}));
829
-
830
682
  // src/normalizeReport.ts
683
+ import { FlakinessReport } from "@flakiness/flakiness-report";
831
684
  import stableObjectHash from "stable-hash";
832
685
  var Multimap = class {
833
686
  _map = /* @__PURE__ */ new Map();
@@ -986,7 +839,8 @@ function computeTestId(test, suiteId) {
986
839
  }
987
840
 
988
841
  // src/validateReport.ts
989
- import z2 from "zod/v4";
842
+ import { Schema } from "@flakiness/flakiness-report";
843
+ import z from "zod/v4";
990
844
  function validateReport(report) {
991
845
  const validation = Schema.Report.safeParse(report);
992
846
  if (!validation.success) {
@@ -994,7 +848,7 @@ function validateReport(report) {
994
848
  const allIssues = validation.error.issues;
995
849
  const shownIssues = allIssues.slice(0, MAX_ISSUES);
996
850
  const remaining = allIssues.length - shownIssues.length;
997
- const base = [z2.prettifyError(new z2.ZodError(shownIssues))];
851
+ const base = [z.prettifyError(new z.ZodError(shownIssues))];
998
852
  if (remaining > 0)
999
853
  base.push(`... and ${remaining} more issue${remaining === 1 ? "" : "s"} ...`);
1000
854
  return base.join("\n");
@@ -1279,7 +1133,7 @@ async function listFilesRecursively(dir, result = []) {
1279
1133
  }
1280
1134
 
1281
1135
  // src/showReport.ts
1282
- import chalk from "chalk";
1136
+ import { styleText } from "node:util";
1283
1137
  import open from "open";
1284
1138
 
1285
1139
  // src/staticServer.ts
@@ -1442,7 +1296,7 @@ async function showReport(reportFolder, options) {
1442
1296
  const url = new URL(reportViewerUrl);
1443
1297
  url.searchParams.set("port", String(server.port()));
1444
1298
  url.searchParams.set("token", token);
1445
- console.log(chalk.cyan(`
1299
+ console.log(styleText("cyan", `
1446
1300
  Serving Flakiness report at ${url.toString()}
1447
1301
  Press Ctrl+C to quit.`));
1448
1302
  await open(url.toString());
@@ -1450,24 +1304,123 @@ async function showReport(reportFolder, options) {
1450
1304
  });
1451
1305
  }
1452
1306
 
1307
+ // src/showReportCommand.ts
1308
+ import fs7 from "node:fs";
1309
+ import path3 from "node:path";
1310
+ import which from "which";
1311
+ var DEFAULT_REPORT_FOLDER = "flakiness-report";
1312
+ var FLAKINESS_CLI_COMMANDS = {
1313
+ GLOBAL: "flakiness",
1314
+ PNPM: "pnpm dlx flakiness",
1315
+ NPM: "npx flakiness"
1316
+ };
1317
+ function showReportCommand(reportFolder) {
1318
+ const userCwd = path3.resolve(process.env.INIT_CWD || process.cwd());
1319
+ const flakinessCLI = detectFlakinessCLIFromEnv() ?? detectFlakinessCLIFromFilesystem(userCwd) ?? detectFlakinessCLIFromPath() ?? FLAKINESS_CLI_COMMANDS.NPM;
1320
+ const absoluteReportFolder = path3.resolve(reportFolder);
1321
+ const reportFolderArg = formatReportFolderArg(absoluteReportFolder, userCwd);
1322
+ return `${flakinessCLI} show${reportFolderArg ? ` ${reportFolderArg}` : ""}`;
1323
+ }
1324
+ function detectFlakinessCLIFromEnv() {
1325
+ const userAgent = process.env.npm_config_user_agent ?? "";
1326
+ if (userAgent.startsWith("pnpm/"))
1327
+ return FLAKINESS_CLI_COMMANDS.PNPM;
1328
+ if (userAgent.startsWith("npm/"))
1329
+ return FLAKINESS_CLI_COMMANDS.NPM;
1330
+ const execPath = process.env.npm_execpath ?? "";
1331
+ const execName = execPath ? path3.basename(execPath).toLowerCase() : "";
1332
+ if (execName.startsWith("pnpm"))
1333
+ return FLAKINESS_CLI_COMMANDS.PNPM;
1334
+ return void 0;
1335
+ }
1336
+ function detectFlakinessCLIFromFilesystem(userCwd) {
1337
+ for (const dir of ancestorDirectories(userCwd)) {
1338
+ const packageManager = parsePackageJSON(dir);
1339
+ if (packageManager === "pnpm")
1340
+ return FLAKINESS_CLI_COMMANDS.PNPM;
1341
+ if (packageManager === "npm" || packageManager === "other")
1342
+ return FLAKINESS_CLI_COMMANDS.NPM;
1343
+ if (fs7.existsSync(path3.join(dir, "pnpm-lock.yaml")))
1344
+ return FLAKINESS_CLI_COMMANDS.PNPM;
1345
+ if (fs7.existsSync(path3.join(dir, "pnpm-workspace.yaml")))
1346
+ return FLAKINESS_CLI_COMMANDS.PNPM;
1347
+ }
1348
+ return void 0;
1349
+ }
1350
+ function detectFlakinessCLIFromPath() {
1351
+ if (which.sync("flakiness", { nothrow: true }))
1352
+ return FLAKINESS_CLI_COMMANDS.GLOBAL;
1353
+ if (which.sync("npx", { nothrow: true }))
1354
+ return FLAKINESS_CLI_COMMANDS.NPM;
1355
+ if (which.sync("pnpm", { nothrow: true }))
1356
+ return FLAKINESS_CLI_COMMANDS.PNPM;
1357
+ return void 0;
1358
+ }
1359
+ function parsePackageJSON(dir) {
1360
+ const packageJsonPath = path3.join(dir, "package.json");
1361
+ if (!fs7.existsSync(packageJsonPath))
1362
+ return void 0;
1363
+ try {
1364
+ const packageJson = JSON.parse(fs7.readFileSync(packageJsonPath, "utf8"));
1365
+ if (typeof packageJson.packageManager !== "string")
1366
+ return void 0;
1367
+ if (packageJson.packageManager.startsWith("pnpm@"))
1368
+ return "pnpm";
1369
+ if (packageJson.packageManager.startsWith("npm@"))
1370
+ return "npm";
1371
+ return "other";
1372
+ } catch {
1373
+ return void 0;
1374
+ }
1375
+ }
1376
+ function ancestorDirectories(startDir) {
1377
+ const directories = [];
1378
+ let current = path3.resolve(startDir);
1379
+ while (true) {
1380
+ directories.push(current);
1381
+ const parent = path3.dirname(current);
1382
+ if (parent === current)
1383
+ return directories;
1384
+ current = parent;
1385
+ }
1386
+ }
1387
+ function formatReportFolderArg(reportFolder, userCwd) {
1388
+ if (isSamePath(reportFolder, path3.resolve(userCwd, DEFAULT_REPORT_FOLDER)))
1389
+ return "";
1390
+ const relativePath = path3.relative(userCwd, reportFolder) || ".";
1391
+ return quoteShellArgument(relativePath);
1392
+ }
1393
+ function isSamePath(left, right) {
1394
+ const normalizedLeft = path3.resolve(left);
1395
+ const normalizedRight = path3.resolve(right);
1396
+ if (process.platform === "win32")
1397
+ return normalizedLeft.toLowerCase() === normalizedRight.toLowerCase();
1398
+ return normalizedLeft === normalizedRight;
1399
+ }
1400
+ function quoteShellArgument(argument) {
1401
+ if (/^[A-Za-z0-9_./:@%+=,-]+$/u.test(argument))
1402
+ return argument;
1403
+ return JSON.stringify(argument);
1404
+ }
1405
+
1453
1406
  // src/writeReport.ts
1454
- import fs7 from "fs";
1455
- import path3 from "path";
1407
+ import fs8 from "fs";
1408
+ import path4 from "path";
1456
1409
  async function writeReport(report, attachments, outputFolder) {
1457
- const reportPath = path3.join(outputFolder, "report.json");
1458
- const attachmentsFolder = path3.join(outputFolder, "attachments");
1459
- await fs7.promises.rm(outputFolder, { recursive: true, force: true });
1460
- await fs7.promises.mkdir(outputFolder, { recursive: true });
1461
- await fs7.promises.writeFile(reportPath, JSON.stringify(report), "utf-8");
1410
+ const reportPath = path4.join(outputFolder, "report.json");
1411
+ const attachmentsFolder = path4.join(outputFolder, "attachments");
1412
+ await fs8.promises.rm(outputFolder, { recursive: true, force: true });
1413
+ await fs8.promises.mkdir(outputFolder, { recursive: true });
1414
+ await fs8.promises.writeFile(reportPath, JSON.stringify(report), "utf-8");
1462
1415
  if (attachments.length)
1463
- await fs7.promises.mkdir(attachmentsFolder);
1416
+ await fs8.promises.mkdir(attachmentsFolder);
1464
1417
  const movedAttachments = [];
1465
1418
  for (const attachment of attachments) {
1466
- const attachmentPath = path3.join(attachmentsFolder, attachment.id);
1419
+ const attachmentPath = path4.join(attachmentsFolder, attachment.id);
1467
1420
  if (attachment.type === "file")
1468
- await fs7.promises.cp(attachment.path, attachmentPath);
1421
+ await fs8.promises.cp(attachment.path, attachmentPath);
1469
1422
  else if (attachment.type === "buffer")
1470
- await fs7.promises.writeFile(attachmentPath, attachment.body);
1423
+ await fs8.promises.writeFile(attachmentPath, attachment.body);
1471
1424
  movedAttachments.push({
1472
1425
  type: "file",
1473
1426
  contentType: attachment.contentType,
@@ -1486,6 +1439,7 @@ export {
1486
1439
  reportUtils_exports as ReportUtils,
1487
1440
  readReport,
1488
1441
  showReport,
1442
+ showReportCommand,
1489
1443
  uploadReport,
1490
1444
  writeReport
1491
1445
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flakiness/sdk",
3
- "version": "2.2.2",
3
+ "version": "2.4.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,12 +24,16 @@
24
24
  "keywords": [],
25
25
  "author": "Degu Labs, Inc",
26
26
  "license": "MIT",
27
+ "engines": {
28
+ "node": "^20.17.0 || >=22.9.0"
29
+ },
27
30
  "devDependencies": {
28
- "@flakiness/flakiness-report": "^0.27.0",
29
- "@flakiness/playwright": "^1.3.2",
31
+ "@flakiness/flakiness-report": "^0.28.0",
32
+ "@flakiness/playwright": "^1.3.3",
30
33
  "@playwright/test": "^1.58.2",
31
34
  "@types/debug": "^4.1.12",
32
35
  "@types/node": "^25.0.3",
36
+ "@types/which": "^3.0.4",
33
37
  "esbuild": "^0.27.0",
34
38
  "kubik": "^0.24.0",
35
39
  "tsx": "^4.21.0",
@@ -39,14 +43,16 @@
39
43
  "@flakiness/flakiness-report": ">=0.26.0 <1.0.0"
40
44
  },
41
45
  "dependencies": {
42
- "chalk": "^5.6.2",
43
46
  "debug": "^4.4.3",
44
47
  "open": "^10.2.0",
45
48
  "stable-hash": "^0.0.6",
49
+ "which": "^6.0.1",
46
50
  "zod": "^4.3.5"
47
51
  },
48
52
  "scripts": {
49
53
  "minor": "./version.mjs minor",
50
- "patch": "./version.mjs patch"
54
+ "patch": "./version.mjs patch",
55
+ "test": "pnpm playwright test",
56
+ "build": "kubik ./build.mts"
51
57
  }
52
58
  }
@@ -6,6 +6,7 @@ export { GithubOIDC } from './githubOIDC.js';
6
6
  export * as ReportUtils from './reportUtils.js';
7
7
  export { readReport } from './readReport.js';
8
8
  export { showReport } from './showReport.js';
9
+ export { showReportCommand } from './showReportCommand.js';
9
10
  export { uploadReport } from './uploadReport.js';
10
11
  export { writeReport } from './writeReport.js';
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Builds a command that opens a Flakiness report with the Flakiness CLI.
3
+ *
4
+ * The command is tailored for the shell directory from which the current process
5
+ * was originally invoked. This matters when package managers like pnpm change the
6
+ * working directory while running scripts.
7
+ *
8
+ * @param {string} reportFolder - Absolute or relative path to the report folder.
9
+ *
10
+ * @returns {string} A shell command such as `pnpm dlx flakiness show`.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const command = showReportCommand('./flakiness-report');
15
+ * // Returns: "npx flakiness show"
16
+ * ```
17
+ */
18
+ export declare function showReportCommand(reportFolder: string): string;
19
+ //# sourceMappingURL=showReportCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"showReportCommand.d.ts","sourceRoot":"","sources":["../../src/showReportCommand.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAM9D"}
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * @example
13
13
  * ```typescript
14
- * const clean = stripAnsi(chalk.red('Error: test failed'));
14
+ * const clean = stripAnsi('\u001B[31mError: test failed\u001B[39m');
15
15
  * // Returns: 'Error: test failed' (without color codes)
16
16
  * ```
17
17
  */