@expcat/tigercat-cli 1.3.4 → 1.5.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.
Files changed (2) hide show
  1. package/dist/index.js +240 -112
  2. package/package.json +6 -4
package/dist/index.js CHANGED
@@ -5,32 +5,67 @@ import { existsSync, readdirSync, mkdirSync, writeFileSync, readFileSync } from
5
5
  import { resolve, join, dirname, basename } from 'path';
6
6
  import pc2 from 'picocolors';
7
7
  import { execSync } from 'child_process';
8
+ import { createRequire } from 'module';
9
+ import { pathToFileURL } from 'url';
10
+
11
+ function logSuccess(msg) {
12
+ console.log(pc2.green("\u2714") + " " + msg);
13
+ }
14
+ function logInfo(msg) {
15
+ console.log(pc2.blue("\u2139") + " " + msg);
16
+ }
17
+ function logWarn(msg) {
18
+ console.log(pc2.yellow("\u26A0") + " " + msg);
19
+ }
20
+ function logError(msg) {
21
+ console.error(pc2.red("\u2716") + " " + msg);
22
+ }
23
+ function logStep(step, total, msg) {
24
+ console.log(pc2.dim(`[${step}/${total}]`) + " " + msg);
25
+ }
26
+ function ensureDir(dir) {
27
+ if (!existsSync(dir)) {
28
+ mkdirSync(dir, { recursive: true });
29
+ }
30
+ }
31
+ function writeFileSafe(filePath, content) {
32
+ ensureDir(dirname(filePath));
33
+ writeFileSync(filePath, content, "utf-8");
34
+ }
35
+ function isDirEmpty(dir) {
36
+ if (!existsSync(dir)) return true;
37
+ return readdirSync(dir).length === 0;
38
+ }
39
+ function readFileSafe(filePath) {
40
+ if (!existsSync(filePath)) return null;
41
+ return readFileSync(filePath, "utf-8");
42
+ }
8
43
 
9
44
  // src/constants.ts
10
45
  var CLI_NAME = "tigercat";
11
- var CLI_VERSION = "1.3.4";
46
+ var CLI_VERSION = "1.5.0";
12
47
  var TEMPLATES = ["vue3", "react"];
13
48
  var TEMPLATE_VERSIONS = {
14
49
  // Tigercat packages (use caret on latest major)
15
- tigercat: "^1.3.4",
50
+ tigercat: "^1.5.0",
16
51
  // Frameworks
17
- vue: "^3.5.33",
18
- react: "^19.2.5",
19
- reactDom: "^19.2.5",
52
+ vue: "^3.5.38",
53
+ react: "^19.2.7",
54
+ reactDom: "^19.2.7",
20
55
  // Build toolchain
21
56
  typescript: "^6.0.3",
22
- vite: "^8.0.10",
23
- tailwindcss: "^4.2.4",
24
- tailwindcssVite: "^4.2.4",
57
+ vite: "^8.1.0",
58
+ tailwindcss: "^4.3.1",
59
+ tailwindcssVite: "^4.3.1",
25
60
  // Vite plugins
26
- vitejsPluginVue: "^6.0.6",
27
- vitejsPluginReact: "^6.0.1",
61
+ vitejsPluginVue: "^6.0.7",
62
+ vitejsPluginReact: "^6.0.3",
28
63
  // Type definitions
29
- typesReact: "^19.2.14",
64
+ typesReact: "^19.2.17",
30
65
  typesReactDom: "^19.2.3",
31
66
  // Vue-specific
32
67
  vueTsconfig: "^0.9.1",
33
- vueTsc: "^3.2.7"
68
+ vueTsc: "^3.3.5"
34
69
  };
35
70
  var COMPONENT_CATEGORIES = {
36
71
  basic: [
@@ -86,37 +121,50 @@ var COMPONENT_CATEGORIES = {
86
121
  ]
87
122
  };
88
123
  var ALL_COMPONENTS = Object.values(COMPONENT_CATEGORIES).flat();
89
- function logSuccess(msg) {
90
- console.log(pc2.green("\u2714") + " " + msg);
91
- }
92
- function logInfo(msg) {
93
- console.log(pc2.blue("\u2139") + " " + msg);
94
- }
95
- function logWarn2(msg) {
96
- console.log(pc2.yellow("\u26A0") + " " + msg);
97
- }
98
- function logError(msg) {
99
- console.error(pc2.red("\u2716") + " " + msg);
100
- }
101
- function logStep(step, total, msg) {
102
- console.log(pc2.dim(`[${step}/${total}]`) + " " + msg);
103
- }
104
- function ensureDir(dir) {
105
- if (!existsSync(dir)) {
106
- mkdirSync(dir, { recursive: true });
124
+
125
+ // src/utils/validate.ts
126
+ var PACKAGE_NAME_REGEX = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
127
+ function validateProjectName(name) {
128
+ if (name.trim().length === 0) return "Project name must not be empty";
129
+ if (name.trim() !== name) return "Project name must not have leading or trailing spaces";
130
+ if (name.length > 214) return "Project name must be 214 characters or fewer";
131
+ if (/[A-Z]/.test(name)) return "Project name must not contain uppercase letters";
132
+ if (!PACKAGE_NAME_REGEX.test(name)) {
133
+ return 'Project name is not a valid npm package name (use lowercase letters, digits, "-", "_" or ".")';
107
134
  }
135
+ return null;
108
136
  }
109
- function writeFileSafe(filePath, content) {
110
- ensureDir(dirname(filePath));
111
- writeFileSync(filePath, content, "utf-8");
137
+ function suggestProjectName(name) {
138
+ const sanitizeSegment = (segment) => segment.trim().toLowerCase().replace(/[^a-z0-9-._~]+/g, "-").replace(/^[-._~]+|[-._~]+$/g, "").replace(/-{2,}/g, "-");
139
+ const scopeMatch = /^@(.+?)\/(.+)$/.exec(name.trim());
140
+ const suggestion = scopeMatch ? `@${sanitizeSegment(scopeMatch[1])}/${sanitizeSegment(scopeMatch[2])}` : sanitizeSegment(name);
141
+ return suggestion || "tigercat-app";
112
142
  }
113
- function isDirEmpty(dir) {
114
- if (!existsSync(dir)) return true;
115
- return readdirSync(dir).length === 0;
143
+ function isFramework(value) {
144
+ return value === "vue3" || value === "react";
116
145
  }
117
- function readFileSafe(filePath) {
118
- if (!existsSync(filePath)) return null;
119
- return readFileSync(filePath, "utf-8");
146
+ async function resolveTemplateOption(arg, promptMessage) {
147
+ if (arg !== void 0) {
148
+ if (!TEMPLATES.includes(arg)) {
149
+ logError(`Invalid template "${arg}". Valid templates: ${TEMPLATES.join(", ")}`);
150
+ process.exit(1);
151
+ }
152
+ return arg;
153
+ }
154
+ const response = await prompts({
155
+ type: "select",
156
+ name: "template",
157
+ message: promptMessage,
158
+ choices: [
159
+ { title: "Vue 3", value: "vue3" },
160
+ { title: "React", value: "react" }
161
+ ]
162
+ });
163
+ if (!response.template) {
164
+ logError("Operation cancelled");
165
+ process.exit(1);
166
+ }
167
+ return response.template;
120
168
  }
121
169
 
122
170
  // src/templates/vue3.ts
@@ -534,31 +582,18 @@ function createCreateCommand() {
534
582
  });
535
583
  }
536
584
  async function runCreate(name, templateArg, dryRun = false) {
537
- let template;
538
- if (templateArg && TEMPLATES.includes(templateArg)) {
539
- template = templateArg;
540
- } else {
541
- const response = await prompts({
542
- type: "select",
543
- name: "template",
544
- message: "Select a framework",
545
- choices: [
546
- { title: "Vue 3", value: "vue3" },
547
- { title: "React", value: "react" }
548
- ]
549
- });
550
- if (!response.template) {
551
- logError("Operation cancelled");
552
- process.exit(1);
553
- }
554
- template = response.template;
585
+ const nameError = validateProjectName(name);
586
+ if (nameError) {
587
+ logError(`${nameError}. Try "${suggestProjectName(name)}" instead.`);
588
+ process.exit(1);
555
589
  }
590
+ const template = await resolveTemplateOption(templateArg, "Select a framework");
556
591
  const targetDir = resolve(process.cwd(), name);
557
592
  if (!dryRun && existsSync(targetDir) && !isDirEmpty(targetDir)) {
558
593
  const { overwrite } = await prompts({
559
594
  type: "confirm",
560
595
  name: "overwrite",
561
- message: `Directory "${name}" is not empty. Remove existing files and continue?`,
596
+ message: `Directory "${name}" is not empty. Overwrite conflicting template files? (other files are kept)`,
562
597
  initial: false
563
598
  });
564
599
  if (!overwrite) {
@@ -590,6 +625,20 @@ async function runCreate(name, templateArg, dryRun = false) {
590
625
  console.log(" pnpm install");
591
626
  console.log(" pnpm dev\n");
592
627
  }
628
+ function runCommand(command, options = {}) {
629
+ try {
630
+ execSync(command, { cwd: options.cwd, stdio: "inherit" });
631
+ } catch (error) {
632
+ if (options.allowFailure) return;
633
+ if (options.failureMessage !== void 0) {
634
+ logError(options.failureMessage);
635
+ process.exit(1);
636
+ }
637
+ throw error;
638
+ }
639
+ }
640
+
641
+ // src/commands/add.ts
593
642
  function createAddCommand() {
594
643
  return new Command("add").argument("[components...]", "Component names to add (e.g. Button Input Select)").option("-f, --framework <framework>", "Framework override (vue3 | react)").option("--install", "Install missing Tigercat dependencies before generating snippets").option("--snippet <file>", "Generate a reusable import snippet file").option("--dry-run", "Preview generated demo files without writing them").description("Add component import boilerplate to your project").action(async (components, opts) => {
595
644
  await runAdd(components ?? [], opts);
@@ -608,8 +657,7 @@ function detectFramework(cwd) {
608
657
  return null;
609
658
  }
610
659
  function normalizeFramework(value) {
611
- if (value === "vue3" || value === "react") return value;
612
- return null;
660
+ return value !== void 0 && isFramework(value) ? value : null;
613
661
  }
614
662
  async function resolveComponents(components) {
615
663
  if (components.length > 0) return components;
@@ -661,6 +709,10 @@ function validateComponents(names) {
661
709
  }
662
710
  async function runAdd(components, options = {}) {
663
711
  const cwd = process.cwd();
712
+ if (options.framework !== void 0 && !isFramework(options.framework)) {
713
+ logError(`Invalid framework "${options.framework}". Valid frameworks: vue3, react`);
714
+ process.exit(1);
715
+ }
664
716
  const framework = normalizeFramework(options.framework) ?? detectFramework(cwd);
665
717
  const dryRun = Boolean(options.dryRun);
666
718
  if (!framework) {
@@ -672,7 +724,7 @@ async function runAdd(components, options = {}) {
672
724
  const selectedComponents = await resolveComponents(components);
673
725
  const { valid, invalid } = validateComponents(selectedComponents);
674
726
  if (invalid.length > 0) {
675
- logWarn2(`Unknown components: ${invalid.join(", ")}`);
727
+ logWarn(`Unknown components: ${invalid.join(", ")}`);
676
728
  logInfo(`Available: ${ALL_COMPONENTS.join(", ")}`);
677
729
  }
678
730
  if (valid.length === 0) {
@@ -688,7 +740,7 @@ async function runAdd(components, options = {}) {
688
740
  const installCommand = formatAddCommand(packageManager, missingDeps);
689
741
  if (options.install && !dryRun) {
690
742
  logInfo(`Installing missing dependencies: ${missingDeps.join(", ")}`);
691
- execSync(installCommand, { cwd, stdio: "inherit" });
743
+ runCommand(installCommand, { cwd });
692
744
  } else {
693
745
  logInfo(`Missing dependencies detected. Run: ${installCommand}`);
694
746
  }
@@ -731,7 +783,7 @@ async function runAdd(components, options = {}) {
731
783
  const ext = framework === "vue3" ? "vue" : "tsx";
732
784
  const sampleFile = join(sampleDir, `${comp}Demo.${ext}`);
733
785
  if (existsSync(sampleFile)) {
734
- logWarn2(`${sampleFile} already exists, skipping`);
786
+ logWarn(`${sampleFile} already exists, skipping`);
735
787
  continue;
736
788
  }
737
789
  if (dryRun) {
@@ -783,29 +835,14 @@ function createPlaygroundCommand() {
783
835
  });
784
836
  }
785
837
  async function runPlayground(templateArg, port = "3456", open = true, dryRun = false) {
786
- let template;
787
- if (templateArg && TEMPLATES.includes(templateArg)) {
788
- template = templateArg;
789
- } else {
790
- const response = await prompts({
791
- type: "select",
792
- name: "template",
793
- message: "Select a framework for playground",
794
- choices: [
795
- { title: "Vue 3", value: "vue3" },
796
- { title: "React", value: "react" }
797
- ]
798
- });
799
- if (!response.template) {
800
- logError("Operation cancelled");
801
- process.exit(1);
802
- }
803
- template = response.template;
804
- }
838
+ const template = await resolveTemplateOption(
839
+ templateArg,
840
+ "Select a framework for playground"
841
+ );
805
842
  const tmpDir = resolve(process.cwd(), ".tigercat-playground");
806
843
  const projectDir = join(tmpDir, `playground-${template}`);
807
844
  if (dryRun) {
808
- const safePort = /^\d+$/.test(port) ? port : "3456";
845
+ const safePort2 = /^\d+$/.test(port) ? port : "3456";
809
846
  logInfo(`Dry run: would prepare ${template} playground in ${projectDir}.`);
810
847
  if (!existsSync(projectDir)) {
811
848
  const files = template === "vue3" ? getVue3Template("playground") : getReactTemplate("playground");
@@ -814,7 +851,7 @@ async function runPlayground(templateArg, port = "3456", open = true, dryRun = f
814
851
  }
815
852
  logInfo("Would run pnpm install");
816
853
  }
817
- logInfo(`Would start Vite on port ${safePort}${open ? " and open the browser" : ""}`);
854
+ logInfo(`Would start Vite on port ${safePort2}${open ? " and open the browser" : ""}`);
818
855
  return;
819
856
  }
820
857
  if (!existsSync(projectDir)) {
@@ -829,21 +866,16 @@ async function runPlayground(templateArg, port = "3456", open = true, dryRun = f
829
866
  writeFileSafe(resolve(projectDir, filePath), content);
830
867
  }
831
868
  logInfo("Installing dependencies...");
832
- try {
833
- execSync("pnpm install", { cwd: projectDir, stdio: "inherit" });
834
- } catch {
835
- logError("Failed to install dependencies. Make sure pnpm is available.");
836
- process.exit(1);
837
- }
869
+ runCommand("pnpm install", {
870
+ cwd: projectDir,
871
+ failureMessage: "Failed to install dependencies. Make sure pnpm is available."
872
+ });
838
873
  }
839
874
  logSuccess(`Starting playground on port ${port}...
840
875
  `);
841
- try {
842
- const safePort = /^\d+$/.test(port) ? port : "3456";
843
- const openFlag = open ? " --open" : "";
844
- execSync(`npx vite --port ${safePort}${openFlag}`, { cwd: projectDir, stdio: "inherit" });
845
- } catch {
846
- }
876
+ const safePort = /^\d+$/.test(port) ? port : "3456";
877
+ const openFlag = open ? " --open" : "";
878
+ runCommand(`npx vite --port ${safePort}${openFlag}`, { cwd: projectDir, allowFailure: true });
847
879
  }
848
880
  function createGenerateCommand() {
849
881
  const cmd = new Command("generate").description("Code generation utilities");
@@ -1131,13 +1163,37 @@ Document keyboard behavior, roles, labels, and focus management.
1131
1163
  List boundary states, empty states, loading states, and controlled/uncontrolled behavior.
1132
1164
  `;
1133
1165
  }
1134
- var MIN_NODE_MAJOR = 20;
1135
- var MIN_PNPM_MAJOR = 8;
1166
+ var MIN_NODE_VERSION = { major: 22, minor: 13, patch: 0 };
1167
+ var MIN_PNPM_VERSION = { major: 11, minor: 9, patch: 0 };
1168
+ var MIN_NODE_RANGE = "22.13.0";
1169
+ var MIN_PNPM_RANGE = "11.9.0";
1136
1170
  var REQUIRED_TAILWIND_MAJOR = 4;
1137
1171
  var REQUIRED_TIGERCAT_MAJOR = 1;
1172
+ var FRAMEWORK_PEER_RANGES = {
1173
+ vue3: [{ dep: "vue", major: 3 }],
1174
+ react: [
1175
+ { dep: "react", major: 19 },
1176
+ { dep: "react-dom", major: 19 }
1177
+ ]
1178
+ };
1179
+ var REQUIRED_CORE_EXPORTS = [
1180
+ ".",
1181
+ "./tailwind",
1182
+ "./tailwind/modern",
1183
+ "./tokens.css",
1184
+ "./figma-variables.json"
1185
+ ];
1138
1186
  var VERSION_COMPATIBILITY_MATRIX = [
1139
- { name: "Node.js", range: ">=20.11.0", reason: "Matches workspace engines and CLI templates" },
1140
- { name: "pnpm", range: ">=8.0.0", reason: "Required by workspace package management" },
1187
+ {
1188
+ name: "Node.js",
1189
+ range: `>=${MIN_NODE_RANGE}`,
1190
+ reason: "Matches workspace engines and CLI templates"
1191
+ },
1192
+ {
1193
+ name: "pnpm",
1194
+ range: `>=${MIN_PNPM_RANGE}`,
1195
+ reason: "Required by workspace package management"
1196
+ },
1141
1197
  { name: "Tailwind CSS", range: ">=4.0.0", reason: "Required by Tigercat theme utilities" },
1142
1198
  { name: "Vue", range: "^3.0.0", reason: "Peer range for @expcat/tigercat-vue" },
1143
1199
  { name: "React", range: "^19.0.0", reason: "Peer range for @expcat/tigercat-react" }
@@ -1160,6 +1216,7 @@ function createDoctorCommand() {
1160
1216
  function collectDoctorChecks(options = {}) {
1161
1217
  const cwd = options.cwd ?? process.cwd();
1162
1218
  const env = options.env ?? process.env;
1219
+ const readCorePackageJson = options.readCorePackageJson ?? defaultReadCorePackageJson;
1163
1220
  const packageResult = readProjectPackage(cwd);
1164
1221
  const nodeVersion = options.nodeVersion ?? process.versions.node;
1165
1222
  const checks = [createPackageCheck(packageResult)];
@@ -1172,6 +1229,14 @@ function collectDoctorChecks(options = {}) {
1172
1229
  checks.push(createPeerDepsCheck(packageResult.packageJson));
1173
1230
  checks.push(createTemplateCompatibilityCheck(packageResult.packageJson));
1174
1231
  checks.push(createCompatibilityMatrixCheck(packageResult.packageJson));
1232
+ const coreExportsCheck = createCoreExportsCheck(
1233
+ packageResult.packageJson,
1234
+ cwd,
1235
+ readCorePackageJson
1236
+ );
1237
+ if (coreExportsCheck) {
1238
+ checks.push(coreExportsCheck);
1239
+ }
1175
1240
  return checks;
1176
1241
  }
1177
1242
  function runDoctor(json = false) {
@@ -1206,7 +1271,7 @@ function runDoctor(json = false) {
1206
1271
  process.exit(1);
1207
1272
  }
1208
1273
  if (warnings.length > 0) {
1209
- logWarn2(`${warnings.length} warning${warnings.length === 1 ? "" : "s"} found`);
1274
+ logWarn(`${warnings.length} warning${warnings.length === 1 ? "" : "s"} found`);
1210
1275
  return;
1211
1276
  }
1212
1277
  logSuccess("All checks passed");
@@ -1240,18 +1305,18 @@ function createPackageCheck(result) {
1240
1305
  }
1241
1306
  function createNodeCheck(version) {
1242
1307
  const parsed = parseVersion(version);
1243
- if (!parsed || parsed.major < MIN_NODE_MAJOR) {
1308
+ if (!parsed || isVersionLessThan(parsed, MIN_NODE_VERSION)) {
1244
1309
  return {
1245
1310
  name: "Node.js",
1246
1311
  status: "fail",
1247
- message: `Node ${MIN_NODE_MAJOR}+ is required, current version is ${version}`,
1248
- suggestions: [`Install Node ${MIN_NODE_MAJOR}+ and rerun tigercat doctor`]
1312
+ message: `Node ${MIN_NODE_RANGE}+ is required, current version is ${version}`,
1313
+ suggestions: [`Install Node ${MIN_NODE_RANGE}+ and rerun tigercat doctor`]
1249
1314
  };
1250
1315
  }
1251
1316
  return {
1252
1317
  name: "Node.js",
1253
1318
  status: "pass",
1254
- message: `Node ${version} satisfies >=${MIN_NODE_MAJOR}`
1319
+ message: `Node ${version} satisfies >=${MIN_NODE_RANGE}`
1255
1320
  };
1256
1321
  }
1257
1322
  function createPnpmCheck(packageJson, env) {
@@ -1260,23 +1325,23 @@ function createPnpmCheck(packageJson, env) {
1260
1325
  return {
1261
1326
  name: "pnpm",
1262
1327
  status: "warn",
1263
- message: `Could not detect pnpm version; Tigercat templates expect pnpm ${MIN_PNPM_MAJOR}+`,
1264
- suggestions: ["Add packageManager: pnpm@10.26.2 to package.json or run through pnpm"]
1328
+ message: `Could not detect pnpm version; Tigercat templates expect pnpm ${MIN_PNPM_RANGE}+`,
1329
+ suggestions: ["Add packageManager: pnpm@11.9.0 to package.json or run through pnpm"]
1265
1330
  };
1266
1331
  }
1267
1332
  const parsed = parseVersion(version);
1268
- if (!parsed || parsed.major < MIN_PNPM_MAJOR) {
1333
+ if (!parsed || isVersionLessThan(parsed, MIN_PNPM_VERSION)) {
1269
1334
  return {
1270
1335
  name: "pnpm",
1271
1336
  status: "fail",
1272
- message: `pnpm ${MIN_PNPM_MAJOR}+ is required, detected ${version}`,
1273
- suggestions: [`Upgrade pnpm to ${MIN_PNPM_MAJOR}+`]
1337
+ message: `pnpm ${MIN_PNPM_RANGE}+ is required, detected ${version}`,
1338
+ suggestions: [`Upgrade pnpm to ${MIN_PNPM_RANGE}+`]
1274
1339
  };
1275
1340
  }
1276
1341
  return {
1277
1342
  name: "pnpm",
1278
1343
  status: "pass",
1279
- message: `pnpm ${version} satisfies >=${MIN_PNPM_MAJOR}`
1344
+ message: `pnpm ${version} satisfies >=${MIN_PNPM_RANGE}`
1280
1345
  };
1281
1346
  }
1282
1347
  function createTailwindCheck(packageJson) {
@@ -1424,13 +1489,71 @@ function createCompatibilityMatrixCheck(packageJson) {
1424
1489
  suggestions: ["Install a Tigercat Vue or React package to validate framework peer ranges"]
1425
1490
  };
1426
1491
  }
1492
+ const incompatible = frameworks.flatMap(
1493
+ (framework) => FRAMEWORK_PEER_RANGES[framework].filter(({ dep, major }) => isOlderMajor(dependencies[dep], major)).map(({ dep, major }) => `${dep}@${dependencies[dep]} is below the supported major ${major}`)
1494
+ );
1495
+ if (incompatible.length > 0) {
1496
+ return {
1497
+ name: "Version compatibility matrix",
1498
+ status: "fail",
1499
+ message: "Installed framework versions are outside the supported range",
1500
+ details: [...incompatible, ...details],
1501
+ suggestions: ["Upgrade the listed framework packages to the supported major versions"]
1502
+ };
1503
+ }
1427
1504
  return {
1428
1505
  name: "Version compatibility matrix",
1429
1506
  status: "pass",
1430
- message: `${frameworks.map(formatFramework).join(" + ")} compatibility matrix is available`,
1507
+ message: `${frameworks.map(formatFramework).join(" + ")} versions satisfy the compatibility matrix`,
1431
1508
  details
1432
1509
  };
1433
1510
  }
1511
+ function createCoreExportsCheck(packageJson, cwd, readCorePackageJson) {
1512
+ const dependencies = collectDependencies2(packageJson);
1513
+ if (!dependencies["@expcat/tigercat-core"]) {
1514
+ return null;
1515
+ }
1516
+ const corePackageJson = readCorePackageJson(cwd);
1517
+ if (!corePackageJson) {
1518
+ return null;
1519
+ }
1520
+ const exportsMap = corePackageJson.exports ?? {};
1521
+ const missing = REQUIRED_CORE_EXPORTS.filter((subpath) => !(subpath in exportsMap));
1522
+ if (missing.length > 0) {
1523
+ return {
1524
+ name: "Core exports",
1525
+ status: "fail",
1526
+ message: "@expcat/tigercat-core is missing required export subpaths",
1527
+ details: missing.map((subpath) => `Missing export: ${subpath}`),
1528
+ suggestions: ["Upgrade @expcat/tigercat-core or reinstall dependencies"]
1529
+ };
1530
+ }
1531
+ return {
1532
+ name: "Core exports",
1533
+ status: "pass",
1534
+ message: "@expcat/tigercat-core exposes the required Tailwind, token and entry exports"
1535
+ };
1536
+ }
1537
+ function defaultReadCorePackageJson(cwd) {
1538
+ try {
1539
+ const requireFromProject = createRequire(pathToFileURL(join(cwd, "package.json")));
1540
+ const mainEntry = requireFromProject.resolve("@expcat/tigercat-core");
1541
+ let dir = dirname(mainEntry);
1542
+ for (let depth = 0; depth < 6; depth++) {
1543
+ const content = readFileSafe(join(dir, "package.json"));
1544
+ if (content) {
1545
+ const parsed = JSON.parse(content);
1546
+ if (parsed.name === "@expcat/tigercat-core") return parsed;
1547
+ }
1548
+ const parent = dirname(dir);
1549
+ if (parent === dir) break;
1550
+ dir = parent;
1551
+ }
1552
+ return null;
1553
+ } catch {
1554
+ return null;
1555
+ }
1556
+ }
1434
1557
  function collectDependencies2(packageJson) {
1435
1558
  return {
1436
1559
  ...packageJson.peerDependencies,
@@ -1467,6 +1590,11 @@ function parseVersion(value) {
1467
1590
  patch: Number(match[3] ?? 0)
1468
1591
  };
1469
1592
  }
1593
+ function isVersionLessThan(current, minimum) {
1594
+ if (current.major !== minimum.major) return current.major < minimum.major;
1595
+ if (current.minor !== minimum.minor) return current.minor < minimum.minor;
1596
+ return current.patch < minimum.patch;
1597
+ }
1470
1598
  function getRangeMajor(range) {
1471
1599
  if (!range) return null;
1472
1600
  if (/^(workspace|file|link|catalog):/.test(range)) return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expcat/tigercat-cli",
3
- "version": "1.3.4",
3
+ "version": "1.5.0",
4
4
  "type": "module",
5
5
  "description": "CLI tooling for Tigercat UI library — project scaffolding, component generation, and more",
6
6
  "license": "MIT",
@@ -28,14 +28,16 @@
28
28
  "module": "./dist/index.js",
29
29
  "types": "./dist/index.d.ts",
30
30
  "files": [
31
- "dist",
32
- "templates"
31
+ "dist"
33
32
  ],
34
33
  "publishConfig": {
35
34
  "access": "public"
36
35
  },
36
+ "engines": {
37
+ "node": ">=22.12.0"
38
+ },
37
39
  "dependencies": {
38
- "commander": "^13.1.0",
40
+ "commander": "^15.0.0",
39
41
  "picocolors": "^1.1.1",
40
42
  "prompts": "^2.4.2"
41
43
  },