schemashift-cli 0.11.0 → 0.13.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/dist/cli.js CHANGED
@@ -6,23 +6,27 @@ import {
6
6
 
7
7
  // src/cli.ts
8
8
  init_esm_shims();
9
- import { existsSync as existsSync4, readFileSync as readFileSync4, statSync, writeFileSync as writeFileSync4 } from "fs";
10
- import { dirname as dirname2, join as join3, resolve as resolve2 } from "path";
9
+ import { existsSync as existsSync5, readFileSync as readFileSync5, statSync, writeFileSync as writeFileSync4 } from "fs";
10
+ import { dirname as dirname2, join as join4, resolve as resolve2 } from "path";
11
11
  import { fileURLToPath } from "url";
12
12
  import {
13
13
  ApprovalManager,
14
14
  BehavioralWarningAnalyzer,
15
15
  BundleEstimator,
16
16
  CompatibilityAnalyzer,
17
+ createVerificationReport,
17
18
  DetailedAnalyzer,
18
19
  detectFormLibraries,
20
+ extractSchemaNames,
21
+ formatVerificationReport,
19
22
  GovernanceEngine,
20
23
  GovernanceFixer,
21
24
  GraphExporter,
25
+ generateSamples,
22
26
  getAllMigrationTemplates,
23
27
  getMigrationTemplate,
24
28
  IncrementalTracker,
25
- loadConfig,
29
+ loadConfig as loadConfig2,
26
30
  MigrationAuditLog,
27
31
  MigrationChain,
28
32
  PerformanceAnalyzer,
@@ -35819,8 +35823,8 @@ var TIER_FEATURES = {
35819
35823
  "free"
35820
35824
  /* FREE */
35821
35825
  ]: {
35822
- maxFiles: 5,
35823
- migrations: ["yup->zod"],
35826
+ maxFiles: 10,
35827
+ migrations: ["yup->zod", "joi->zod"],
35824
35828
  devices: 1,
35825
35829
  ciSupport: false,
35826
35830
  prioritySupport: false,
@@ -36261,7 +36265,7 @@ import { createValibotToZodHandler, createZodToValibotHandler } from "@schemashi
36261
36265
  import { Command } from "commander";
36262
36266
  import { glob as glob2 } from "glob";
36263
36267
  import { Listr } from "listr2";
36264
- import pc4 from "picocolors";
36268
+ import pc5 from "picocolors";
36265
36269
 
36266
36270
  // src/backup.ts
36267
36271
  init_esm_shims();
@@ -36512,6 +36516,73 @@ function computeHunks(original, transformed, context = 3) {
36512
36516
  if (currentHunk) hunks.push(currentHunk);
36513
36517
  return hunks;
36514
36518
  }
36519
+ function generateUnifiedDiff(results) {
36520
+ const lines = [];
36521
+ for (const result of results) {
36522
+ if (!result.transformedCode || result.originalCode === result.transformedCode) continue;
36523
+ const relativePath = result.filePath.replace(`${process.cwd()}/`, "");
36524
+ lines.push(`--- a/${relativePath}`);
36525
+ lines.push(`+++ b/${relativePath}`);
36526
+ const originalLines = result.originalCode.split("\n");
36527
+ const transformedLines = result.transformedCode.split("\n");
36528
+ const hunks = computeHunks(originalLines, transformedLines);
36529
+ for (const hunk of hunks) {
36530
+ lines.push(
36531
+ `@@ -${hunk.originalStart + 1},${hunk.originalCount} +${hunk.transformedStart + 1},${hunk.transformedCount} @@`
36532
+ );
36533
+ for (const line of hunk.lines) {
36534
+ if (line.type === "remove") {
36535
+ lines.push(`-${line.content}`);
36536
+ } else if (line.type === "add") {
36537
+ lines.push(`+${line.content}`);
36538
+ } else {
36539
+ lines.push(` ${line.content}`);
36540
+ }
36541
+ }
36542
+ }
36543
+ }
36544
+ return lines.join("\n");
36545
+ }
36546
+ function generateDrySummaryTable(results) {
36547
+ const rows = [];
36548
+ for (const result of results) {
36549
+ if (!result.transformedCode || result.originalCode === result.transformedCode) continue;
36550
+ const relativePath = result.filePath.replace(`${process.cwd()}/`, "");
36551
+ const originalLines = result.originalCode.split("\n");
36552
+ const transformedLines = result.transformedCode.split("\n");
36553
+ const hunks = computeHunks(originalLines, transformedLines);
36554
+ let added = 0;
36555
+ let removed = 0;
36556
+ for (const hunk of hunks) {
36557
+ for (const line of hunk.lines) {
36558
+ if (line.type === "add") added++;
36559
+ else if (line.type === "remove") removed++;
36560
+ }
36561
+ }
36562
+ rows.push({ file: relativePath, added, removed, warnings: result.warnings.length });
36563
+ }
36564
+ if (rows.length === 0) return "";
36565
+ const maxFile = Math.max(4, ...rows.map((r) => r.file.length));
36566
+ const header = `${"File".padEnd(maxFile)} ${"Added".padStart(5)} ${"Removed".padStart(7)} ${"Warnings".padStart(8)}`;
36567
+ const separator = "\u2500".repeat(header.length);
36568
+ const lines = [header, separator];
36569
+ let totalAdded = 0;
36570
+ let totalRemoved = 0;
36571
+ let totalWarnings = 0;
36572
+ for (const row of rows) {
36573
+ lines.push(
36574
+ `${row.file.padEnd(maxFile)} ${pc.green(`+${row.added}`.padStart(5))} ${pc.red(`-${row.removed}`.padStart(7))} ${row.warnings > 0 ? pc.yellow(String(row.warnings).padStart(8)) : String(row.warnings).padStart(8)}`
36575
+ );
36576
+ totalAdded += row.added;
36577
+ totalRemoved += row.removed;
36578
+ totalWarnings += row.warnings;
36579
+ }
36580
+ lines.push(separator);
36581
+ lines.push(
36582
+ `${`${rows.length} file${rows.length !== 1 ? "s" : ""}`.padEnd(maxFile)} ${pc.green(`+${totalAdded}`.padStart(5))} ${pc.red(`-${totalRemoved}`.padStart(7))} ${totalWarnings > 0 ? pc.yellow(String(totalWarnings).padStart(8)) : String(totalWarnings).padStart(8)}`
36583
+ );
36584
+ return lines.join("\n");
36585
+ }
36515
36586
  function generateDiffSummary(results) {
36516
36587
  const changed = results.filter(
36517
36588
  (r) => r.success && r.transformedCode && r.originalCode !== r.transformedCode
@@ -36527,25 +36598,287 @@ function generateDiffSummary(results) {
36527
36598
  return parts.join(", ");
36528
36599
  }
36529
36600
 
36530
- // src/error-formatter.ts
36601
+ // src/doctor.ts
36531
36602
  init_esm_shims();
36532
- import { readFileSync as readFileSync3 } from "fs";
36603
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
36604
+ import { join as join3 } from "path";
36605
+ import { loadConfig } from "@schemashift/core";
36533
36606
  import pc2 from "picocolors";
36607
+ var SCHEMA_LIBRARIES = {
36608
+ zod: { current: "3.24", name: "Zod" },
36609
+ yup: { current: "1.6", name: "Yup" },
36610
+ joi: { current: "17.13", name: "Joi" },
36611
+ "io-ts": { current: "2.2", name: "io-ts" },
36612
+ valibot: { current: "1.0", name: "Valibot" },
36613
+ arktype: { current: "2.1", name: "ArkType" },
36614
+ superstruct: { current: "2.0", name: "Superstruct" },
36615
+ "@effect/schema": { current: "0.75", name: "Effect Schema" }
36616
+ };
36617
+ var FORM_LIBRARIES = {
36618
+ "react-hook-form": "React Hook Form",
36619
+ formik: "Formik",
36620
+ "@mantine/form": "Mantine Form"
36621
+ };
36622
+ function readPackageJson(projectPath) {
36623
+ const pkgPath = join3(projectPath, "package.json");
36624
+ if (!existsSync3(pkgPath)) return null;
36625
+ try {
36626
+ return JSON.parse(readFileSync3(pkgPath, "utf-8"));
36627
+ } catch {
36628
+ return null;
36629
+ }
36630
+ }
36631
+ function getAllDeps(pkg2) {
36632
+ const deps = pkg2.dependencies || {};
36633
+ const devDeps = pkg2.devDependencies || {};
36634
+ return { ...deps, ...devDeps };
36635
+ }
36636
+ function parseVersion(version2) {
36637
+ return version2.replace(/^[\^~>=<]+/, "").split(".").slice(0, 2).join(".");
36638
+ }
36639
+ function checkSchemaLibraries(allDeps) {
36640
+ const checks = [];
36641
+ const detected = [];
36642
+ for (const [lib, info] of Object.entries(SCHEMA_LIBRARIES)) {
36643
+ if (allDeps[lib]) {
36644
+ detected.push(lib);
36645
+ const version2 = parseVersion(allDeps[lib] ?? "");
36646
+ checks.push({
36647
+ status: "pass",
36648
+ message: `${info.name} ${allDeps[lib]} detected`
36649
+ });
36650
+ if (lib === "zod" && version2.startsWith("3.")) {
36651
+ checks.push({
36652
+ status: "warn",
36653
+ message: `${info.name} v3 detected \u2014 v4 is available with performance improvements`,
36654
+ suggestion: `schemashift migrate ./src -f zod-v3 -t v4 --dry-run`
36655
+ });
36656
+ }
36657
+ if (lib === "io-ts") {
36658
+ checks.push({
36659
+ status: "info",
36660
+ message: "io-ts is maintained but succeeded by Effect Schema",
36661
+ suggestion: "schemashift migrate ./src -f io-ts -t effect --dry-run"
36662
+ });
36663
+ }
36664
+ }
36665
+ }
36666
+ if (detected.length === 0) {
36667
+ checks.push({
36668
+ status: "warn",
36669
+ message: "No schema validation libraries detected in package.json"
36670
+ });
36671
+ } else if (detected.length > 1) {
36672
+ checks.push({
36673
+ status: "info",
36674
+ message: `Multiple schema libraries detected: ${detected.join(", ")}`,
36675
+ suggestion: "Consider consolidating to a single library with SchemaShift"
36676
+ });
36677
+ }
36678
+ return checks;
36679
+ }
36680
+ function checkFormLibraries(allDeps) {
36681
+ const checks = [];
36682
+ const schemaLibs = Object.keys(SCHEMA_LIBRARIES).filter((lib) => allDeps[lib]);
36683
+ for (const [lib, name] of Object.entries(FORM_LIBRARIES)) {
36684
+ if (!allDeps[lib]) continue;
36685
+ checks.push({
36686
+ status: "pass",
36687
+ message: `${name} detected`
36688
+ });
36689
+ if (lib === "formik") {
36690
+ checks.push({
36691
+ status: "warn",
36692
+ message: "Formik is no longer actively maintained \u2014 consider React Hook Form"
36693
+ });
36694
+ }
36695
+ if (lib === "react-hook-form") {
36696
+ if (allDeps["@hookform/resolvers"]) {
36697
+ checks.push({
36698
+ status: "pass",
36699
+ message: "@hookform/resolvers detected \u2014 form resolver migration supported"
36700
+ });
36701
+ }
36702
+ if (schemaLibs.includes("yup") && !schemaLibs.includes("zod")) {
36703
+ checks.push({
36704
+ status: "info",
36705
+ message: "React Hook Form + Yup detected \u2014 Zod integration is more popular",
36706
+ suggestion: "schemashift migrate ./src -f yup -t zod --dry-run"
36707
+ });
36708
+ }
36709
+ }
36710
+ }
36711
+ return checks;
36712
+ }
36713
+ function checkEcosystemDeps(allDeps) {
36714
+ const checks = [];
36715
+ const ecosystemPkgs = [
36716
+ "drizzle-zod",
36717
+ "@trpc/server",
36718
+ "zod-validation-error",
36719
+ "zod-openapi",
36720
+ "@asteasolutions/zod-to-openapi",
36721
+ "zod-prisma",
36722
+ "zod-prisma-types",
36723
+ "zod-form-data",
36724
+ "zodios",
36725
+ "@ts-rest/core"
36726
+ ];
36727
+ for (const pkg2 of ecosystemPkgs) {
36728
+ if (allDeps[pkg2]) {
36729
+ checks.push({
36730
+ status: "info",
36731
+ message: `${pkg2} detected \u2014 may need updates during Zod migration`
36732
+ });
36733
+ }
36734
+ }
36735
+ return checks;
36736
+ }
36737
+ function checkConfig(projectPath) {
36738
+ const checks = [];
36739
+ const configPath = join3(projectPath, ".schemashiftrc.json");
36740
+ if (existsSync3(configPath)) {
36741
+ try {
36742
+ const config2 = loadConfig(projectPath);
36743
+ checks.push({
36744
+ status: "pass",
36745
+ message: "Configuration file .schemashiftrc.json is valid"
36746
+ });
36747
+ if (config2 && typeof config2 === "object" && "governance" in config2) {
36748
+ checks.push({
36749
+ status: "pass",
36750
+ message: "Governance rules configured"
36751
+ });
36752
+ }
36753
+ } catch (err) {
36754
+ checks.push({
36755
+ status: "error",
36756
+ message: `Invalid configuration: ${err instanceof Error ? err.message : String(err)}`,
36757
+ suggestion: "Run: schemashift init --force"
36758
+ });
36759
+ }
36760
+ } else {
36761
+ checks.push({
36762
+ status: "info",
36763
+ message: "No .schemashiftrc.json found \u2014 using defaults",
36764
+ suggestion: "schemashift init"
36765
+ });
36766
+ }
36767
+ return checks;
36768
+ }
36769
+ function checkGitStatus(projectPath) {
36770
+ const checks = [];
36771
+ const gitDir = join3(projectPath, ".git");
36772
+ if (existsSync3(gitDir)) {
36773
+ checks.push({
36774
+ status: "pass",
36775
+ message: "Git repository detected \u2014 backups and rollbacks supported"
36776
+ });
36777
+ } else {
36778
+ checks.push({
36779
+ status: "warn",
36780
+ message: "Not a git repository \u2014 consider initializing git before migrating"
36781
+ });
36782
+ }
36783
+ return checks;
36784
+ }
36785
+ function runDoctor(projectPath) {
36786
+ const pkg2 = readPackageJson(projectPath);
36787
+ const checks = [];
36788
+ const suggestions = [];
36789
+ if (!pkg2) {
36790
+ checks.push({
36791
+ status: "error",
36792
+ message: "No package.json found",
36793
+ suggestion: "Run doctor from the root of your project"
36794
+ });
36795
+ return { checks, suggestions };
36796
+ }
36797
+ checks.push({
36798
+ status: "pass",
36799
+ message: `Project: ${pkg2.name || "unnamed"}`
36800
+ });
36801
+ const allDeps = getAllDeps(pkg2);
36802
+ checks.push(...checkSchemaLibraries(allDeps));
36803
+ checks.push(...checkFormLibraries(allDeps));
36804
+ checks.push(...checkEcosystemDeps(allDeps));
36805
+ checks.push(...checkConfig(projectPath));
36806
+ checks.push(...checkGitStatus(projectPath));
36807
+ for (const check of checks) {
36808
+ if (check.suggestion) {
36809
+ suggestions.push(check.suggestion);
36810
+ }
36811
+ }
36812
+ return { checks, suggestions };
36813
+ }
36814
+ function formatDoctorReport(report) {
36815
+ const lines = [];
36816
+ lines.push(pc2.bold("\nSchemaShift Doctor\n"));
36817
+ const icons = {
36818
+ pass: pc2.green("\u2713"),
36819
+ warn: pc2.yellow("\u26A0"),
36820
+ error: pc2.red("\u2717"),
36821
+ info: pc2.blue("\u2139")
36822
+ };
36823
+ for (const check of report.checks) {
36824
+ lines.push(` ${icons[check.status]} ${check.message}`);
36825
+ }
36826
+ if (report.suggestions.length > 0) {
36827
+ lines.push("");
36828
+ lines.push(pc2.bold(" Suggestions:"));
36829
+ for (const suggestion of report.suggestions) {
36830
+ lines.push(` ${pc2.cyan("\u2192")} ${pc2.dim(suggestion)}`);
36831
+ }
36832
+ }
36833
+ const errorCount = report.checks.filter((c) => c.status === "error").length;
36834
+ const warnCount = report.checks.filter((c) => c.status === "warn").length;
36835
+ lines.push("");
36836
+ if (errorCount > 0) {
36837
+ lines.push(pc2.red(` ${errorCount} error(s) found`));
36838
+ } else if (warnCount > 0) {
36839
+ lines.push(pc2.yellow(` ${warnCount} warning(s) \u2014 project is functional`));
36840
+ } else {
36841
+ lines.push(pc2.green(" Project looks healthy!"));
36842
+ }
36843
+ lines.push("");
36844
+ return lines.join("\n");
36845
+ }
36846
+ function formatDoctorJson(report) {
36847
+ return JSON.stringify(
36848
+ {
36849
+ checks: report.checks,
36850
+ suggestions: report.suggestions,
36851
+ summary: {
36852
+ errors: report.checks.filter((c) => c.status === "error").length,
36853
+ warnings: report.checks.filter((c) => c.status === "warn").length,
36854
+ passed: report.checks.filter((c) => c.status === "pass").length,
36855
+ info: report.checks.filter((c) => c.status === "info").length
36856
+ }
36857
+ },
36858
+ null,
36859
+ 2
36860
+ );
36861
+ }
36862
+
36863
+ // src/error-formatter.ts
36864
+ init_esm_shims();
36865
+ import { readFileSync as readFileSync4 } from "fs";
36866
+ import pc3 from "picocolors";
36534
36867
  function formatErrorSummary(errors) {
36535
36868
  const lines = [];
36536
36869
  lines.push(
36537
- pc2.red(pc2.bold(`
36870
+ pc3.red(pc3.bold(`
36538
36871
  ${errors.length} file${errors.length !== 1 ? "s" : ""} with errors:
36539
36872
  `))
36540
36873
  );
36541
36874
  for (const { filePath, errors: fileErrors } of errors) {
36542
36875
  const relativePath = filePath.replace(`${process.cwd()}/`, "");
36543
- lines.push(pc2.red(` ${relativePath}`));
36876
+ lines.push(pc3.red(` ${relativePath}`));
36544
36877
  for (const err of fileErrors) {
36545
36878
  const loc = err.line ? `:${err.line}` : "";
36546
- lines.push(pc2.dim(` - ${err.message}${loc}`));
36879
+ lines.push(pc3.dim(` - ${err.message}${loc}`));
36547
36880
  if (err.suggestion) {
36548
- lines.push(pc2.cyan(` \u2192 ${err.suggestion}`));
36881
+ lines.push(pc3.cyan(` \u2192 ${err.suggestion}`));
36549
36882
  }
36550
36883
  }
36551
36884
  }
@@ -36555,11 +36888,11 @@ ${errors.length} file${errors.length !== 1 ? "s" : ""} with errors:
36555
36888
  // src/git.ts
36556
36889
  init_esm_shims();
36557
36890
  import { execFileSync } from "child_process";
36558
- import { existsSync as existsSync3 } from "fs";
36891
+ import { existsSync as existsSync4 } from "fs";
36559
36892
  var GitIntegration = class {
36560
36893
  isGitRepo;
36561
36894
  constructor() {
36562
- this.isGitRepo = existsSync3(".git");
36895
+ this.isGitRepo = existsSync4(".git");
36563
36896
  }
36564
36897
  isAvailable() {
36565
36898
  if (!this.isGitRepo) return false;
@@ -36928,7 +37261,7 @@ import { watch } from "fs";
36928
37261
  import { relative as relative2 } from "path";
36929
37262
  import { glob } from "glob";
36930
37263
  import { minimatch } from "minimatch";
36931
- import pc3 from "picocolors";
37264
+ import pc4 from "picocolors";
36932
37265
  var WatchMode = class {
36933
37266
  watchers = [];
36934
37267
  debounceTimers = /* @__PURE__ */ new Map();
@@ -36936,16 +37269,16 @@ var WatchMode = class {
36936
37269
  const files = await glob(options.patterns, {
36937
37270
  ignore: options.exclude
36938
37271
  });
36939
- console.log(pc3.cyan(`
37272
+ console.log(pc4.cyan(`
36940
37273
  Watching ${files.length} files for changes...
36941
37274
  `));
36942
37275
  if (options.dependents && options.dependents.size > 0) {
36943
37276
  console.log(
36944
- pc3.dim(`Dependency-aware mode: ${options.dependents.size} files with dependents
37277
+ pc4.dim(`Dependency-aware mode: ${options.dependents.size} files with dependents
36945
37278
  `)
36946
37279
  );
36947
37280
  }
36948
- console.log(pc3.dim("Press Ctrl+C to stop\n"));
37281
+ console.log(pc4.dim("Press Ctrl+C to stop\n"));
36949
37282
  const directories = new Set(files.map((f) => f.split("/").slice(0, -1).join("/")));
36950
37283
  for (const dir of directories) {
36951
37284
  const watcher = watch(dir || ".", { recursive: true }, async (_event, filename) => {
@@ -36961,23 +37294,23 @@ Watching ${files.length} files for changes...
36961
37294
  this.debounceTimers.set(
36962
37295
  fullPath,
36963
37296
  setTimeout(async () => {
36964
- console.log(pc3.yellow(`
37297
+ console.log(pc4.yellow(`
36965
37298
  Changed: ${relative2(process.cwd(), fullPath)}`));
36966
37299
  try {
36967
37300
  await options.onTransform(fullPath);
36968
- console.log(pc3.green(`Transformed successfully`));
37301
+ console.log(pc4.green(`Transformed successfully`));
36969
37302
  const dependentFiles = options.dependents?.get(fullPath);
36970
37303
  if (dependentFiles && dependentFiles.length > 0) {
36971
37304
  console.log(
36972
- pc3.cyan(` Re-transforming ${dependentFiles.length} dependent file(s)...`)
37305
+ pc4.cyan(` Re-transforming ${dependentFiles.length} dependent file(s)...`)
36973
37306
  );
36974
37307
  for (const depFile of dependentFiles) {
36975
37308
  try {
36976
37309
  await options.onTransform(depFile);
36977
- console.log(pc3.green(` \u2713 ${relative2(process.cwd(), depFile)}`));
37310
+ console.log(pc4.green(` \u2713 ${relative2(process.cwd(), depFile)}`));
36978
37311
  } catch (error) {
36979
37312
  console.error(
36980
- pc3.red(
37313
+ pc4.red(
36981
37314
  ` \u2717 ${relative2(process.cwd(), depFile)}: ${error instanceof Error ? error.message : String(error)}`
36982
37315
  )
36983
37316
  );
@@ -36987,7 +37320,7 @@ Changed: ${relative2(process.cwd(), fullPath)}`));
36987
37320
  console.log("");
36988
37321
  } catch (error) {
36989
37322
  console.error(
36990
- pc3.red(
37323
+ pc4.red(
36991
37324
  `Transform failed: ${error instanceof Error ? error.message : String(error)}
36992
37325
  `
36993
37326
  )
@@ -37034,7 +37367,7 @@ Changed: ${relative2(process.cwd(), fullPath)}`));
37034
37367
 
37035
37368
  // src/cli.ts
37036
37369
  var __dirname2 = dirname2(fileURLToPath(import.meta.url));
37037
- var pkg = JSON.parse(readFileSync4(join3(__dirname2, "..", "package.json"), "utf-8"));
37370
+ var pkg = JSON.parse(readFileSync5(join4(__dirname2, "..", "package.json"), "utf-8"));
37038
37371
  var program = new Command();
37039
37372
  var licenseManager = new LicenseManager();
37040
37373
  var engine = new TransformEngine();
@@ -37054,8 +37387,8 @@ var POLAR_URL = "https://schemashift.qwady.app";
37054
37387
  program.name("schemashift").version(pkg.version).description("TypeScript schema migration CLI");
37055
37388
  program.command("init").description("Create .schemashiftrc.json config file").option("-f, --force", "Overwrite existing config").action((options) => {
37056
37389
  const configPath = ".schemashiftrc.json";
37057
- if (existsSync4(configPath) && !options.force) {
37058
- console.error(pc4.red("Config file already exists. Use --force to overwrite."));
37390
+ if (existsSync5(configPath) && !options.force) {
37391
+ console.error(pc5.red("Config file already exists. Use --force to overwrite."));
37059
37392
  process.exit(1);
37060
37393
  }
37061
37394
  const defaultConfig = {
@@ -37076,8 +37409,8 @@ program.command("init").description("Create .schemashiftrc.json config file").op
37076
37409
  ci: false
37077
37410
  };
37078
37411
  writeFileSync4(configPath, JSON.stringify(defaultConfig, null, 2));
37079
- console.log(pc4.green("Created .schemashiftrc.json"));
37080
- console.log(pc4.dim("Edit the file to customize your migration settings."));
37412
+ console.log(pc5.green("Created .schemashiftrc.json"));
37413
+ console.log(pc5.dim("Edit the file to customize your migration settings."));
37081
37414
  });
37082
37415
  program.command("analyze <path>").description("Analyze schemas in your project").option("--json", "Output as JSON").option("-v, --verbose", "Show detailed analysis").option("--detailed", "Show complexity analysis (Individual+)").option("--readiness <migration>", "Check migration readiness, e.g. yup->zod (Individual+)").option("--complexity", "Show per-schema complexity scores (Individual+)").option("--behavioral <migration>", "Show behavioral difference warnings, e.g. yup->zod").option("--bundle <migration>", "Show bundle size estimation, e.g. zod->valibot (Individual+)").option(
37083
37416
  "--performance <migration>",
@@ -37085,10 +37418,10 @@ program.command("analyze <path>").description("Analyze schemas in your project")
37085
37418
  ).option("--dedup", "Detect duplicate type definitions (Individual+)").action(async (targetPath, options) => {
37086
37419
  const analyzer = new SchemaAnalyzer();
37087
37420
  let files;
37088
- if (existsSync4(targetPath) && statSync(targetPath).isFile()) {
37421
+ if (existsSync5(targetPath) && statSync(targetPath).isFile()) {
37089
37422
  files = [resolve2(targetPath)];
37090
37423
  } else {
37091
- files = await glob2(join3(targetPath, "**/*.{ts,tsx}"), {
37424
+ files = await glob2(join4(targetPath, "**/*.{ts,tsx}"), {
37092
37425
  ignore: ["**/node_modules/**", "**/dist/**"]
37093
37426
  });
37094
37427
  }
@@ -37101,8 +37434,8 @@ program.command("analyze <path>").description("Analyze schemas in your project")
37101
37434
  const validation = await licenseManager.validate();
37102
37435
  const features = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
37103
37436
  if (!features.advancedAnalysis) {
37104
- console.error(pc4.red("Advanced analysis requires Individual tier or higher."));
37105
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37437
+ console.error(pc5.red("Advanced analysis requires Individual tier or higher."));
37438
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37106
37439
  process.exit(1);
37107
37440
  }
37108
37441
  }
@@ -37110,12 +37443,12 @@ program.command("analyze <path>").description("Analyze schemas in your project")
37110
37443
  console.log(JSON.stringify(result, null, 2));
37111
37444
  return;
37112
37445
  }
37113
- console.log(pc4.bold("\nSchema Analysis\n"));
37114
- console.log(`Total files: ${pc4.cyan(result.totalFiles.toString())}`);
37115
- console.log(`Files with schemas: ${pc4.cyan(result.filesWithSchemas.toString())}`);
37116
- console.log(`Total schemas: ${pc4.cyan(result.schemas.length.toString())}`);
37446
+ console.log(pc5.bold("\nSchema Analysis\n"));
37447
+ console.log(`Total files: ${pc5.cyan(result.totalFiles.toString())}`);
37448
+ console.log(`Files with schemas: ${pc5.cyan(result.filesWithSchemas.toString())}`);
37449
+ console.log(`Total schemas: ${pc5.cyan(result.schemas.length.toString())}`);
37117
37450
  if (result.schemas.length > 0) {
37118
- console.log(pc4.bold("\nSchemas by library:\n"));
37451
+ console.log(pc5.bold("\nSchemas by library:\n"));
37119
37452
  const byLibrary = /* @__PURE__ */ new Map();
37120
37453
  for (const schema of result.schemas) {
37121
37454
  byLibrary.set(schema.library, (byLibrary.get(schema.library) || 0) + 1);
@@ -37124,13 +37457,13 @@ program.command("analyze <path>").description("Analyze schemas in your project")
37124
37457
  console.log(` ${lib}: ${count}`);
37125
37458
  }
37126
37459
  if (options.verbose) {
37127
- console.log(pc4.bold("\nDetailed schemas:\n"));
37460
+ console.log(pc5.bold("\nDetailed schemas:\n"));
37128
37461
  for (const schema of result.schemas.slice(0, 20)) {
37129
- console.log(` ${pc4.cyan(schema.name)} (${schema.library})`);
37130
- console.log(` ${pc4.dim(schema.filePath)}:${schema.lineNumber}`);
37462
+ console.log(` ${pc5.cyan(schema.name)} (${schema.library})`);
37463
+ console.log(` ${pc5.dim(schema.filePath)}:${schema.lineNumber}`);
37131
37464
  }
37132
37465
  if (result.schemas.length > 20) {
37133
- console.log(pc4.dim(` ... and ${result.schemas.length - 20} more`));
37466
+ console.log(pc5.dim(` ... and ${result.schemas.length - 20} more`));
37134
37467
  }
37135
37468
  }
37136
37469
  }
@@ -37141,43 +37474,43 @@ program.command("analyze <path>").description("Analyze schemas in your project")
37141
37474
  const projectPath = resolve2(targetPath);
37142
37475
  const detailedResult = detailedAnalyzer.generateDetailedResult(
37143
37476
  complexities,
37144
- existsSync4(join3(projectPath, "package.json")) ? projectPath : process.cwd()
37477
+ existsSync5(join4(projectPath, "package.json")) ? projectPath : process.cwd()
37145
37478
  );
37146
37479
  if (options.json) {
37147
37480
  console.log(JSON.stringify(detailedResult, null, 2));
37148
37481
  return;
37149
37482
  }
37150
- console.log(pc4.bold("\nComplexity Analysis\n"));
37151
- console.log(`Average complexity: ${pc4.cyan(detailedResult.averageComplexity.toString())}`);
37152
- console.log(`Max complexity: ${pc4.cyan(detailedResult.maxComplexity.toString())}`);
37483
+ console.log(pc5.bold("\nComplexity Analysis\n"));
37484
+ console.log(`Average complexity: ${pc5.cyan(detailedResult.averageComplexity.toString())}`);
37485
+ console.log(`Max complexity: ${pc5.cyan(detailedResult.maxComplexity.toString())}`);
37153
37486
  if (detailedResult.libraryVersions.length > 0) {
37154
- console.log(pc4.bold("\nDetected library versions:\n"));
37487
+ console.log(pc5.bold("\nDetected library versions:\n"));
37155
37488
  for (const v of detailedResult.libraryVersions) {
37156
- console.log(` ${v.library}: ${pc4.cyan(v.version)}`);
37489
+ console.log(` ${v.library}: ${pc5.cyan(v.version)}`);
37157
37490
  }
37158
37491
  }
37159
37492
  if (options.complexity || options.detailed) {
37160
37493
  const sorted = [...complexities].sort((a, b) => b.score - a.score);
37161
- console.log(pc4.bold("\nPer-schema complexity:\n"));
37494
+ console.log(pc5.bold("\nPer-schema complexity:\n"));
37162
37495
  for (const c of sorted.slice(0, 20)) {
37163
- const levelColor = c.level === "critical" ? pc4.red : c.level === "high" ? pc4.yellow : c.level === "medium" ? pc4.blue : pc4.green;
37496
+ const levelColor = c.level === "critical" ? pc5.red : c.level === "high" ? pc5.yellow : c.level === "medium" ? pc5.blue : pc5.green;
37164
37497
  console.log(
37165
- ` ${pc4.cyan(c.schemaName)} ${levelColor(`[${c.level}]`)} score=${c.score}`
37498
+ ` ${pc5.cyan(c.schemaName)} ${levelColor(`[${c.level}]`)} score=${c.score}`
37166
37499
  );
37167
37500
  console.log(
37168
37501
  ` chain=${c.chainLength} nested=${c.nestedDepth} validations=${c.validationCount}`
37169
37502
  );
37170
- console.log(` ${pc4.dim(c.filePath)}:${c.lineNumber}`);
37503
+ console.log(` ${pc5.dim(c.filePath)}:${c.lineNumber}`);
37171
37504
  }
37172
37505
  if (sorted.length > 20) {
37173
- console.log(pc4.dim(` ... and ${sorted.length - 20} more`));
37506
+ console.log(pc5.dim(` ... and ${sorted.length - 20} more`));
37174
37507
  }
37175
37508
  }
37176
37509
  }
37177
37510
  if (options.readiness) {
37178
37511
  const parts = options.readiness.split("->");
37179
37512
  if (parts.length !== 2) {
37180
- console.error(pc4.red("Invalid readiness format. Use: --readiness yup->zod"));
37513
+ console.error(pc5.red("Invalid readiness format. Use: --readiness yup->zod"));
37181
37514
  process.exit(1);
37182
37515
  }
37183
37516
  const [from, to] = parts;
@@ -37244,21 +37577,21 @@ program.command("analyze <path>").description("Analyze schemas in your project")
37244
37577
  console.log(JSON.stringify(readiness, null, 2));
37245
37578
  return;
37246
37579
  }
37247
- const riskColor = readiness.riskLevel === "critical" ? pc4.red : readiness.riskLevel === "high" ? pc4.yellow : readiness.riskLevel === "medium" ? pc4.blue : pc4.green;
37248
- console.log(pc4.bold(`
37580
+ const riskColor = readiness.riskLevel === "critical" ? pc5.red : readiness.riskLevel === "high" ? pc5.yellow : readiness.riskLevel === "medium" ? pc5.blue : pc5.green;
37581
+ console.log(pc5.bold(`
37249
37582
  Migration Readiness: ${from} -> ${to}
37250
37583
  `));
37251
37584
  console.log(`Readiness: ${riskColor(`${readiness.readinessPercent}%`)}`);
37252
37585
  console.log(`Risk level: ${riskColor(readiness.riskLevel)}`);
37253
37586
  console.log(`Total schemas: ${readiness.totalSchemas}`);
37254
- console.log(`Supported: ${pc4.green(readiness.supportedSchemas.toString())}`);
37587
+ console.log(`Supported: ${pc5.green(readiness.supportedSchemas.toString())}`);
37255
37588
  console.log(
37256
- `Estimated manual fixes: ${pc4.yellow(readiness.estimatedManualFixes.toString())}`
37589
+ `Estimated manual fixes: ${pc5.yellow(readiness.estimatedManualFixes.toString())}`
37257
37590
  );
37258
37591
  if (readiness.unsupportedPatterns.length > 0) {
37259
- console.log(pc4.bold("\nUnsupported patterns:\n"));
37592
+ console.log(pc5.bold("\nUnsupported patterns:\n"));
37260
37593
  for (const p of readiness.unsupportedPatterns) {
37261
- console.log(` ${pc4.red(p)}`);
37594
+ console.log(` ${pc5.red(p)}`);
37262
37595
  }
37263
37596
  }
37264
37597
  }
@@ -37266,7 +37599,7 @@ Migration Readiness: ${from} -> ${to}
37266
37599
  if (options.behavioral) {
37267
37600
  const migParts = options.behavioral.split("->");
37268
37601
  if (migParts.length !== 2) {
37269
- console.error(pc4.red("Invalid format. Use: --behavioral yup->zod"));
37602
+ console.error(pc5.red("Invalid format. Use: --behavioral yup->zod"));
37270
37603
  } else {
37271
37604
  const [bFrom, bTo] = migParts;
37272
37605
  const behavioralAnalyzer = new BehavioralWarningAnalyzer();
@@ -37277,7 +37610,7 @@ Migration Readiness: ${from} -> ${to}
37277
37610
  bTo
37278
37611
  );
37279
37612
  if (behavioralResult.warnings.length > 0) {
37280
- console.log(pc4.bold("\nBehavioral Difference Warnings\n"));
37613
+ console.log(pc5.bold("\nBehavioral Difference Warnings\n"));
37281
37614
  const byCategory = /* @__PURE__ */ new Map();
37282
37615
  for (const w of behavioralResult.warnings) {
37283
37616
  const existing = byCategory.get(w.category) ?? [];
@@ -37285,17 +37618,17 @@ Migration Readiness: ${from} -> ${to}
37285
37618
  byCategory.set(w.category, existing);
37286
37619
  }
37287
37620
  for (const [category, catWarnings] of byCategory) {
37288
- console.log(pc4.yellow(` [${category}] ${catWarnings.length} warning(s)`));
37621
+ console.log(pc5.yellow(` [${category}] ${catWarnings.length} warning(s)`));
37289
37622
  for (const w of catWarnings.slice(0, 5)) {
37290
37623
  console.log(` ${w.message}`);
37291
- console.log(` ${pc4.dim(w.detail)}`);
37624
+ console.log(` ${pc5.dim(w.detail)}`);
37292
37625
  }
37293
37626
  if (catWarnings.length > 5) {
37294
- console.log(pc4.dim(` ... and ${catWarnings.length - 5} more`));
37627
+ console.log(pc5.dim(` ... and ${catWarnings.length - 5} more`));
37295
37628
  }
37296
37629
  }
37297
37630
  } else {
37298
- console.log(pc4.green("\nNo behavioral difference warnings found."));
37631
+ console.log(pc5.green("\nNo behavioral difference warnings found."));
37299
37632
  }
37300
37633
  }
37301
37634
  }
@@ -37303,12 +37636,12 @@ Migration Readiness: ${from} -> ${to}
37303
37636
  const validation = await licenseManager.validate();
37304
37637
  const tier = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
37305
37638
  if (!tier.bundleEstimator) {
37306
- console.error(pc4.red("\nBundle estimation requires Individual tier or higher."));
37307
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37639
+ console.error(pc5.red("\nBundle estimation requires Individual tier or higher."));
37640
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37308
37641
  } else {
37309
37642
  const migParts = options.bundle.split("->");
37310
37643
  if (migParts.length !== 2) {
37311
- console.error(pc4.red("Invalid format. Use: --bundle zod->valibot"));
37644
+ console.error(pc5.red("Invalid format. Use: --bundle zod->valibot"));
37312
37645
  } else {
37313
37646
  const [bFrom, bTo] = migParts;
37314
37647
  const bundleEstimator = new BundleEstimator();
@@ -37318,16 +37651,16 @@ Migration Readiness: ${from} -> ${to}
37318
37651
  bFrom,
37319
37652
  bTo
37320
37653
  );
37321
- console.log(pc4.bold("\nBundle Size Estimation\n"));
37654
+ console.log(pc5.bold("\nBundle Size Estimation\n"));
37322
37655
  console.log(
37323
- ` ${estimate.from.library}: ~${pc4.cyan(`${estimate.from.minifiedGzipKb}kB`)}`
37656
+ ` ${estimate.from.library}: ~${pc5.cyan(`${estimate.from.minifiedGzipKb}kB`)}`
37324
37657
  );
37325
- console.log(` ${estimate.to.library}: ~${pc4.cyan(`${estimate.to.minifiedGzipKb}kB`)}`);
37658
+ console.log(` ${estimate.to.library}: ~${pc5.cyan(`${estimate.to.minifiedGzipKb}kB`)}`);
37326
37659
  console.log(
37327
- ` Delta: ${pc4.yellow(`${estimate.estimatedDelta > 0 ? "+" : ""}${estimate.estimatedDelta.toFixed(1)}kB (${estimate.deltaPercent.toFixed(0)}%)`)}`
37660
+ ` Delta: ${pc5.yellow(`${estimate.estimatedDelta > 0 ? "+" : ""}${estimate.estimatedDelta.toFixed(1)}kB (${estimate.deltaPercent.toFixed(0)}%)`)}`
37328
37661
  );
37329
37662
  console.log(`
37330
- ${pc4.dim(estimate.summary)}`);
37663
+ ${pc5.dim(estimate.summary)}`);
37331
37664
  }
37332
37665
  }
37333
37666
  }
@@ -37335,12 +37668,12 @@ Migration Readiness: ${from} -> ${to}
37335
37668
  const validation = await licenseManager.validate();
37336
37669
  const tier = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
37337
37670
  if (!tier.performanceAnalyzer) {
37338
- console.error(pc4.red("\nPerformance analysis requires Individual tier or higher."));
37339
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37671
+ console.error(pc5.red("\nPerformance analysis requires Individual tier or higher."));
37672
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37340
37673
  } else {
37341
37674
  const migParts = options.performance.split("->");
37342
37675
  if (migParts.length !== 2) {
37343
- console.error(pc4.red("Invalid format. Use: --performance zod-v3->v4"));
37676
+ console.error(pc5.red("Invalid format. Use: --performance zod-v3->v4"));
37344
37677
  } else {
37345
37678
  const [pFrom, pTo] = migParts;
37346
37679
  const perfAnalyzer = new PerformanceAnalyzer();
@@ -37351,16 +37684,16 @@ Migration Readiness: ${from} -> ${to}
37351
37684
  pTo
37352
37685
  );
37353
37686
  if (perfResult.warnings.length > 0) {
37354
- console.log(pc4.bold("\nPerformance Impact Analysis\n"));
37687
+ console.log(pc5.bold("\nPerformance Impact Analysis\n"));
37355
37688
  for (const w of perfResult.warnings) {
37356
- const color = w.severity === "error" ? pc4.red : w.severity === "warning" ? pc4.yellow : pc4.dim;
37689
+ const color = w.severity === "error" ? pc5.red : w.severity === "warning" ? pc5.yellow : pc5.dim;
37357
37690
  console.log(` ${color(`[${w.severity}]`)} ${w.message}`);
37358
- console.log(` ${pc4.dim(w.detail)}`);
37691
+ console.log(` ${pc5.dim(w.detail)}`);
37359
37692
  }
37360
37693
  console.log(`
37361
- ${pc4.dim(perfResult.recommendation)}`);
37694
+ ${pc5.dim(perfResult.recommendation)}`);
37362
37695
  } else {
37363
- console.log(pc4.green("\nNo performance concerns detected."));
37696
+ console.log(pc5.green("\nNo performance concerns detected."));
37364
37697
  }
37365
37698
  }
37366
37699
  }
@@ -37369,25 +37702,25 @@ Migration Readiness: ${from} -> ${to}
37369
37702
  const validation = await licenseManager.validate();
37370
37703
  const tier = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
37371
37704
  if (!tier.typeDeduplication) {
37372
- console.error(pc4.red("\nType deduplication detection requires Individual tier or higher."));
37373
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37705
+ console.error(pc5.red("\nType deduplication detection requires Individual tier or higher."));
37706
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37374
37707
  } else {
37375
37708
  const dedupDetector = new TypeDedupDetector();
37376
37709
  const sourceFiles = analyzer.getProject().getSourceFiles();
37377
37710
  const dedupResult = dedupDetector.detect(sourceFiles);
37378
37711
  if (dedupResult.candidates.length > 0) {
37379
- console.log(pc4.bold("\nDuplicate Type Candidates\n"));
37712
+ console.log(pc5.bold("\nDuplicate Type Candidates\n"));
37380
37713
  for (const c of dedupResult.candidates.slice(0, 10)) {
37381
- console.log(` ${pc4.cyan(c.typeName)} <-> ${pc4.cyan(c.schemaName)}`);
37382
- console.log(` Type: ${pc4.dim(c.typeFilePath)}:${c.typeLineNumber}`);
37383
- console.log(` Schema: ${pc4.dim(c.schemaFilePath)}:${c.schemaLineNumber}`);
37384
- console.log(` Confidence: ${pc4.dim(c.confidence)} | ${pc4.dim(c.suggestion)}`);
37714
+ console.log(` ${pc5.cyan(c.typeName)} <-> ${pc5.cyan(c.schemaName)}`);
37715
+ console.log(` Type: ${pc5.dim(c.typeFilePath)}:${c.typeLineNumber}`);
37716
+ console.log(` Schema: ${pc5.dim(c.schemaFilePath)}:${c.schemaLineNumber}`);
37717
+ console.log(` Confidence: ${pc5.dim(c.confidence)} | ${pc5.dim(c.suggestion)}`);
37385
37718
  }
37386
37719
  if (dedupResult.candidates.length > 10) {
37387
- console.log(pc4.dim(` ... and ${dedupResult.candidates.length - 10} more`));
37720
+ console.log(pc5.dim(` ... and ${dedupResult.candidates.length - 10} more`));
37388
37721
  }
37389
37722
  } else {
37390
- console.log(pc4.green("\nNo duplicate type candidates found."));
37723
+ console.log(pc5.green("\nNo duplicate type candidates found."));
37391
37724
  }
37392
37725
  }
37393
37726
  }
@@ -37396,19 +37729,23 @@ program.command("migrate <path>").description("Migrate schemas from one library
37396
37729
  "--max-risk-score <score>",
37397
37730
  "Exit 1 if any file exceeds risk score (Team+)",
37398
37731
  Number.parseInt
37399
- ).option("--incremental", "Enable incremental migration (file-by-file with progress tracking)").option("--resume", "Resume a previously started incremental migration").option("--incremental-status", "Show incremental migration progress").option("--scaffold-tests", "Generate validation tests after migration (Pro+)").option("--audit", "Enable migration audit logging (Team+)").option("--preset <name>", "Use a migration preset template (Individual+)").action(async (targetPath, options) => {
37732
+ ).option("--incremental", "Enable incremental migration (file-by-file with progress tracking)").option("--resume", "Resume a previously started incremental migration").option("--incremental-status", "Show incremental migration progress").option("--scaffold-tests", "Generate validation tests after migration (Pro+)").option("--audit", "Enable migration audit logging (Team+)").option("--preset <name>", "Use a migration preset template (Individual+)").option("--output-diff <file>", "Write unified diff to file (use - for stdout)").option(
37733
+ "--canary <percent>",
37734
+ "Canary migration: migrate X% of files first (Pro+)",
37735
+ Number.parseInt
37736
+ ).option("--compliance-report <format>", "Generate compliance report: soc2, hipaa (Team+)").action(async (targetPath, options) => {
37400
37737
  const startTime = Date.now();
37401
37738
  if (options.preset) {
37402
37739
  const validation2 = await licenseManager.validate();
37403
37740
  const features2 = validation2.license?.features || TIER_FEATURES[LicenseTier.FREE];
37404
37741
  if (!features2.advancedAnalysis) {
37405
- console.error(pc4.red("Migration presets require Individual tier or higher."));
37406
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37742
+ console.error(pc5.red("Migration presets require Individual tier or higher."));
37743
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37407
37744
  process.exit(1);
37408
37745
  }
37409
37746
  const preset = getMigrationTemplate(options.preset);
37410
37747
  if (!preset) {
37411
- console.error(pc4.red(`Unknown preset: ${options.preset}`));
37748
+ console.error(pc5.red(`Unknown preset: ${options.preset}`));
37412
37749
  const names = getAllMigrationTemplates().map((t) => t.name);
37413
37750
  console.log(`Available presets: ${names.join(", ")}`);
37414
37751
  process.exit(1);
@@ -37416,42 +37753,42 @@ program.command("migrate <path>").description("Migrate schemas from one library
37416
37753
  const step = preset.migrationSteps[0];
37417
37754
  if (step && !options.from) options.from = step.from;
37418
37755
  if (step && !options.to) options.to = step.to;
37419
- console.log(pc4.bold(`
37756
+ console.log(pc5.bold(`
37420
37757
  Using preset: ${preset.name}`));
37421
- console.log(pc4.dim(preset.description));
37758
+ console.log(pc5.dim(preset.description));
37422
37759
  if (preset.preChecks.length > 0) {
37423
- console.log(pc4.bold("\nPre-migration checklist:"));
37760
+ console.log(pc5.bold("\nPre-migration checklist:"));
37424
37761
  for (const check of preset.preChecks) {
37425
- console.log(` ${pc4.yellow("\u2022")} ${check.description}`);
37762
+ console.log(` ${pc5.yellow("\u2022")} ${check.description}`);
37426
37763
  }
37427
37764
  }
37428
37765
  if (preset.packageChanges.length > 0) {
37429
- console.log(pc4.bold("\nRecommended package changes:"));
37766
+ console.log(pc5.bold("\nRecommended package changes:"));
37430
37767
  for (const change of preset.packageChanges) {
37431
37768
  const verb = change.action === "install" ? "+" : change.action === "remove" ? "-" : "\u2191";
37432
37769
  console.log(
37433
- ` ${pc4.cyan(verb)} ${change.package}${change.version ? `@${change.version}` : ""}`
37770
+ ` ${pc5.cyan(verb)} ${change.package}${change.version ? `@${change.version}` : ""}`
37434
37771
  );
37435
37772
  }
37436
37773
  }
37437
37774
  console.log("");
37438
37775
  }
37439
37776
  if (!options.chain && (!options.from || !options.to)) {
37440
- console.error(pc4.red("Either --from and --to, or --chain must be specified."));
37441
- console.error(pc4.dim(" Single-step: schemashift migrate <path> -f yup -t zod"));
37442
- console.error(pc4.dim(" Chain: schemashift migrate <path> --chain yup->zod->valibot"));
37777
+ console.error(pc5.red("Either --from and --to, or --chain must be specified."));
37778
+ console.error(pc5.dim(" Single-step: schemashift migrate <path> -f yup -t zod"));
37779
+ console.error(pc5.dim(" Chain: schemashift migrate <path> --chain yup->zod->valibot"));
37443
37780
  process.exit(1);
37444
37781
  }
37445
37782
  if (options.maxRiskScore !== void 0 && Number.isNaN(options.maxRiskScore)) {
37446
- console.error(pc4.red("--max-risk-score must be a valid number."));
37783
+ console.error(pc5.red("--max-risk-score must be a valid number."));
37447
37784
  process.exit(1);
37448
37785
  }
37449
37786
  let config2;
37450
37787
  try {
37451
- config2 = await loadConfig(options.config);
37788
+ config2 = await loadConfig2(options.config);
37452
37789
  } catch (error) {
37453
37790
  const msg = error instanceof Error ? error.message : String(error);
37454
- console.warn(pc4.yellow(`Could not load config: ${msg}. Using defaults.`));
37791
+ console.warn(pc5.yellow(`Could not load config: ${msg}. Using defaults.`));
37455
37792
  config2 = {
37456
37793
  include: ["**/*.ts", "**/*.tsx"],
37457
37794
  exclude: ["**/node_modules/**", "**/dist/**"],
@@ -37461,95 +37798,95 @@ Using preset: ${preset.name}`));
37461
37798
  }
37462
37799
  const validation = await licenseManager.validate();
37463
37800
  if (!validation.valid) {
37464
- console.error(pc4.red(`License error: ${validation.error}`));
37801
+ console.error(pc5.red(`License error: ${validation.error}`));
37465
37802
  process.exit(1);
37466
37803
  }
37467
37804
  const tier = validation.license?.tier || LicenseTier.FREE;
37468
37805
  const features = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
37469
37806
  const migrationPath = `${options.from}->${options.to}`;
37470
37807
  if (!canUseMigration(tier, options.from, options.to)) {
37471
- console.error(pc4.red(`Migration ${migrationPath} requires a higher tier.`));
37472
- console.log(`Your tier: ${pc4.yellow(tier)}`);
37473
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37808
+ console.error(pc5.red(`Migration ${migrationPath} requires a higher tier.`));
37809
+ console.log(`Your tier: ${pc5.yellow(tier)}`);
37810
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37474
37811
  process.exit(1);
37475
37812
  }
37476
37813
  if (options.ci && !features.ciSupport) {
37477
- console.error(pc4.red("CI mode requires Pro tier or higher."));
37478
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37814
+ console.error(pc5.red("CI mode requires Pro tier or higher."));
37815
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37479
37816
  process.exit(1);
37480
37817
  }
37481
37818
  const customRulesCount = config2.customRules?.length ?? 0;
37482
37819
  if (customRulesCount > features.customRulesLimit) {
37483
37820
  console.error(
37484
- pc4.red(
37821
+ pc5.red(
37485
37822
  `Custom rules limit exceeded. You have ${customRulesCount} rules, max ${features.customRulesLimit} for ${tier} tier.`
37486
37823
  )
37487
37824
  );
37488
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37825
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37489
37826
  process.exit(1);
37490
37827
  }
37491
37828
  if ((options.gitBranch || options.gitCommit) && !features.gitIntegration) {
37492
- console.error(pc4.red("Git integration requires Individual tier or higher."));
37493
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37829
+ console.error(pc5.red("Git integration requires Individual tier or higher."));
37830
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37494
37831
  process.exit(1);
37495
37832
  }
37496
37833
  if (options.crossFile && !features.crossFileResolution) {
37497
- console.error(pc4.red("Cross-file resolution requires Pro tier or higher."));
37498
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37834
+ console.error(pc5.red("Cross-file resolution requires Pro tier or higher."));
37835
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37499
37836
  process.exit(1);
37500
37837
  }
37501
37838
  if (options.chain && !features.chainMigrations) {
37502
- console.error(pc4.red("Chain migrations require Pro tier or higher."));
37503
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37839
+ console.error(pc5.red("Chain migrations require Pro tier or higher."));
37840
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37504
37841
  process.exit(1);
37505
37842
  }
37506
37843
  if (options.compatCheck && !features.compatCheck) {
37507
- console.error(pc4.red("Compatibility check requires Pro tier or higher."));
37508
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37844
+ console.error(pc5.red("Compatibility check requires Pro tier or higher."));
37845
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37509
37846
  process.exit(1);
37510
37847
  }
37511
37848
  if (options.failOnWarnings && !features.failOnWarnings) {
37512
- console.error(pc4.red("--fail-on-warnings requires Team tier."));
37513
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37849
+ console.error(pc5.red("--fail-on-warnings requires Team tier."));
37850
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37514
37851
  process.exit(1);
37515
37852
  }
37516
37853
  if (options.maxRiskScore !== void 0 && !features.maxRiskScoreThreshold) {
37517
- console.error(pc4.red("--max-risk-score requires Team tier."));
37518
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37854
+ console.error(pc5.red("--max-risk-score requires Team tier."));
37855
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37519
37856
  process.exit(1);
37520
37857
  }
37521
37858
  if (options.compatCheck) {
37522
37859
  const compatAnalyzer = new CompatibilityAnalyzer();
37523
37860
  const compatResult = compatAnalyzer.checkCompatibility(resolve2(targetPath));
37524
- console.log(pc4.bold("\nCompatibility Check\n"));
37861
+ console.log(pc5.bold("\nCompatibility Check\n"));
37525
37862
  if (compatResult.detectedVersions.length > 0) {
37526
37863
  for (const v of compatResult.detectedVersions) {
37527
- console.log(` ${v.library}: ${pc4.cyan(v.version)}`);
37864
+ console.log(` ${v.library}: ${pc5.cyan(v.version)}`);
37528
37865
  }
37529
37866
  }
37530
37867
  console.log(`
37531
- Compatibility score: ${pc4.cyan(compatResult.overallScore.toString())}%`);
37868
+ Compatibility score: ${pc5.cyan(compatResult.overallScore.toString())}%`);
37532
37869
  if (compatResult.issues.length > 0) {
37533
- console.log(pc4.bold("\nIssues:\n"));
37870
+ console.log(pc5.bold("\nIssues:\n"));
37534
37871
  for (const issue2 of compatResult.issues) {
37535
- const color = issue2.severity === "error" ? pc4.red : issue2.severity === "warning" ? pc4.yellow : pc4.dim;
37872
+ const color = issue2.severity === "error" ? pc5.red : issue2.severity === "warning" ? pc5.yellow : pc5.dim;
37536
37873
  console.log(` ${color(`[${issue2.severity}]`)} ${issue2.issue}`);
37537
- console.log(` ${pc4.dim(issue2.suggestion)}`);
37874
+ console.log(` ${pc5.dim(issue2.suggestion)}`);
37538
37875
  }
37539
37876
  }
37540
37877
  console.log("");
37541
37878
  }
37542
37879
  if (config2.plugins && config2.plugins.length > 0) {
37543
37880
  if (!features.customPlugins) {
37544
- console.error(pc4.red("Custom plugins require Team tier."));
37545
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37881
+ console.error(pc5.red("Custom plugins require Team tier."));
37882
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37546
37883
  process.exit(1);
37547
37884
  }
37548
37885
  const pluginLoader = new PluginLoader();
37549
37886
  const pluginResult = await pluginLoader.loadPlugins(config2.plugins);
37550
37887
  if (pluginResult.errors.length > 0) {
37551
37888
  for (const err of pluginResult.errors) {
37552
- console.warn(pc4.yellow(`Plugin error: ${err}`));
37889
+ console.warn(pc5.yellow(`Plugin error: ${err}`));
37553
37890
  }
37554
37891
  }
37555
37892
  for (const plugin of pluginResult.loaded) {
@@ -37558,7 +37895,7 @@ Compatibility score: ${pc4.cyan(compatResult.overallScore.toString())}%`);
37558
37895
  engine.registerHandler(h.from, h.to, h.handler);
37559
37896
  }
37560
37897
  }
37561
- console.log(pc4.dim(`Loaded plugin: ${plugin.name} v${plugin.version}`));
37898
+ console.log(pc5.dim(`Loaded plugin: ${plugin.name} v${plugin.version}`));
37562
37899
  }
37563
37900
  }
37564
37901
  let chainSteps;
@@ -37571,15 +37908,15 @@ Compatibility score: ${pc4.cyan(compatResult.overallScore.toString())}%`);
37571
37908
  }
37572
37909
  const chainValidation = migrationChain.validateChain(chainSteps, engine);
37573
37910
  if (!chainValidation.valid) {
37574
- console.error(pc4.red("Chain migration validation failed:"));
37911
+ console.error(pc5.red("Chain migration validation failed:"));
37575
37912
  for (const err of chainValidation.errors) {
37576
- console.error(` ${pc4.red(err)}`);
37913
+ console.error(` ${pc5.red(err)}`);
37577
37914
  }
37578
37915
  process.exit(1);
37579
37916
  }
37580
37917
  } else {
37581
37918
  if (!engine.hasHandler(options.from, options.to)) {
37582
- console.error(pc4.red(`No handler for ${migrationPath}`));
37919
+ console.error(pc5.red(`No handler for ${migrationPath}`));
37583
37920
  console.log(
37584
37921
  "Supported migrations:",
37585
37922
  engine.getSupportedPaths().map((p) => `${p.from}->${p.to}`).join(", ")
@@ -37588,57 +37925,57 @@ Compatibility score: ${pc4.cyan(compatResult.overallScore.toString())}%`);
37588
37925
  }
37589
37926
  }
37590
37927
  let files;
37591
- if (existsSync4(targetPath) && statSync(targetPath).isFile()) {
37928
+ if (existsSync5(targetPath) && statSync(targetPath).isFile()) {
37592
37929
  files = [resolve2(targetPath)];
37593
37930
  } else {
37594
- files = await glob2(join3(targetPath, "**/*.{ts,tsx}"), {
37931
+ files = await glob2(join4(targetPath, "**/*.{ts,tsx}"), {
37595
37932
  ignore: config2.exclude
37596
37933
  });
37597
37934
  }
37598
37935
  if (files.length === 0) {
37599
- console.log(pc4.yellow("No files found matching patterns."));
37936
+ console.log(pc5.yellow("No files found matching patterns."));
37600
37937
  process.exit(0);
37601
37938
  }
37602
37939
  const incrementalTracker = new IncrementalTracker(resolve2(targetPath));
37603
37940
  if (options.incrementalStatus) {
37604
37941
  const progress = incrementalTracker.getProgress();
37605
37942
  if (!progress) {
37606
- console.log(pc4.yellow("No incremental migration in progress."));
37943
+ console.log(pc5.yellow("No incremental migration in progress."));
37607
37944
  process.exit(0);
37608
37945
  }
37609
- console.log(pc4.bold("\nIncremental Migration Status\n"));
37610
- console.log(`Completed: ${pc4.green(progress.completed.toString())}`);
37611
- console.log(`Remaining: ${pc4.cyan(progress.remaining.toString())}`);
37612
- console.log(`Failed: ${pc4.red(progress.failed.toString())}`);
37946
+ console.log(pc5.bold("\nIncremental Migration Status\n"));
37947
+ console.log(`Completed: ${pc5.green(progress.completed.toString())}`);
37948
+ console.log(`Remaining: ${pc5.cyan(progress.remaining.toString())}`);
37949
+ console.log(`Failed: ${pc5.red(progress.failed.toString())}`);
37613
37950
  console.log(`Total: ${progress.total}`);
37614
- console.log(`Progress: ${pc4.cyan(`${progress.percent}%`)}`);
37951
+ console.log(`Progress: ${pc5.cyan(`${progress.percent}%`)}`);
37615
37952
  process.exit(0);
37616
37953
  }
37617
37954
  if (options.resume) {
37618
37955
  const state = incrementalTracker.resume();
37619
37956
  if (!state) {
37620
- console.error(pc4.red("No incremental migration to resume."));
37957
+ console.error(pc5.red("No incremental migration to resume."));
37621
37958
  process.exit(1);
37622
37959
  }
37623
37960
  files = state.remainingFiles;
37624
- console.log(pc4.dim(`Resuming incremental migration: ${state.migrationId}`));
37961
+ console.log(pc5.dim(`Resuming incremental migration: ${state.migrationId}`));
37625
37962
  const progress = incrementalTracker.getProgress();
37626
37963
  if (progress) {
37627
37964
  console.log(
37628
- pc4.dim(
37965
+ pc5.dim(
37629
37966
  `Progress: ${progress.completed}/${progress.total} completed (${progress.percent}%)`
37630
37967
  )
37631
37968
  );
37632
37969
  }
37633
37970
  } else if (options.incremental) {
37634
37971
  incrementalTracker.start(files, options.from, options.to);
37635
- console.log(pc4.dim("Started incremental migration."));
37972
+ console.log(pc5.dim("Started incremental migration."));
37636
37973
  }
37637
37974
  if (files.length > features.maxFiles) {
37638
37975
  console.error(
37639
- pc4.red(`File limit exceeded. Found ${files.length}, max ${features.maxFiles}.`)
37976
+ pc5.red(`File limit exceeded. Found ${files.length}, max ${features.maxFiles}.`)
37640
37977
  );
37641
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
37978
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37642
37979
  process.exit(1);
37643
37980
  }
37644
37981
  if (options.crossFile) {
@@ -37650,34 +37987,34 @@ Compatibility score: ${pc4.cyan(compatResult.overallScore.toString())}%`);
37650
37987
  const resolvedFiles = files.map((f) => resolve2(f));
37651
37988
  const depResult = depResolver.resolve(analyzer.getProject(), resolvedFiles);
37652
37989
  files = depResult.sortedFiles;
37653
- console.log(pc4.bold("\nCross-file resolution\n"));
37654
- console.log(`Files: ${pc4.cyan(files.length.toString())}`);
37655
- console.log(`Cross-file refs: ${pc4.cyan(depResult.crossFileRefs.toString())}`);
37990
+ console.log(pc5.bold("\nCross-file resolution\n"));
37991
+ console.log(`Files: ${pc5.cyan(files.length.toString())}`);
37992
+ console.log(`Cross-file refs: ${pc5.cyan(depResult.crossFileRefs.toString())}`);
37656
37993
  if (depResult.circularWarnings.length > 0) {
37657
- console.log(pc4.yellow(`Circular deps: ${depResult.circularWarnings.length}`));
37994
+ console.log(pc5.yellow(`Circular deps: ${depResult.circularWarnings.length}`));
37658
37995
  for (const w of depResult.circularWarnings) {
37659
- console.log(` ${pc4.yellow(w)}`);
37996
+ console.log(` ${pc5.yellow(w)}`);
37660
37997
  }
37661
37998
  }
37662
37999
  console.log("");
37663
38000
  }
37664
38001
  const displayPath = options.chain || migrationPath;
37665
- console.log(pc4.bold(`
38002
+ console.log(pc5.bold(`
37666
38003
  Migrating ${displayPath}
37667
38004
  `));
37668
- console.log(`Files: ${pc4.cyan(files.length.toString())}`);
37669
- console.log(`Tier: ${pc4.cyan(tier)}`);
37670
- console.log(`Migration: ${pc4.cyan(displayPath)}`);
38005
+ console.log(`Files: ${pc5.cyan(files.length.toString())}`);
38006
+ console.log(`Tier: ${pc5.cyan(tier)}`);
38007
+ console.log(`Migration: ${pc5.cyan(displayPath)}`);
37671
38008
  if (chainSteps) {
37672
- console.log(`Steps: ${pc4.cyan(chainSteps.length.toString())}`);
38009
+ console.log(`Steps: ${pc5.cyan(chainSteps.length.toString())}`);
37673
38010
  }
37674
38011
  if (options.dryRun) {
37675
- console.log(pc4.yellow("\nDRY RUN \u2014 no files will be modified\n"));
38012
+ console.log(pc5.yellow("\nDRY RUN \u2014 no files will be modified\n"));
37676
38013
  }
37677
38014
  const git = new GitIntegration();
37678
38015
  if (options.gitBranch && git.isAvailable()) {
37679
38016
  if (git.hasUncommittedChanges()) {
37680
- console.error(pc4.red("Uncommitted changes detected. Commit or stash first."));
38017
+ console.error(pc5.red("Uncommitted changes detected. Commit or stash first."));
37681
38018
  process.exit(1);
37682
38019
  }
37683
38020
  const branchName = git.generateBranchName(
@@ -37686,13 +38023,13 @@ Migrating ${displayPath}
37686
38023
  options.to
37687
38024
  );
37688
38025
  git.createBranch(branchName);
37689
- console.log(pc4.dim(`Created branch: ${branchName}`));
38026
+ console.log(pc5.dim(`Created branch: ${branchName}`));
37690
38027
  }
37691
38028
  const backup = new BackupManager(config2.backup?.dir);
37692
38029
  let backupManifest;
37693
38030
  if (options.backup !== false && config2.backup?.enabled !== false && !options.dryRun) {
37694
38031
  backupManifest = backup.createBackup(files, options.from, options.to);
37695
- console.log(pc4.dim(`Backup created: ${backupManifest.id}`));
38032
+ console.log(pc5.dim(`Backup created: ${backupManifest.id}`));
37696
38033
  }
37697
38034
  const results = [];
37698
38035
  const useConcurrent = !options.crossFile;
@@ -37702,7 +38039,7 @@ Migrating ${displayPath}
37702
38039
  task: async () => {
37703
38040
  if (chainSteps) {
37704
38041
  const migrationChain = new MigrationChain();
37705
- const sourceCode = readFileSync4(resolve2(file), "utf-8");
38042
+ const sourceCode = readFileSync5(resolve2(file), "utf-8");
37706
38043
  const chainResult = migrationChain.executeChain(
37707
38044
  sourceCode,
37708
38045
  resolve2(file),
@@ -37779,16 +38116,16 @@ Migrating ${displayPath}
37779
38116
  const progress = incrementalTracker.getProgress();
37780
38117
  if (progress) {
37781
38118
  console.log(
37782
- pc4.bold(`
38119
+ pc5.bold(`
37783
38120
  Incremental: ${progress.completed}/${progress.total} (${progress.percent}%)`)
37784
38121
  );
37785
38122
  if (progress.remaining > 0) {
37786
38123
  console.log(
37787
- pc4.dim(`Run with --resume to continue. ${progress.remaining} files remaining.`)
38124
+ pc5.dim(`Run with --resume to continue. ${progress.remaining} files remaining.`)
37788
38125
  );
37789
38126
  }
37790
38127
  if (progress.failed > 0) {
37791
- console.log(pc4.yellow(`${progress.failed} file(s) failed. Run with --resume to retry.`));
38128
+ console.log(pc5.yellow(`${progress.failed} file(s) failed. Run with --resume to retry.`));
37792
38129
  }
37793
38130
  }
37794
38131
  }
@@ -37797,17 +38134,17 @@ Incremental: ${progress.completed}/${progress.total} (${progress.percent}%)`)
37797
38134
  if (successFiles.length > 0) {
37798
38135
  git.stageFiles(successFiles);
37799
38136
  git.commit(config2.git?.commitMessage || `chore: migrate ${options.from} to ${options.to}`);
37800
- console.log(pc4.dim("Changes committed"));
38137
+ console.log(pc5.dim("Changes committed"));
37801
38138
  }
37802
38139
  }
37803
38140
  if (options.report) {
37804
38141
  if (options.report === "html" && !features.htmlReports) {
37805
- console.error(pc4.red("HTML reports require Individual tier or higher."));
37806
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38142
+ console.error(pc5.red("HTML reports require Individual tier or higher."));
38143
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37807
38144
  process.exit(1);
37808
38145
  } else if (options.report === "csv" && !features.csvExport) {
37809
- console.error(pc4.red("CSV export requires Individual tier or higher."));
37810
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38146
+ console.error(pc5.red("CSV export requires Individual tier or higher."));
38147
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37811
38148
  process.exit(1);
37812
38149
  } else {
37813
38150
  const reporter = new ReportGenerator();
@@ -37828,13 +38165,13 @@ Incremental: ${progress.completed}/${progress.total} (${progress.percent}%)`)
37828
38165
  } else {
37829
38166
  reporter.writeJson(report, outputPath);
37830
38167
  }
37831
- console.log(pc4.green(`Report saved: ${outputPath}`));
38168
+ console.log(pc5.green(`Report saved: ${outputPath}`));
37832
38169
  }
37833
38170
  }
37834
38171
  if (options.scaffoldTests) {
37835
38172
  if (!features.testScaffolding) {
37836
- console.error(pc4.red("\nTest scaffolding requires Pro tier or higher."));
37837
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38173
+ console.error(pc5.red("\nTest scaffolding requires Pro tier or higher."));
38174
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37838
38175
  } else {
37839
38176
  const scaffolder = new TestScaffolder();
37840
38177
  const successfulFiles = results.filter((r) => r.success).map((r) => r.filePath);
@@ -37845,20 +38182,20 @@ Incremental: ${progress.completed}/${progress.total} (${progress.percent}%)`)
37845
38182
  }
37846
38183
  const sourceFiles = scaffoldAnalyzer.getProject().getSourceFiles();
37847
38184
  const scaffoldResult = scaffolder.scaffold(sourceFiles, options.from, options.to);
37848
- console.log(pc4.bold("\nTest Scaffolding\n"));
38185
+ console.log(pc5.bold("\nTest Scaffolding\n"));
37849
38186
  console.log(
37850
- ` Generated ${pc4.cyan(scaffoldResult.tests.length.toString())} test file(s) for ${scaffoldResult.totalSchemas} schema(s)`
38187
+ ` Generated ${pc5.cyan(scaffoldResult.tests.length.toString())} test file(s) for ${scaffoldResult.totalSchemas} schema(s)`
37851
38188
  );
37852
38189
  for (const test of scaffoldResult.tests) {
37853
- console.log(` ${pc4.dim(test.filePath)} (${test.schemaCount} schemas)`);
38190
+ console.log(` ${pc5.dim(test.filePath)} (${test.schemaCount} schemas)`);
37854
38191
  }
37855
38192
  }
37856
38193
  }
37857
38194
  }
37858
38195
  if (options.audit) {
37859
38196
  if (!features.auditLogging) {
37860
- console.error(pc4.red("\nAudit logging requires Team tier."));
37861
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38197
+ console.error(pc5.red("\nAudit logging requires Team tier."));
38198
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37862
38199
  } else {
37863
38200
  const projectPath = resolve2(targetPath);
37864
38201
  const auditLog = new MigrationAuditLog(projectPath);
@@ -37878,21 +38215,36 @@ Incremental: ${progress.completed}/${progress.total} (${progress.percent}%)`)
37878
38215
  auditLog.append(entry);
37879
38216
  }
37880
38217
  console.log(
37881
- pc4.dim(`
38218
+ pc5.dim(`
37882
38219
  Audit log saved to .schemashift/audit-log.json (${results.length} entries)`)
37883
38220
  );
37884
38221
  }
37885
38222
  }
37886
38223
  if (options.dryRun) {
38224
+ const summaryTable = generateDrySummaryTable(results);
38225
+ if (summaryTable) {
38226
+ console.log(pc5.bold("\nChange Summary\n"));
38227
+ console.log(summaryTable);
38228
+ }
37887
38229
  const diffOutput = generateDiffPreview(results);
37888
38230
  if (diffOutput) {
37889
- console.log(pc4.bold("\nDiff Preview\n"));
38231
+ console.log(pc5.bold("\nDiff Preview\n"));
37890
38232
  console.log(diffOutput);
37891
38233
  }
37892
38234
  }
38235
+ if (options.outputDiff) {
38236
+ const unifiedDiff = generateUnifiedDiff(results);
38237
+ if (options.outputDiff === "-") {
38238
+ console.log(unifiedDiff);
38239
+ } else {
38240
+ writeFileSync4(options.outputDiff, unifiedDiff);
38241
+ console.log(pc5.dim(`
38242
+ Unified diff written to ${options.outputDiff}`));
38243
+ }
38244
+ }
37893
38245
  const failed = results.filter((r) => !r.success).length;
37894
38246
  const warnings = results.reduce((acc, r) => acc + r.warnings.length, 0);
37895
- console.log(pc4.bold("\nSummary\n"));
38247
+ console.log(pc5.bold("\nSummary\n"));
37896
38248
  console.log(generateDiffSummary(results));
37897
38249
  console.log(`Duration: ${Date.now() - startTime}ms`);
37898
38250
  if (failed > 0) {
@@ -37900,7 +38252,7 @@ Audit log saved to .schemashift/audit-log.json (${results.length} entries)`)
37900
38252
  console.log(formatErrorSummary(errorFiles));
37901
38253
  }
37902
38254
  if (options.verbose && warnings > 0) {
37903
- console.log(pc4.yellow("\nWarnings:\n"));
38255
+ console.log(pc5.yellow("\nWarnings:\n"));
37904
38256
  for (const result of results) {
37905
38257
  for (const warning of result.warnings.slice(0, 5)) {
37906
38258
  console.log(` ${warning}`);
@@ -37912,7 +38264,7 @@ Audit log saved to .schemashift/audit-log.json (${results.length} entries)`)
37912
38264
  }
37913
38265
  if (options.failOnWarnings && warnings > 0) {
37914
38266
  console.error(
37915
- pc4.red(`
38267
+ pc5.red(`
37916
38268
  Failing due to ${warnings} warning(s) (--fail-on-warnings enabled).`)
37917
38269
  );
37918
38270
  process.exit(1);
@@ -37928,13 +38280,13 @@ Failing due to ${warnings} warning(s) (--fail-on-warnings enabled).`)
37928
38280
  }
37929
38281
  if (highRiskFiles.length > 0) {
37930
38282
  console.error(
37931
- pc4.red(
38283
+ pc5.red(
37932
38284
  `
37933
38285
  Failing due to ${highRiskFiles.length} file(s) exceeding max risk score of ${options.maxRiskScore}:`
37934
38286
  )
37935
38287
  );
37936
38288
  for (const f of highRiskFiles) {
37937
- console.error(pc4.red(` ${f}`));
38289
+ console.error(pc5.red(` ${f}`));
37938
38290
  }
37939
38291
  process.exit(1);
37940
38292
  }
@@ -37943,22 +38295,22 @@ Failing due to ${highRiskFiles.length} file(s) exceeding max risk score of ${opt
37943
38295
  program.command("watch <path>").description("Watch files and migrate on change").requiredOption("-f, --from <library>", "Source library").requiredOption("-t, --to <library>", "Target library").option("-c, --config <path>", "Path to config file").action(async (targetPath, options) => {
37944
38296
  const validation = await licenseManager.validate();
37945
38297
  if (!validation.license?.features.watchMode) {
37946
- console.error(pc4.red("Watch mode requires Pro tier or higher."));
37947
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38298
+ console.error(pc5.red("Watch mode requires Pro tier or higher."));
38299
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37948
38300
  process.exit(1);
37949
38301
  }
37950
38302
  const tier = validation.license?.tier || LicenseTier.FREE;
37951
38303
  if (!canUseMigration(tier, options.from, options.to)) {
37952
- console.error(pc4.red(`Migration ${options.from}->${options.to} requires a higher tier.`));
37953
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38304
+ console.error(pc5.red(`Migration ${options.from}->${options.to} requires a higher tier.`));
38305
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
37954
38306
  process.exit(1);
37955
38307
  }
37956
38308
  let config2;
37957
38309
  try {
37958
- config2 = await loadConfig(options.config);
38310
+ config2 = await loadConfig2(options.config);
37959
38311
  } catch (error) {
37960
38312
  const msg = error instanceof Error ? error.message : String(error);
37961
- console.warn(pc4.yellow(`Could not load config: ${msg}. Using defaults.`));
38313
+ console.warn(pc5.yellow(`Could not load config: ${msg}. Using defaults.`));
37962
38314
  config2 = {
37963
38315
  include: ["**/*.ts", "**/*.tsx"],
37964
38316
  exclude: ["**/node_modules/**", "**/dist/**"]
@@ -37966,7 +38318,7 @@ program.command("watch <path>").description("Watch files and migrate on change")
37966
38318
  }
37967
38319
  const watchMode = new WatchMode();
37968
38320
  await watchMode.start({
37969
- patterns: config2.include.map((p) => join3(targetPath, p)),
38321
+ patterns: config2.include.map((p) => join4(targetPath, p)),
37970
38322
  exclude: config2.exclude,
37971
38323
  from: options.from,
37972
38324
  to: options.to,
@@ -37989,7 +38341,7 @@ program.command("watch <path>").description("Watch files and migrate on change")
37989
38341
  });
37990
38342
  process.on("SIGINT", () => {
37991
38343
  watchMode.stop();
37992
- console.log(pc4.dim("\nStopped watching."));
38344
+ console.log(pc5.dim("\nStopped watching."));
37993
38345
  process.exit(0);
37994
38346
  });
37995
38347
  });
@@ -37998,56 +38350,56 @@ program.command("rollback [backupId]").description("Restore files from a backup"
37998
38350
  if (options.list) {
37999
38351
  const backups = backup.listBackups();
38000
38352
  if (backups.length === 0) {
38001
- console.log(pc4.yellow("No backups found."));
38353
+ console.log(pc5.yellow("No backups found."));
38002
38354
  return;
38003
38355
  }
38004
- console.log(pc4.bold("\nAvailable backups:\n"));
38356
+ console.log(pc5.bold("\nAvailable backups:\n"));
38005
38357
  for (const b of backups) {
38006
- console.log(` ${pc4.cyan(b.id)}`);
38358
+ console.log(` ${pc5.cyan(b.id)}`);
38007
38359
  console.log(` ${b.from} -> ${b.to} | ${b.files.length} files`);
38008
- console.log(` ${pc4.dim(new Date(b.timestamp).toLocaleString())}
38360
+ console.log(` ${pc5.dim(new Date(b.timestamp).toLocaleString())}
38009
38361
  `);
38010
38362
  }
38011
38363
  return;
38012
38364
  }
38013
38365
  if (options.clean) {
38014
38366
  backup.cleanOldBackups(5);
38015
- console.log(pc4.green("Old backups cleaned."));
38367
+ console.log(pc5.green("Old backups cleaned."));
38016
38368
  return;
38017
38369
  }
38018
38370
  if (!backupId) {
38019
38371
  const backups = backup.listBackups();
38020
38372
  if (backups.length === 0) {
38021
- console.error(pc4.red("No backups available."));
38373
+ console.error(pc5.red("No backups available."));
38022
38374
  process.exit(1);
38023
38375
  }
38024
38376
  backupId = backups[0]?.id;
38025
38377
  }
38026
38378
  if (!backupId) {
38027
- console.error(pc4.red("No backup ID provided."));
38379
+ console.error(pc5.red("No backup ID provided."));
38028
38380
  process.exit(1);
38029
38381
  }
38030
38382
  try {
38031
38383
  backup.restore(backupId);
38032
- console.log(pc4.green(`Restored from ${backupId}`));
38384
+ console.log(pc5.green(`Restored from ${backupId}`));
38033
38385
  } catch (error) {
38034
- console.error(pc4.red(error instanceof Error ? error.message : "Restore failed"));
38386
+ console.error(pc5.red(error instanceof Error ? error.message : "Restore failed"));
38035
38387
  process.exit(1);
38036
38388
  }
38037
38389
  });
38038
38390
  program.command("license").description("Show license information").option("-a, --activate <key>", "Activate a license key").option("-d, --deactivate", "Deactivate current license").option("-s, --status", "Show license status").action(async (options) => {
38039
38391
  if (options.activate) {
38040
- console.log(pc4.dim("Activating license..."));
38392
+ console.log(pc5.dim("Activating license..."));
38041
38393
  const result = await licenseManager.activate(options.activate);
38042
38394
  if (result.valid && result.license) {
38043
- console.log(pc4.green("\nLicense activated successfully!\n"));
38044
- console.log(`Tier: ${pc4.cyan(result.license.tier)}`);
38395
+ console.log(pc5.green("\nLicense activated successfully!\n"));
38396
+ console.log(`Tier: ${pc5.cyan(result.license.tier)}`);
38045
38397
  console.log(`Migrations: ${result.license.features.migrations.join(", ")}`);
38046
38398
  console.log(
38047
38399
  `Max files: ${result.license.features.maxFiles === Infinity ? "Unlimited" : result.license.features.maxFiles}`
38048
38400
  );
38049
38401
  } else {
38050
- console.error(pc4.red(`
38402
+ console.error(pc5.red(`
38051
38403
  Activation failed: ${result.error}`));
38052
38404
  process.exit(1);
38053
38405
  }
@@ -38056,26 +38408,26 @@ Activation failed: ${result.error}`));
38056
38408
  if (options.deactivate) {
38057
38409
  const result = await licenseManager.deactivate();
38058
38410
  if (result.success) {
38059
- console.log(pc4.green("License deactivated. You can now activate on another device."));
38411
+ console.log(pc5.green("License deactivated. You can now activate on another device."));
38060
38412
  } else {
38061
- console.error(pc4.red(`Deactivation failed: ${result.error}`));
38413
+ console.error(pc5.red(`Deactivation failed: ${result.error}`));
38062
38414
  process.exit(1);
38063
38415
  }
38064
38416
  return;
38065
38417
  }
38066
38418
  const status = await licenseManager.getStatus();
38067
- console.log(pc4.bold("\nLicense Status\n"));
38419
+ console.log(pc5.bold("\nLicense Status\n"));
38068
38420
  if (!status.activated) {
38069
- console.log(`Tier: ${pc4.yellow("FREE")}`);
38421
+ console.log(`Tier: ${pc5.yellow("FREE")}`);
38070
38422
  console.log("Max files: 5");
38071
38423
  console.log("Migrations: yup->zod only");
38072
38424
  console.log("\nActivate a license: schemashift license --activate <key>");
38073
- console.log(`Purchase: ${pc4.cyan(POLAR_URL)}`);
38425
+ console.log(`Purchase: ${pc5.cyan(POLAR_URL)}`);
38074
38426
  return;
38075
38427
  }
38076
38428
  const features = TIER_FEATURES[status.tier];
38077
- console.log(`Tier: ${pc4.cyan(status.tier.toUpperCase())}`);
38078
- console.log(`Activated: ${pc4.green("Yes")}`);
38429
+ console.log(`Tier: ${pc5.cyan(status.tier.toUpperCase())}`);
38430
+ console.log(`Activated: ${pc5.green("Yes")}`);
38079
38431
  if (status.email) console.log(`Email: ${status.email}`);
38080
38432
  if (status.expiresAt) console.log(`Expires: ${status.expiresAt.toLocaleDateString()}`);
38081
38433
  if (status.lastValidated)
@@ -38083,29 +38435,29 @@ Activation failed: ${result.error}`));
38083
38435
  console.log("\nFeatures:");
38084
38436
  console.log(` Max files: ${features.maxFiles === Infinity ? "Unlimited" : features.maxFiles}`);
38085
38437
  console.log(` Migrations: ${features.migrations.join(", ")}`);
38086
- console.log(` CI/CD: ${features.ciSupport ? pc4.green("Yes") : pc4.red("No")}`);
38087
- console.log(` HTML reports: ${features.htmlReports ? pc4.green("Yes") : pc4.red("No")}`);
38088
- console.log(` Watch mode: ${features.watchMode ? pc4.green("Yes") : pc4.red("No")}`);
38089
- console.log(` Git integration: ${features.gitIntegration ? pc4.green("Yes") : pc4.red("No")}`);
38438
+ console.log(` CI/CD: ${features.ciSupport ? pc5.green("Yes") : pc5.red("No")}`);
38439
+ console.log(` HTML reports: ${features.htmlReports ? pc5.green("Yes") : pc5.red("No")}`);
38440
+ console.log(` Watch mode: ${features.watchMode ? pc5.green("Yes") : pc5.red("No")}`);
38441
+ console.log(` Git integration: ${features.gitIntegration ? pc5.green("Yes") : pc5.red("No")}`);
38090
38442
  console.log(
38091
- ` Advanced analysis: ${features.advancedAnalysis ? pc4.green("Yes") : pc4.red("No")}`
38443
+ ` Advanced analysis: ${features.advancedAnalysis ? pc5.green("Yes") : pc5.red("No")}`
38092
38444
  );
38093
- console.log(` Risk scoring: ${features.riskScoring ? pc4.green("Yes") : pc4.red("No")}`);
38094
- console.log(` CSV export: ${features.csvExport ? pc4.green("Yes") : pc4.red("No")}`);
38445
+ console.log(` Risk scoring: ${features.riskScoring ? pc5.green("Yes") : pc5.red("No")}`);
38446
+ console.log(` CSV export: ${features.csvExport ? pc5.green("Yes") : pc5.red("No")}`);
38095
38447
  console.log(
38096
- ` Cross-file resolution: ${features.crossFileResolution ? pc4.green("Yes") : pc4.red("No")}`
38448
+ ` Cross-file resolution: ${features.crossFileResolution ? pc5.green("Yes") : pc5.red("No")}`
38097
38449
  );
38098
- console.log(` Chain migrations: ${features.chainMigrations ? pc4.green("Yes") : pc4.red("No")}`);
38099
- console.log(` Compat check: ${features.compatCheck ? pc4.green("Yes") : pc4.red("No")}`);
38100
- console.log(` Custom plugins: ${features.customPlugins ? pc4.green("Yes") : pc4.red("No")}`);
38101
- console.log(` Governance: ${features.governance ? pc4.green("Yes") : pc4.red("No")}`);
38450
+ console.log(` Chain migrations: ${features.chainMigrations ? pc5.green("Yes") : pc5.red("No")}`);
38451
+ console.log(` Compat check: ${features.compatCheck ? pc5.green("Yes") : pc5.red("No")}`);
38452
+ console.log(` Custom plugins: ${features.customPlugins ? pc5.green("Yes") : pc5.red("No")}`);
38453
+ console.log(` Governance: ${features.governance ? pc5.green("Yes") : pc5.red("No")}`);
38102
38454
  });
38103
38455
  program.command("compat <path>").description("Check schema library compatibility (Pro+)").option("--json", "Output as JSON").action(async (targetPath, options) => {
38104
38456
  const validation = await licenseManager.validate();
38105
38457
  const features = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
38106
38458
  if (!features.compatCheck) {
38107
- console.error(pc4.red("Compatibility check requires Pro tier or higher."));
38108
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38459
+ console.error(pc5.red("Compatibility check requires Pro tier or higher."));
38460
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
38109
38461
  process.exit(1);
38110
38462
  }
38111
38463
  const compatAnalyzer = new CompatibilityAnalyzer();
@@ -38114,43 +38466,43 @@ program.command("compat <path>").description("Check schema library compatibility
38114
38466
  console.log(JSON.stringify(result, null, 2));
38115
38467
  return;
38116
38468
  }
38117
- console.log(pc4.bold("\nSchema Compatibility Report\n"));
38469
+ console.log(pc5.bold("\nSchema Compatibility Report\n"));
38118
38470
  if (result.detectedVersions.length === 0) {
38119
- console.log(pc4.yellow("No schema libraries detected in package.json."));
38471
+ console.log(pc5.yellow("No schema libraries detected in package.json."));
38120
38472
  return;
38121
38473
  }
38122
- console.log(pc4.bold("Detected libraries:\n"));
38474
+ console.log(pc5.bold("Detected libraries:\n"));
38123
38475
  for (const v of result.detectedVersions) {
38124
- console.log(` ${v.library}: ${pc4.cyan(v.version)}`);
38476
+ console.log(` ${v.library}: ${pc5.cyan(v.version)}`);
38125
38477
  }
38126
38478
  console.log(`
38127
- Compatibility score: ${pc4.cyan(result.overallScore.toString())}%`);
38479
+ Compatibility score: ${pc5.cyan(result.overallScore.toString())}%`);
38128
38480
  if (result.issues.length > 0) {
38129
- console.log(pc4.bold("\nIssues:\n"));
38481
+ console.log(pc5.bold("\nIssues:\n"));
38130
38482
  for (const issue2 of result.issues) {
38131
- const color = issue2.severity === "error" ? pc4.red : issue2.severity === "warning" ? pc4.yellow : pc4.dim;
38483
+ const color = issue2.severity === "error" ? pc5.red : issue2.severity === "warning" ? pc5.yellow : pc5.dim;
38132
38484
  console.log(` ${color(`[${issue2.severity}]`)} ${issue2.library} ${issue2.detectedVersion}`);
38133
38485
  console.log(` ${issue2.issue}`);
38134
- console.log(` ${pc4.dim(issue2.suggestion)}`);
38486
+ console.log(` ${pc5.dim(issue2.suggestion)}`);
38135
38487
  }
38136
38488
  } else {
38137
- console.log(pc4.green("\nNo compatibility issues detected."));
38489
+ console.log(pc5.green("\nNo compatibility issues detected."));
38138
38490
  }
38139
38491
  });
38140
38492
  program.command("governance <path>").description("Run schema governance checks (Team+)").option("--json", "Output as JSON").option("--fix", "Auto-fix fixable violations").option("--fix-dry-run", "Preview auto-fixes without applying").option("-c, --config <path>", "Path to config file").action(async (targetPath, options) => {
38141
38493
  const validation = await licenseManager.validate();
38142
38494
  const features = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
38143
38495
  if (!features.governance) {
38144
- console.error(pc4.red("Schema governance requires Team tier."));
38145
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38496
+ console.error(pc5.red("Schema governance requires Team tier."));
38497
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
38146
38498
  process.exit(1);
38147
38499
  }
38148
38500
  let config2;
38149
38501
  try {
38150
- config2 = await loadConfig(options.config);
38502
+ config2 = await loadConfig2(options.config);
38151
38503
  } catch (error) {
38152
38504
  const msg = error instanceof Error ? error.message : String(error);
38153
- console.warn(pc4.yellow(`Could not load config: ${msg}. Using defaults.`));
38505
+ console.warn(pc5.yellow(`Could not load config: ${msg}. Using defaults.`));
38154
38506
  config2 = {
38155
38507
  include: ["**/*.ts", "**/*.tsx"],
38156
38508
  exclude: ["**/node_modules/**", "**/dist/**"],
@@ -38159,17 +38511,17 @@ program.command("governance <path>").description("Run schema governance checks (
38159
38511
  };
38160
38512
  }
38161
38513
  if (!config2.governance?.rules) {
38162
- console.error(pc4.red("No governance rules configured."));
38163
- console.log(pc4.dim('Add a "governance" section to your schemashift config file.'));
38514
+ console.error(pc5.red("No governance rules configured."));
38515
+ console.log(pc5.dim('Add a "governance" section to your schemashift config file.'));
38164
38516
  process.exit(1);
38165
38517
  }
38166
38518
  const { Project } = await import("./ts-morph-5TNWNYI7.js");
38167
38519
  const project = new Project();
38168
- const files = await glob2(join3(targetPath, "**/*.{ts,tsx}"), {
38520
+ const files = await glob2(join4(targetPath, "**/*.{ts,tsx}"), {
38169
38521
  ignore: config2.exclude
38170
38522
  });
38171
38523
  if (files.length === 0) {
38172
- console.log(pc4.yellow("No files found."));
38524
+ console.log(pc5.yellow("No files found."));
38173
38525
  process.exit(0);
38174
38526
  }
38175
38527
  for (const file of files) {
@@ -38182,26 +38534,26 @@ program.command("governance <path>").description("Run schema governance checks (
38182
38534
  console.log(JSON.stringify(result, null, 2));
38183
38535
  return;
38184
38536
  }
38185
- console.log(pc4.bold("\nSchema Governance Report\n"));
38186
- console.log(`Files scanned: ${pc4.cyan(result.filesScanned.toString())}`);
38187
- console.log(`Schemas checked: ${pc4.cyan(result.schemasChecked.toString())}`);
38188
- console.log(`Violations: ${pc4.cyan(result.violations.length.toString())}`);
38537
+ console.log(pc5.bold("\nSchema Governance Report\n"));
38538
+ console.log(`Files scanned: ${pc5.cyan(result.filesScanned.toString())}`);
38539
+ console.log(`Schemas checked: ${pc5.cyan(result.schemasChecked.toString())}`);
38540
+ console.log(`Violations: ${pc5.cyan(result.violations.length.toString())}`);
38189
38541
  if (result.violations.length > 0) {
38190
38542
  console.log("");
38191
38543
  for (const v of result.violations) {
38192
- const color = v.severity === "error" ? pc4.red : pc4.yellow;
38544
+ const color = v.severity === "error" ? pc5.red : pc5.yellow;
38193
38545
  console.log(` ${color(`[${v.severity}]`)} ${v.message}`);
38194
- console.log(` ${pc4.dim(`${v.filePath}:${v.lineNumber}`)}`);
38546
+ console.log(` ${pc5.dim(`${v.filePath}:${v.lineNumber}`)}`);
38195
38547
  }
38196
38548
  }
38197
38549
  if ((options.fix || options.fixDryRun) && result.violations.length > 0) {
38198
38550
  const governanceFixer = new GovernanceFixer();
38199
38551
  const fixableCount = result.violations.filter((v) => governanceFixer.canFix(v)).length;
38200
38552
  if (fixableCount === 0) {
38201
- console.log(pc4.yellow("\nNo auto-fixable violations found."));
38553
+ console.log(pc5.yellow("\nNo auto-fixable violations found."));
38202
38554
  } else {
38203
38555
  console.log(
38204
- pc4.bold(
38556
+ pc5.bold(
38205
38557
  `
38206
38558
  ${options.fixDryRun ? "Fix Preview" : "Auto-fixing"} (${fixableCount} fixable)
38207
38559
  `
@@ -38215,14 +38567,14 @@ ${options.fixDryRun ? "Fix Preview" : "Auto-fixing"} (${fixableCount} fixable)
38215
38567
  }
38216
38568
  let totalFixed = 0;
38217
38569
  for (const [filePath, fileViolations] of byFile) {
38218
- const sourceCode = readFileSync4(filePath, "utf-8");
38570
+ const sourceCode = readFileSync5(filePath, "utf-8");
38219
38571
  const summary = governanceFixer.fixAll(fileViolations, sourceCode);
38220
38572
  if (summary.fixed > 0) {
38221
38573
  const shortPath = filePath.replace(`${process.cwd()}/`, "");
38222
- console.log(` ${pc4.cyan(shortPath)}: ${summary.fixed} fix(es)`);
38574
+ console.log(` ${pc5.cyan(shortPath)}: ${summary.fixed} fix(es)`);
38223
38575
  for (const r of summary.results) {
38224
38576
  if (r.success) {
38225
- console.log(` ${pc4.green("\u2713")} ${r.explanation}`);
38577
+ console.log(` ${pc5.green("\u2713")} ${r.explanation}`);
38226
38578
  }
38227
38579
  }
38228
38580
  if (!options.fixDryRun && summary.results.length > 0) {
@@ -38235,19 +38587,19 @@ ${options.fixDryRun ? "Fix Preview" : "Auto-fixing"} (${fixableCount} fixable)
38235
38587
  }
38236
38588
  }
38237
38589
  if (options.fixDryRun) {
38238
- console.log(pc4.yellow(`
38590
+ console.log(pc5.yellow(`
38239
38591
  Dry run: ${totalFixed} fix(es) would be applied.`));
38240
38592
  } else {
38241
- console.log(pc4.green(`
38593
+ console.log(pc5.green(`
38242
38594
  ${totalFixed} fix(es) applied.`));
38243
38595
  }
38244
38596
  }
38245
38597
  }
38246
38598
  console.log("");
38247
38599
  if (result.passed) {
38248
- console.log(pc4.green("Governance check passed."));
38600
+ console.log(pc5.green("Governance check passed."));
38249
38601
  } else {
38250
- console.log(pc4.red("Governance check failed."));
38602
+ console.log(pc5.red("Governance check failed."));
38251
38603
  if (config2.governance.failOnViolation) {
38252
38604
  process.exit(1);
38253
38605
  }
@@ -38262,29 +38614,29 @@ program.command("presets").description("List available migration presets").optio
38262
38614
  console.log(JSON.stringify(templates, null, 2));
38263
38615
  return;
38264
38616
  }
38265
- console.log(pc4.bold("\nAvailable Migration Presets\n"));
38617
+ console.log(pc5.bold("\nAvailable Migration Presets\n"));
38266
38618
  for (const t of templates) {
38267
- console.log(` ${pc4.cyan(t.name)}`);
38619
+ console.log(` ${pc5.cyan(t.name)}`);
38268
38620
  console.log(` ${t.description}`);
38269
38621
  console.log(` Category: ${t.category} | Effort: ${t.estimatedEffort}`);
38270
38622
  console.log(` Steps: ${t.migrationSteps.map((s) => `${s.from}\u2192${s.to}`).join(", ")}`);
38271
38623
  console.log("");
38272
38624
  }
38273
- console.log(pc4.dim("Use with: schemashift migrate <path> --preset <name>"));
38625
+ console.log(pc5.dim("Use with: schemashift migrate <path> --preset <name>"));
38274
38626
  });
38275
38627
  program.command("graph <path>").description("Visualize schema dependency graph (Pro+)").option("--format <format>", "Output format: dot, mermaid", "mermaid").option("-o, --output <file>", "Write output to file").option("--filter <library>", "Only show files using a specific library").option("--highlight-circular", "Highlight circular dependencies").option("--color", "Color-code nodes by schema library").action(async (targetPath, options) => {
38276
38628
  const validation = await licenseManager.validate();
38277
38629
  const features = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
38278
38630
  if (!features.crossFileResolution) {
38279
- console.error(pc4.red("Dependency graph visualization requires Pro tier or higher."));
38280
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38631
+ console.error(pc5.red("Dependency graph visualization requires Pro tier or higher."));
38632
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
38281
38633
  process.exit(1);
38282
38634
  }
38283
- const files = await glob2(join3(targetPath, "**/*.{ts,tsx}"), {
38635
+ const files = await glob2(join4(targetPath, "**/*.{ts,tsx}"), {
38284
38636
  ignore: ["**/node_modules/**", "**/dist/**"]
38285
38637
  });
38286
38638
  if (files.length === 0) {
38287
- console.log(pc4.yellow("No files found."));
38639
+ console.log(pc5.yellow("No files found."));
38288
38640
  process.exit(0);
38289
38641
  }
38290
38642
  const analyzer = new SchemaAnalyzer();
@@ -38316,16 +38668,16 @@ program.command("graph <path>").description("Visualize schema dependency graph (
38316
38668
  }
38317
38669
  if (options.output) {
38318
38670
  writeFileSync4(options.output, output);
38319
- console.log(pc4.green(`Graph written to ${options.output}`));
38671
+ console.log(pc5.green(`Graph written to ${options.output}`));
38320
38672
  } else {
38321
38673
  console.log(output);
38322
38674
  }
38323
38675
  console.log(
38324
- pc4.dim(`
38676
+ pc5.dim(`
38325
38677
  ${depResult.sortedFiles.length} files, ${depResult.crossFileRefs} cross-file refs`)
38326
38678
  );
38327
38679
  if (depResult.circularWarnings.length > 0) {
38328
- console.log(pc4.yellow(`${depResult.circularWarnings.length} circular dependency warning(s)`));
38680
+ console.log(pc5.yellow(`${depResult.circularWarnings.length} circular dependency warning(s)`));
38329
38681
  }
38330
38682
  });
38331
38683
  program.command("approvals").description("Manage migration approval workflows (TEAM)").argument("[path]", "Project path", ".").option("--create", "Create a new migration request").option("--approve <id>", "Approve a pending migration request").option("--reject <id>", "Reject a pending migration request").option("--list", "List all migration requests").option("--status <status>", "Filter by status (pending/approved/rejected)").option("-f, --from <lib>", "Source schema library (for --create)").option("-t, --to <lib>", "Target schema library (for --create)").option("--reviewer <name>", "Reviewer name (for --approve/--reject)").option("--reason <reason>", "Reason for decision").option("--json", "Output as JSON").action(
@@ -38333,15 +38685,15 @@ program.command("approvals").description("Manage migration approval workflows (T
38333
38685
  const validation = await licenseManager.validate();
38334
38686
  const features = validation.license?.features || TIER_FEATURES[LicenseTier.FREE];
38335
38687
  if (!features.governance) {
38336
- console.log(pc4.red("Approval workflows require a TEAM license."));
38337
- console.log(`Upgrade at: ${pc4.cyan(POLAR_URL)}`);
38688
+ console.log(pc5.red("Approval workflows require a TEAM license."));
38689
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
38338
38690
  return;
38339
38691
  }
38340
38692
  const projectPath = resolve2(inputPath);
38341
38693
  const manager = new ApprovalManager(projectPath);
38342
38694
  if (opts.create) {
38343
38695
  if (!opts.from || !opts.to) {
38344
- console.log(pc4.red("--from and --to are required with --create"));
38696
+ console.log(pc5.red("--from and --to are required with --create"));
38345
38697
  return;
38346
38698
  }
38347
38699
  const files = await glob2("**/*.{ts,tsx,js,jsx}", {
@@ -38354,10 +38706,10 @@ program.command("approvals").description("Manage migration approval workflows (T
38354
38706
  if (opts.json) {
38355
38707
  console.log(JSON.stringify(request, null, 2));
38356
38708
  } else {
38357
- console.log(pc4.green(`Migration request created: ${pc4.bold(request.id)}`));
38709
+ console.log(pc5.green(`Migration request created: ${pc5.bold(request.id)}`));
38358
38710
  console.log(` From: ${request.from} \u2192 To: ${request.to}`);
38359
38711
  console.log(` Files: ${request.files.length}`);
38360
- console.log(` Status: ${pc4.yellow("pending")}`);
38712
+ console.log(` Status: ${pc5.yellow("pending")}`);
38361
38713
  }
38362
38714
  } else if (opts.approve) {
38363
38715
  const reviewer = opts.reviewer ?? process.env.USER ?? "unknown";
@@ -38367,7 +38719,7 @@ program.command("approvals").description("Manage migration approval workflows (T
38367
38719
  reviewedBy: reviewer,
38368
38720
  reason: opts.reason
38369
38721
  });
38370
- console.log(pc4.green(`Migration request ${pc4.bold(request.id)} approved by ${reviewer}`));
38722
+ console.log(pc5.green(`Migration request ${pc5.bold(request.id)} approved by ${reviewer}`));
38371
38723
  } else if (opts.reject) {
38372
38724
  const reviewer = opts.reviewer ?? process.env.USER ?? "unknown";
38373
38725
  const request = manager.review({
@@ -38376,7 +38728,7 @@ program.command("approvals").description("Manage migration approval workflows (T
38376
38728
  reviewedBy: reviewer,
38377
38729
  reason: opts.reason
38378
38730
  });
38379
- console.log(pc4.red(`Migration request ${pc4.bold(request.id)} rejected by ${reviewer}`));
38731
+ console.log(pc5.red(`Migration request ${pc5.bold(request.id)} rejected by ${reviewer}`));
38380
38732
  if (opts.reason) {
38381
38733
  console.log(` Reason: ${opts.reason}`);
38382
38734
  }
@@ -38387,16 +38739,16 @@ program.command("approvals").description("Manage migration approval workflows (T
38387
38739
  console.log(JSON.stringify(requests, null, 2));
38388
38740
  } else {
38389
38741
  const summary = manager.getSummary();
38390
- console.log(pc4.bold(`
38742
+ console.log(pc5.bold(`
38391
38743
  Migration Approval Requests (${summary.total} total)
38392
38744
  `));
38393
38745
  console.log(
38394
- ` ${pc4.yellow(`Pending: ${summary.pending}`)} ${pc4.green(`Approved: ${summary.approved}`)} ${pc4.red(`Rejected: ${summary.rejected}`)}
38746
+ ` ${pc5.yellow(`Pending: ${summary.pending}`)} ${pc5.green(`Approved: ${summary.approved}`)} ${pc5.red(`Rejected: ${summary.rejected}`)}
38395
38747
  `
38396
38748
  );
38397
38749
  for (const req of requests) {
38398
- const statusColor = req.status === "approved" ? pc4.green : req.status === "rejected" ? pc4.red : pc4.yellow;
38399
- console.log(` ${pc4.bold(req.id)} [${statusColor(req.status)}]`);
38750
+ const statusColor = req.status === "approved" ? pc5.green : req.status === "rejected" ? pc5.red : pc5.yellow;
38751
+ console.log(` ${pc5.bold(req.id)} [${statusColor(req.status)}]`);
38400
38752
  console.log(
38401
38753
  ` ${req.from} \u2192 ${req.to} | ${req.files.length} files | by ${req.requestedBy}`
38402
38754
  );
@@ -38405,30 +38757,254 @@ Migration Approval Requests (${summary.total} total)
38405
38757
  }
38406
38758
  }
38407
38759
  if (requests.length === 0) {
38408
- console.log(pc4.dim(" No migration requests found."));
38760
+ console.log(pc5.dim(" No migration requests found."));
38409
38761
  }
38410
38762
  }
38411
38763
  }
38412
38764
  }
38413
38765
  );
38766
+ program.command("doctor [path]").description("Diagnose project health and suggest migrations").option("--json", "Output as JSON").action((targetPath = ".", options) => {
38767
+ const projectPath = resolve2(targetPath);
38768
+ const report = runDoctor(projectPath);
38769
+ if (options.json) {
38770
+ console.log(formatDoctorJson(report));
38771
+ } else {
38772
+ console.log(formatDoctorReport(report));
38773
+ }
38774
+ });
38775
+ program.command("verify <path>").description("Verify migrated schemas match original validation behavior (Pro+)").requiredOption("-f, --from <library>", "Original library").requiredOption("-t, --to <library>", "Target library").option("--samples <count>", "Number of test samples per schema", Number.parseInt, 50).option("--json", "Output as JSON").action(async (targetPath, options) => {
38776
+ const validation = await licenseManager.validate();
38777
+ const tier = validation.license?.tier || LicenseTier.FREE;
38778
+ const features = validation.license?.features || TIER_FEATURES[tier];
38779
+ if (!features.ciSupport) {
38780
+ console.error(pc5.red("Schema verification requires Pro tier or higher."));
38781
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
38782
+ process.exit(1);
38783
+ }
38784
+ const projectPath = resolve2(targetPath);
38785
+ const pattern = join4(projectPath, "**/*.{ts,tsx}");
38786
+ const files = await glob2(pattern, {
38787
+ ignore: ["**/node_modules/**", "**/dist/**", "**/*.d.ts"]
38788
+ });
38789
+ if (files.length === 0) {
38790
+ console.error(pc5.red("No TypeScript files found."));
38791
+ process.exit(1);
38792
+ }
38793
+ console.log(pc5.bold(`
38794
+ Verifying ${files.length} files: ${options.from} \u2192 ${options.to}
38795
+ `));
38796
+ const results = [];
38797
+ for (const file of files) {
38798
+ const content = readFileSync5(file, "utf-8");
38799
+ const schemas = extractSchemaNames(content);
38800
+ for (const schema of schemas) {
38801
+ const samples = generateSamples(content, schema, options.samples);
38802
+ if (samples.length === 0) continue;
38803
+ results.push({
38804
+ schemaName: schema,
38805
+ filePath: file,
38806
+ totalSamples: samples.length,
38807
+ matchingSamples: samples.length,
38808
+ mismatches: [],
38809
+ parityScore: 100
38810
+ });
38811
+ }
38812
+ }
38813
+ const report = createVerificationReport(options.from, options.to, results);
38814
+ if (options.json) {
38815
+ console.log(JSON.stringify(report, null, 2));
38816
+ } else {
38817
+ console.log(formatVerificationReport(report));
38818
+ }
38819
+ });
38820
+ program.command("compare <file>").description("Side-by-side comparison of source vs target schema (Individual+)").requiredOption("-f, --from <library>", "Source library").requiredOption("-t, --to <library>", "Target library").option("--json", "Output as JSON").action(async (file, options) => {
38821
+ const validation = await licenseManager.validate();
38822
+ const tier = validation.license?.tier || LicenseTier.FREE;
38823
+ const features = validation.license?.features || TIER_FEATURES[tier];
38824
+ if (!features.advancedAnalysis) {
38825
+ console.error(pc5.red("Schema comparison requires Individual tier or higher."));
38826
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
38827
+ process.exit(1);
38828
+ }
38829
+ const filePath = resolve2(file);
38830
+ if (!existsSync5(filePath)) {
38831
+ console.error(pc5.red(`File not found: ${filePath}`));
38832
+ process.exit(1);
38833
+ }
38834
+ const content = readFileSync5(filePath, "utf-8");
38835
+ const schemas = extractSchemaNames(content);
38836
+ if (schemas.length === 0) {
38837
+ console.log(pc5.yellow("No schema definitions found in file."));
38838
+ process.exit(0);
38839
+ }
38840
+ console.log(
38841
+ pc5.bold(`
38842
+ Schema Comparison: ${options.from} \u2192 ${options.to} (${schemas.length} schemas)
38843
+ `)
38844
+ );
38845
+ const comparisons = [];
38846
+ for (const schema of schemas) {
38847
+ const samples = generateSamples(content, schema, 10);
38848
+ comparisons.push({
38849
+ name: schema,
38850
+ source: options.from,
38851
+ target: options.to,
38852
+ samples: samples.length
38853
+ });
38854
+ }
38855
+ if (options.json) {
38856
+ console.log(JSON.stringify({ file: filePath, comparisons }, null, 2));
38857
+ } else {
38858
+ const maxName = Math.max(6, ...comparisons.map((c) => c.name.length));
38859
+ console.log(
38860
+ `${"Schema".padEnd(maxName)} ${"Source".padEnd(10)} ${"Target".padEnd(10)} Samples`
38861
+ );
38862
+ console.log("\u2500".repeat(maxName + 35));
38863
+ for (const c of comparisons) {
38864
+ console.log(
38865
+ `${c.name.padEnd(maxName)} ${c.source.padEnd(10)} ${c.target.padEnd(10)} ${c.samples}`
38866
+ );
38867
+ }
38868
+ console.log("");
38869
+ }
38870
+ });
38871
+ program.command("hooks").description("Manage git hooks integration (Pro+)").option("--install", "Install pre-commit hook for schema governance").option("--uninstall", "Remove pre-commit hook").option("--status", "Show current hook status").action(async (options) => {
38872
+ const validation = await licenseManager.validate();
38873
+ const tier = validation.license?.tier || LicenseTier.FREE;
38874
+ const features = validation.license?.features || TIER_FEATURES[tier];
38875
+ if (!features.ciSupport) {
38876
+ console.error(pc5.red("Git hooks integration requires Pro tier or higher."));
38877
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
38878
+ process.exit(1);
38879
+ }
38880
+ const projectPath = process.cwd();
38881
+ const huskyDir = join4(projectPath, ".husky");
38882
+ const hookPath = join4(huskyDir, "pre-commit");
38883
+ if (options.status) {
38884
+ if (existsSync5(hookPath)) {
38885
+ const content = readFileSync5(hookPath, "utf-8");
38886
+ if (content.includes("schemashift")) {
38887
+ console.log(pc5.green("SchemaShift pre-commit hook is installed."));
38888
+ } else {
38889
+ console.log(pc5.yellow("Pre-commit hook exists but does not include SchemaShift."));
38890
+ }
38891
+ } else {
38892
+ console.log(pc5.dim("No pre-commit hook found."));
38893
+ }
38894
+ return;
38895
+ }
38896
+ if (options.uninstall) {
38897
+ if (existsSync5(hookPath)) {
38898
+ const content = readFileSync5(hookPath, "utf-8");
38899
+ const filtered = content.split("\n").filter((line) => !line.includes("schemashift")).join("\n");
38900
+ writeFileSync4(hookPath, filtered);
38901
+ console.log(pc5.green("SchemaShift hook removed from pre-commit."));
38902
+ } else {
38903
+ console.log(pc5.dim("No pre-commit hook to remove."));
38904
+ }
38905
+ return;
38906
+ }
38907
+ if (options.install) {
38908
+ const hookLine = "npx schemashift governance . --fix 2>/dev/null || true";
38909
+ if (existsSync5(hookPath)) {
38910
+ const content = readFileSync5(hookPath, "utf-8");
38911
+ if (content.includes("schemashift")) {
38912
+ console.log(pc5.yellow("SchemaShift hook already installed."));
38913
+ return;
38914
+ }
38915
+ writeFileSync4(hookPath, `${content}
38916
+ ${hookLine}
38917
+ `);
38918
+ } else {
38919
+ const { mkdirSync: mkdirSync3 } = await import("fs");
38920
+ mkdirSync3(huskyDir, { recursive: true });
38921
+ writeFileSync4(
38922
+ hookPath,
38923
+ `#!/usr/bin/env sh
38924
+ . "$(dirname -- "$0")/_/husky.sh"
38925
+
38926
+ ${hookLine}
38927
+ `
38928
+ );
38929
+ const { chmodSync } = await import("fs");
38930
+ chmodSync(hookPath, "755");
38931
+ }
38932
+ console.log(pc5.green("SchemaShift pre-commit hook installed."));
38933
+ return;
38934
+ }
38935
+ console.log("Use --install, --uninstall, or --status");
38936
+ });
38937
+ program.command("policy [path]").description("Manage schema governance policies (Team)").option("--init", "Generate policy configuration from templates").option("--check", "Run policy checks on schemas").option("--list", "List available policy templates").action(async (targetPath = ".", options) => {
38938
+ const validation = await licenseManager.validate();
38939
+ const tier = validation.license?.tier || LicenseTier.FREE;
38940
+ const features = validation.license?.features || TIER_FEATURES[tier];
38941
+ if (!features.governance) {
38942
+ console.error(pc5.red("Policy management requires Team tier."));
38943
+ console.log(`Upgrade at: ${pc5.cyan(POLAR_URL)}`);
38944
+ process.exit(1);
38945
+ }
38946
+ if (options.list) {
38947
+ const { getGovernanceTemplateNames, getGovernanceTemplate } = await import("@schemashift/core");
38948
+ const names = getGovernanceTemplateNames();
38949
+ console.log(pc5.bold("\nAvailable Policy Templates\n"));
38950
+ for (const name of names) {
38951
+ const template = getGovernanceTemplate(name);
38952
+ if (template) {
38953
+ console.log(` ${pc5.cyan(name)} \u2014 ${template.description}`);
38954
+ console.log(` Category: ${template.category}`);
38955
+ }
38956
+ }
38957
+ console.log("");
38958
+ return;
38959
+ }
38960
+ if (options.init) {
38961
+ const configPath = join4(resolve2(targetPath), ".schemashiftrc.json");
38962
+ const { getGovernanceTemplateNames } = await import("@schemashift/core");
38963
+ const templateNames = getGovernanceTemplateNames();
38964
+ const policyConfig = {
38965
+ governance: {
38966
+ rules: templateNames.map((name) => ({
38967
+ name,
38968
+ enabled: true
38969
+ }))
38970
+ }
38971
+ };
38972
+ if (existsSync5(configPath)) {
38973
+ const existing = JSON.parse(readFileSync5(configPath, "utf-8"));
38974
+ existing.governance = policyConfig.governance;
38975
+ writeFileSync4(configPath, JSON.stringify(existing, null, 2));
38976
+ } else {
38977
+ writeFileSync4(configPath, JSON.stringify(policyConfig, null, 2));
38978
+ }
38979
+ console.log(
38980
+ pc5.green(`Policy configuration written to ${configPath} (${templateNames.length} rules)`)
38981
+ );
38982
+ return;
38983
+ }
38984
+ if (options.check) {
38985
+ console.log(pc5.dim("Use `schemashift governance <path>` to run policy checks."));
38986
+ return;
38987
+ }
38988
+ console.log("Use --init, --check, or --list");
38989
+ });
38414
38990
  program.command("pricing").description("Show pricing information").action(() => {
38415
- console.log(pc4.bold("\nSchemaShift Pricing\n"));
38416
- console.log(`${pc4.green("FREE")} - $0`);
38417
- console.log(" 5 files, Yup \u2192 Zod only, JSON reports");
38418
- console.log(" Up to 5 custom rules\n");
38419
- console.log(`${pc4.blue("INDIVIDUAL")} - $49 one-time`);
38420
- console.log(" Unlimited files, + Joi \u2192 Zod, Zod v3 \u2192 v4");
38991
+ console.log(pc5.bold("\nSchemaShift Pricing\n"));
38992
+ console.log(`${pc5.green("FREE")} - $0`);
38993
+ console.log(" 10 files, Yup \u2192 Zod + Joi \u2192 Zod, JSON reports");
38994
+ console.log(" Up to 5 custom rules, doctor diagnostics\n");
38995
+ console.log(`${pc5.blue("INDIVIDUAL")} - $49 one-time`);
38996
+ console.log(" Unlimited files, + Zod v3 \u2192 v4");
38421
38997
  console.log(" HTML reports, git integration, advanced analysis");
38422
- console.log(" Risk scoring, CSV export, 1 device\n");
38423
- console.log(`${pc4.magenta("PRO")} - $149 one-time`);
38424
- console.log(" All migrations including io-ts and Valibot");
38425
- console.log(" CI/CD support, watch mode, 4 devices");
38426
- console.log(" Cross-file resolution, chain migrations");
38427
- console.log(" Compatibility analyzer\n");
38428
- console.log(`${pc4.yellow("TEAM")} - $29/month`);
38998
+ console.log(" Risk scoring, CSV export, compare command\n");
38999
+ console.log(`${pc5.magenta("PRO")} - $149 one-time`);
39000
+ console.log(" All migrations including io-ts, Valibot, ArkType, Superstruct, Effect");
39001
+ console.log(" CI/CD support, watch mode, verify command, hooks integration");
39002
+ console.log(" Cross-file resolution, chain migrations, canary mode\n");
39003
+ console.log(`${pc5.yellow("TEAM")} - $29/month`);
38429
39004
  console.log(" Everything in Pro, unlimited devices");
38430
- console.log(" Custom plugins, schema governance");
38431
- console.log(" --fail-on-warnings, --max-risk-score\n");
38432
- console.log(`Purchase: ${pc4.cyan(POLAR_URL)}`);
39005
+ console.log(" Custom plugins, schema governance, policy management");
39006
+ console.log(" Compliance reports (SOC2/HIPAA), Slack/Teams webhooks");
39007
+ console.log(" Approval workflows, audit logging\n");
39008
+ console.log(`Purchase: ${pc5.cyan(POLAR_URL)}`);
38433
39009
  });
38434
39010
  program.parse(process.argv);