@emailens/cli 0.1.0 → 0.3.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
@@ -48,6 +48,32 @@ emailens export email.html --json -o ./report
48
48
  emailens export email.html --dark-mode --screenshots -o ./report
49
49
  ```
50
50
 
51
+ ### `emailens fix <file>`
52
+
53
+ Generate AI-powered fixes for email compatibility issues. Uses `@emailens/engine` analysis to build a structured prompt, then calls Claude to fix structural issues (table layouts, VML, MSO conditionals) that static snippets can't handle.
54
+
55
+ Requires `ANTHROPIC_API_KEY` environment variable and the optional `@anthropic-ai/sdk` dependency.
56
+
57
+ ```bash
58
+ emailens fix email.html # Fix and print to stdout
59
+ emailens fix email.html -o fixed.html # Write to file
60
+ emailens fix email.html --estimate # Show token estimate only (no AI call)
61
+ emailens fix email.html --clients outlook-windows # Scope to one client
62
+ emailens fix email.html --json # Full JSON output with metadata
63
+ emailens fix email.html --max-tokens 8000 # Limit prompt size
64
+ cat email.html | emailens fix - --format jsx # Pipe from stdin
65
+ ```
66
+
67
+ | Flag | Alias | Description |
68
+ |------|-------|-------------|
69
+ | `--format` | `-f` | Input format: `html`, `jsx`, `mjml`, `maizzle` |
70
+ | `--clients` | `-c` | Comma-separated client IDs to scope the fix |
71
+ | `--output` | `-o` | Write fixed code to file instead of stdout |
72
+ | `--json` | | Output as JSON (includes token estimates and metadata) |
73
+ | `--quiet` | `-q` | Suppress spinners and decorations |
74
+ | `--estimate` | | Only show token estimate without calling the AI |
75
+ | `--max-tokens` | | Maximum input tokens for the prompt (default: 16000) |
76
+
51
77
  ### `emailens clients`
52
78
 
53
79
  List all 12 supported email clients.
@@ -76,6 +102,24 @@ Preview and export add:
76
102
  | `--screenshots` | | Capture screenshots (requires `BROWSERLESS_URL`) |
77
103
  | `--out` | `-o` | Output directory |
78
104
 
105
+ ## AI Fixes
106
+
107
+ The `fix` command requires an `ANTHROPIC_API_KEY` environment variable and the `@anthropic-ai/sdk` package:
108
+
109
+ ```bash
110
+ npm install @anthropic-ai/sdk
111
+ export ANTHROPIC_API_KEY=sk-ant-...
112
+ ```
113
+
114
+ Use `--estimate` to check token usage before making an API call:
115
+
116
+ ```bash
117
+ emailens fix email.html --estimate
118
+ # Input tokens: ~4,200
119
+ # Output tokens: ~5,400
120
+ # Warnings: 23 (5 structural)
121
+ ```
122
+
79
123
  ## Framework Support
80
124
 
81
125
  The CLI can compile React Email (JSX/TSX), MJML, and Maizzle templates to HTML before analysis. Format is auto-detected from file extension, or specify with `--format`.
package/dist/index.js CHANGED
@@ -1,39 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { defineCommand as defineCommand5, runMain } from "citty";
4
+ import { defineCommand as defineCommand7, runMain } from "citty";
5
5
 
6
6
  // src/commands/analyze.ts
7
7
  import { defineCommand } from "citty";
8
8
  import ora from "ora";
9
9
  import {
10
10
  analyzeEmail,
11
- generateCompatibilityScore
11
+ generateCompatibilityScore,
12
+ warningsForClient,
13
+ CompileError
12
14
  } from "@emailens/engine";
13
15
 
14
16
  // src/utils.ts
15
17
  import { readFileSync } from "fs";
16
18
  import { EMAIL_CLIENTS } from "@emailens/engine";
17
-
18
- // src/compile/detect.ts
19
- import { extname } from "path";
20
- function detectFormat(filePath) {
21
- const ext = extname(filePath).toLowerCase();
22
- switch (ext) {
23
- case ".tsx":
24
- case ".jsx":
25
- return "jsx";
26
- case ".mjml":
27
- return "mjml";
28
- case ".html":
29
- case ".htm":
30
- return "html";
31
- default:
32
- return "html";
33
- }
34
- }
35
-
36
- // src/utils.ts
19
+ import { detectFormat } from "@emailens/engine/compile";
37
20
  var VALID_FORMATS = /* @__PURE__ */ new Set(["html", "jsx", "mjml", "maizzle"]);
38
21
  async function readInput(pathOrStdin) {
39
22
  if (pathOrStdin === "-") {
@@ -99,27 +82,8 @@ function toFramework(format) {
99
82
  return void 0;
100
83
  }
101
84
 
102
- // src/compile/index.ts
103
- async function compile(source, format, _filePath) {
104
- switch (format) {
105
- case "html":
106
- return source;
107
- case "jsx": {
108
- const { compileReactEmail } = await import("./react-email-ZWLGXROP.js");
109
- return compileReactEmail(source);
110
- }
111
- case "mjml": {
112
- const { compileMjml } = await import("./mjml-KG66APFB.js");
113
- return compileMjml(source);
114
- }
115
- case "maizzle": {
116
- const { compileMaizzle } = await import("./maizzle-JGKTYDDO.js");
117
- return compileMaizzle(source);
118
- }
119
- default:
120
- throw new Error(`Unknown format: "${format}". Use html, jsx, mjml, or maizzle.`);
121
- }
122
- }
85
+ // src/commands/analyze.ts
86
+ import { compile } from "@emailens/engine/compile";
123
87
 
124
88
  // src/output/terminal.ts
125
89
  import pc from "picocolors";
@@ -315,7 +279,7 @@ var analyze_default = defineCommand({
315
279
  scores[id] = data;
316
280
  }
317
281
  }
318
- const filteredWarnings = warnings.filter((w) => clientSet.has(w.client));
282
+ const filteredWarnings = clientIds.flatMap((id) => warningsForClient(warnings, id));
319
283
  spinner?.succeed("Analysis complete");
320
284
  if (args.json) {
321
285
  printJson({ scores, warnings: filteredWarnings });
@@ -324,7 +288,11 @@ var analyze_default = defineCommand({
324
288
  printWarnings(filteredWarnings, { quiet: args.quiet });
325
289
  }
326
290
  } catch (err) {
327
- spinner?.fail(err.message);
291
+ if (err instanceof CompileError) {
292
+ spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);
293
+ } else {
294
+ spinner?.fail(err.message);
295
+ }
328
296
  process.exit(1);
329
297
  }
330
298
  }
@@ -337,8 +305,11 @@ import {
337
305
  transformForAllClients,
338
306
  analyzeEmail as analyzeEmail2,
339
307
  generateCompatibilityScore as generateCompatibilityScore2,
340
- simulateDarkMode
308
+ simulateDarkMode,
309
+ warningsForClient as warningsForClient2,
310
+ CompileError as CompileError2
341
311
  } from "@emailens/engine";
312
+ import { compile as compile2 } from "@emailens/engine/compile";
342
313
  var preview_default = defineCommand2({
343
314
  meta: {
344
315
  name: "preview",
@@ -391,7 +362,7 @@ var preview_default = defineCommand2({
391
362
  spinner?.start("Reading input...");
392
363
  const source = await readInput(args.input);
393
364
  spinner?.succeed("Input read");
394
- const html = await compile(source, format, args.input !== "-" ? args.input : void 0);
365
+ const html = await compile2(source, format, args.input !== "-" ? args.input : void 0);
395
366
  const clientIds = resolveClients(args.clients);
396
367
  const clientSet = new Set(clientIds);
397
368
  spinner?.start("Transforming for all clients...");
@@ -408,7 +379,7 @@ var preview_default = defineCommand2({
408
379
  scores[id] = data;
409
380
  }
410
381
  }
411
- const filteredWarnings = warnings.filter((w) => clientSet.has(w.client));
382
+ const filteredWarnings = clientIds.flatMap((id) => warningsForClient2(warnings, id));
412
383
  spinner?.succeed("Analysis complete");
413
384
  let darkMode;
414
385
  if (args["dark-mode"]) {
@@ -443,7 +414,11 @@ var preview_default = defineCommand2({
443
414
  printWarnings(filteredWarnings, { quiet: args.quiet });
444
415
  }
445
416
  } catch (err) {
446
- spinner?.fail(err.message);
417
+ if (err instanceof CompileError2) {
418
+ spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);
419
+ } else {
420
+ spinner?.fail(err.message);
421
+ }
447
422
  process.exit(1);
448
423
  }
449
424
  }
@@ -515,8 +490,11 @@ import {
515
490
  transformForAllClients as transformForAllClients2,
516
491
  analyzeEmail as analyzeEmail3,
517
492
  generateCompatibilityScore as generateCompatibilityScore3,
518
- simulateDarkMode as simulateDarkMode2
493
+ simulateDarkMode as simulateDarkMode2,
494
+ warningsForClient as warningsForClient3,
495
+ CompileError as CompileError3
519
496
  } from "@emailens/engine";
497
+ import { compile as compile3 } from "@emailens/engine/compile";
520
498
 
521
499
  // src/output/html-report.ts
522
500
  import { EMAIL_CLIENTS as EMAIL_CLIENTS4 } from "@emailens/engine";
@@ -641,7 +619,7 @@ var export_default = defineCommand4({
641
619
  spinner?.start("Reading input...");
642
620
  const source = await readInput(args.input);
643
621
  spinner?.succeed("Input read");
644
- const html = await compile(source, format, args.input !== "-" ? args.input : void 0);
622
+ const html = await compile3(source, format, args.input !== "-" ? args.input : void 0);
645
623
  const clientIds = resolveClients(args.clients);
646
624
  const clientSet = new Set(clientIds);
647
625
  spinner?.start("Transforming for all clients...");
@@ -658,7 +636,7 @@ var export_default = defineCommand4({
658
636
  scores[id] = data;
659
637
  }
660
638
  }
661
- const filteredWarnings = warnings.filter((w) => clientSet.has(w.client));
639
+ const filteredWarnings = clientIds.flatMap((id) => warningsForClient3(warnings, id));
662
640
  spinner?.succeed("Analysis complete");
663
641
  let darkMode;
664
642
  if (args["dark-mode"]) {
@@ -712,24 +690,341 @@ var export_default = defineCommand4({
712
690
  console.log();
713
691
  }
714
692
  } catch (err) {
715
- spinner?.fail(err.message);
693
+ if (err instanceof CompileError3) {
694
+ spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);
695
+ } else {
696
+ spinner?.fail(err.message);
697
+ }
698
+ process.exit(1);
699
+ }
700
+ }
701
+ });
702
+
703
+ // src/commands/fix.ts
704
+ import { defineCommand as defineCommand5 } from "citty";
705
+ import ora4 from "ora";
706
+ import pc3 from "picocolors";
707
+ import {
708
+ analyzeEmail as analyzeEmail4,
709
+ generateCompatibilityScore as generateCompatibilityScore4,
710
+ generateAiFix,
711
+ estimateAiFixTokens,
712
+ AI_FIX_SYSTEM_PROMPT,
713
+ CompileError as CompileError4
714
+ } from "@emailens/engine";
715
+ import { compile as compile4 } from "@emailens/engine/compile";
716
+ var fix_default = defineCommand5({
717
+ meta: {
718
+ name: "fix",
719
+ description: "Generate AI-powered fixes for email compatibility issues"
720
+ },
721
+ args: {
722
+ input: {
723
+ type: "positional",
724
+ description: "HTML file path or - for stdin",
725
+ required: true
726
+ },
727
+ format: {
728
+ type: "string",
729
+ alias: "f",
730
+ description: "Input format: html, jsx, mjml, maizzle"
731
+ },
732
+ clients: {
733
+ type: "string",
734
+ alias: "c",
735
+ description: "Comma-separated client IDs to scope the fix"
736
+ },
737
+ output: {
738
+ type: "string",
739
+ alias: "o",
740
+ description: "Write fixed code to file instead of stdout"
741
+ },
742
+ json: {
743
+ type: "boolean",
744
+ description: "Output as JSON (includes token estimates and metadata)"
745
+ },
746
+ quiet: {
747
+ type: "boolean",
748
+ alias: "q",
749
+ description: "Suppress spinners and decorations"
750
+ },
751
+ estimate: {
752
+ type: "boolean",
753
+ description: "Only show token estimate without calling the AI"
754
+ },
755
+ "max-tokens": {
756
+ type: "string",
757
+ description: "Maximum input tokens for the prompt (default: 16000)"
758
+ }
759
+ },
760
+ async run({ args }) {
761
+ const spinner = args.quiet || args.json ? null : ora4();
762
+ try {
763
+ const format = resolveFormat(args.format, args.input);
764
+ const framework = toFramework(format);
765
+ spinner?.start("Reading input...");
766
+ const source = await readInput(args.input);
767
+ const html = await compile4(source, format, args.input !== "-" ? args.input : void 0);
768
+ spinner?.succeed("Input read");
769
+ spinner?.start("Analyzing compatibility...");
770
+ const warnings = analyzeEmail4(html, framework);
771
+ const scores = generateCompatibilityScore4(warnings);
772
+ spinner?.succeed(`Found ${warnings.length} warnings`);
773
+ if (warnings.length === 0) {
774
+ if (args.json) {
775
+ console.log(JSON.stringify({ message: "No issues found", code: source }, null, 2));
776
+ } else {
777
+ console.log(pc3.green("\n No compatibility issues found \u2014 nothing to fix.\n"));
778
+ }
779
+ return;
780
+ }
781
+ const clientIds = resolveClients(args.clients);
782
+ let scope;
783
+ let selectedClientId;
784
+ let scopedWarnings = warnings;
785
+ let scopedScores = scores;
786
+ if (args.clients && clientIds.length === 1) {
787
+ scope = "current";
788
+ selectedClientId = clientIds[0];
789
+ } else if (args.clients && clientIds.length > 1) {
790
+ const clientSet = new Set(clientIds);
791
+ scope = "all";
792
+ selectedClientId = void 0;
793
+ scopedWarnings = warnings.filter((w) => clientSet.has(w.client));
794
+ scopedScores = Object.fromEntries(
795
+ Object.entries(scores).filter(([id]) => clientSet.has(id))
796
+ );
797
+ } else {
798
+ scope = "all";
799
+ selectedClientId = void 0;
800
+ }
801
+ const maxInputTokens = args["max-tokens"] ? parseInt(args["max-tokens"], 10) : 16e3;
802
+ const estimate = await estimateAiFixTokens({
803
+ originalHtml: html,
804
+ warnings: scopedWarnings,
805
+ scores: scopedScores,
806
+ scope,
807
+ selectedClientId,
808
+ format,
809
+ maxInputTokens
810
+ });
811
+ const structuralPct = estimate.warningCount > 0 ? Math.round(estimate.structuralCount / estimate.warningCount * 100) : 0;
812
+ if (args.estimate) {
813
+ if (args.json) {
814
+ console.log(JSON.stringify(estimate, null, 2));
815
+ } else {
816
+ console.log(`
817
+ ${pc3.bold("Token Estimate")}`);
818
+ console.log(` Input tokens: ~${estimate.inputTokens.toLocaleString()}`);
819
+ console.log(` Output tokens: ~${estimate.estimatedOutputTokens.toLocaleString()}`);
820
+ console.log(` Warnings: ${estimate.warningCount} (${estimate.structuralCount} structural)`);
821
+ if (estimate.truncated) {
822
+ console.log(` ${pc3.yellow(`Truncated: ${estimate.warningsRemoved} low-priority warnings removed`)}`);
823
+ }
824
+ console.log();
825
+ }
826
+ return;
827
+ }
828
+ const apiKey = process.env.ANTHROPIC_API_KEY;
829
+ if (!apiKey) {
830
+ spinner?.fail("ANTHROPIC_API_KEY environment variable is required");
831
+ console.error(pc3.dim("\n Set it with: export ANTHROPIC_API_KEY=sk-ant-...\n"));
832
+ process.exit(1);
833
+ }
834
+ if (!args.quiet && !args.json) {
835
+ console.log(pc3.dim(` ~${estimate.inputTokens.toLocaleString()} input tokens, ${estimate.warningCount} warnings (${structuralPct}% structural)`));
836
+ if (estimate.truncated) {
837
+ console.log(pc3.yellow(` Truncated ${estimate.warningsRemoved} low-priority warnings to fit token limit`));
838
+ }
839
+ }
840
+ spinner?.start("Generating AI fix...");
841
+ let Anthropic;
842
+ try {
843
+ Anthropic = (await import("./sdk-HQZAL655.js")).default;
844
+ } catch {
845
+ spinner?.fail("@anthropic-ai/sdk is required for the fix command");
846
+ console.error(pc3.dim("\n Install it with: npm install @anthropic-ai/sdk\n"));
847
+ process.exit(1);
848
+ }
849
+ const anthropic = new Anthropic({ apiKey });
850
+ const provider = async (prompt) => {
851
+ const msg = await anthropic.messages.create({
852
+ model: "claude-sonnet-4-6",
853
+ max_tokens: 8192,
854
+ system: AI_FIX_SYSTEM_PROMPT,
855
+ messages: [{ role: "user", content: prompt }]
856
+ });
857
+ const textBlock = msg.content.find((b) => b.type === "text");
858
+ return textBlock?.type === "text" ? textBlock.text : "";
859
+ };
860
+ const result = await generateAiFix({
861
+ originalHtml: html,
862
+ warnings: scopedWarnings,
863
+ scores: scopedScores,
864
+ scope,
865
+ selectedClientId,
866
+ format,
867
+ maxInputTokens,
868
+ provider
869
+ });
870
+ spinner?.succeed(`Fixed ${result.targetedWarnings} warnings (${result.structuralCount} structural)`);
871
+ if (args.output) {
872
+ const { writeFileSync: writeFileSync2 } = await import("fs");
873
+ writeFileSync2(args.output, result.code, "utf-8");
874
+ if (!args.quiet) {
875
+ console.log(pc3.green(`
876
+ Fixed code written to ${args.output}
877
+ `));
878
+ }
879
+ } else if (args.json) {
880
+ console.log(JSON.stringify({
881
+ code: result.code,
882
+ targetedWarnings: result.targetedWarnings,
883
+ structuralCount: result.structuralCount,
884
+ tokenEstimate: result.tokenEstimate
885
+ }, null, 2));
886
+ } else {
887
+ console.log("\n" + result.code);
888
+ }
889
+ } catch (err) {
890
+ if (err instanceof CompileError4) {
891
+ spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);
892
+ } else {
893
+ spinner?.fail(err.message);
894
+ }
716
895
  process.exit(1);
717
896
  }
718
897
  }
719
898
  });
720
899
 
900
+ // src/commands/audit.ts
901
+ import { defineCommand as defineCommand6 } from "citty";
902
+ import ora5 from "ora";
903
+ import pc4 from "picocolors";
904
+ import Table3 from "cli-table3";
905
+ import {
906
+ auditEmail,
907
+ CompileError as CompileError5
908
+ } from "@emailens/engine";
909
+ import { compile as compile5 } from "@emailens/engine/compile";
910
+ var VALID_SKIPS = /* @__PURE__ */ new Set(["spam", "links", "accessibility", "images", "compatibility"]);
911
+ var audit_default = defineCommand6({
912
+ meta: {
913
+ name: "audit",
914
+ description: "Full email audit: compatibility + spam + links + accessibility + images"
915
+ },
916
+ args: {
917
+ input: {
918
+ type: "positional",
919
+ description: "HTML file path or - for stdin",
920
+ required: true
921
+ },
922
+ format: {
923
+ type: "string",
924
+ alias: "f",
925
+ description: "Input format: html, jsx, mjml, maizzle"
926
+ },
927
+ json: {
928
+ type: "boolean",
929
+ description: "Output as JSON"
930
+ },
931
+ quiet: {
932
+ type: "boolean",
933
+ alias: "q",
934
+ description: "Suppress spinners and decorations"
935
+ },
936
+ skip: {
937
+ type: "string",
938
+ description: "Comma-separated checks to skip: spam,links,accessibility,images,compatibility"
939
+ }
940
+ },
941
+ async run({ args }) {
942
+ const spinner = args.quiet || args.json ? null : ora5();
943
+ try {
944
+ const format = resolveFormat(args.format, args.input);
945
+ spinner?.start("Reading input...");
946
+ const source = await readInput(args.input);
947
+ spinner?.succeed("Input read");
948
+ const html = await compile5(source, format, args.input !== "-" ? args.input : void 0);
949
+ const skip = [];
950
+ if (args.skip) {
951
+ for (const s of args.skip.split(",").map((s2) => s2.trim()).filter(Boolean)) {
952
+ if (!VALID_SKIPS.has(s)) {
953
+ throw new Error(`Unknown skip value "${s}". Valid: ${Array.from(VALID_SKIPS).join(", ")}`);
954
+ }
955
+ skip.push(s);
956
+ }
957
+ }
958
+ spinner?.start("Running full audit...");
959
+ const framework = toFramework(format);
960
+ const report = auditEmail(html, { framework, skip });
961
+ spinner?.succeed("Audit complete");
962
+ if (args.json) {
963
+ console.log(JSON.stringify(report, null, 2));
964
+ } else {
965
+ if (!skip.includes("compatibility")) {
966
+ printScoreTable(report.compatibility.scores, report.compatibility.warnings, { quiet: args.quiet });
967
+ printWarnings(report.compatibility.warnings, { quiet: args.quiet });
968
+ }
969
+ printQualitySummary(report, skip, { quiet: args.quiet });
970
+ }
971
+ } catch (err) {
972
+ if (err instanceof CompileError5) {
973
+ spinner?.fail(`Compilation failed (${err.phase}): ${err.message}`);
974
+ } else {
975
+ spinner?.fail(err.message);
976
+ }
977
+ process.exit(1);
978
+ }
979
+ }
980
+ });
981
+ function printQualitySummary(report, skip, options) {
982
+ if (!options?.quiet) {
983
+ console.log(pc4.bold(" Quality Summary"));
984
+ console.log();
985
+ }
986
+ const table = new Table3({
987
+ head: [pc4.bold("Check"), pc4.bold("Result")],
988
+ style: { head: [], border: [] }
989
+ });
990
+ if (!skip.includes("spam")) {
991
+ const { score, level, issues } = report.spam;
992
+ const color = score >= 90 ? pc4.green : score >= 70 ? pc4.yellow : pc4.red;
993
+ table.push(["Spam Score", `${color(String(score))}/100 (${level}) \u2014 ${issues.length} issue${issues.length === 1 ? "" : "s"}`]);
994
+ }
995
+ if (!skip.includes("links")) {
996
+ const { totalLinks, issues } = report.links;
997
+ const color = issues.length === 0 ? pc4.green : pc4.yellow;
998
+ table.push(["Links", `${totalLinks} link${totalLinks === 1 ? "" : "s"} \u2014 ${color(`${issues.length} issue${issues.length === 1 ? "" : "s"}`)}`]);
999
+ }
1000
+ if (!skip.includes("accessibility")) {
1001
+ const { score, issues } = report.accessibility;
1002
+ const color = score >= 90 ? pc4.green : score >= 70 ? pc4.yellow : pc4.red;
1003
+ table.push(["Accessibility", `${color(String(score))}/100 \u2014 ${issues.length} issue${issues.length === 1 ? "" : "s"}`]);
1004
+ }
1005
+ if (!skip.includes("images")) {
1006
+ const { total, issues } = report.images;
1007
+ const color = issues.length === 0 ? pc4.green : pc4.yellow;
1008
+ table.push(["Images", `${total} image${total === 1 ? "" : "s"} \u2014 ${color(`${issues.length} issue${issues.length === 1 ? "" : "s"}`)}`]);
1009
+ }
1010
+ console.log(table.toString());
1011
+ console.log();
1012
+ }
1013
+
721
1014
  // src/index.ts
722
- var main = defineCommand5({
1015
+ var main = defineCommand7({
723
1016
  meta: {
724
1017
  name: "emailens",
725
- version: "0.1.0",
1018
+ version: "0.3.0",
726
1019
  description: "Email compatibility analysis CLI \u2014 preview how HTML emails render across 12 email clients."
727
1020
  },
728
1021
  subCommands: {
729
1022
  analyze: analyze_default,
730
1023
  preview: preview_default,
731
1024
  clients: clients_default,
732
- export: export_default
1025
+ export: export_default,
1026
+ fix: fix_default,
1027
+ audit: audit_default
733
1028
  }
734
1029
  });
735
1030
  runMain(main);