@expcat/tigercat-cli 1.0.7 → 1.1.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 (3) hide show
  1. package/README.md +33 -0
  2. package/dist/index.js +432 -77
  3. package/package.json +8 -8
package/README.md CHANGED
@@ -48,6 +48,39 @@ tigercat generate docs
48
48
  tigercat generate docs --output ./docs/api
49
49
  ```
50
50
 
51
+ ### `tigercat doctor`
52
+
53
+ Check whether the current project has compatible Node, pnpm, Tailwind CSS, Tigercat peer dependencies, and template tooling.
54
+
55
+ ```bash
56
+ tigercat doctor
57
+ ```
58
+
59
+ ## Windows Support
60
+
61
+ The CLI is fully cross-platform. All template file paths use forward slashes and are
62
+ resolved via Node.js `path.resolve()` at write time, so they work correctly on Windows
63
+ with backslash paths, paths containing spaces, and UNC paths.
64
+
65
+ ### Package Manager `.cmd` Shims
66
+
67
+ When installed globally or locally, each package manager creates platform-specific shims
68
+ so that `tigercat` can be invoked directly from PowerShell, CMD, or Git Bash:
69
+
70
+ | Package manager | Global install | Shim files created |
71
+ | --------------- | ------------------------------------- | -------------------------------- |
72
+ | **pnpm** | `pnpm add -g @expcat/tigercat-cli` | `tigercat.cmd`, `tigercat` (sh) |
73
+ | **npm** | `npm i -g @expcat/tigercat-cli` | `tigercat.cmd`, `tigercat` (sh), `tigercat.ps1` |
74
+ | **bun** | `bun add -g @expcat/tigercat-cli` | `tigercat.cmd`, `tigercat` (sh) |
75
+
76
+ For local (non-global) installs, run via `npx tigercat`, `pnpm exec tigercat`, or
77
+ `bunx tigercat`. The `#!/usr/bin/env node` shebang in the built output is used by all
78
+ three package managers to locate the Node.js runtime.
79
+
80
+ > **Note:** If you use Corepack with pnpm on Windows, ensure `shell: true` is passed
81
+ > when spawning pnpm programmatically (the project scripts already handle this via
82
+ > `scripts/utils/pnpm.mjs`).
83
+
51
84
  ## License
52
85
 
53
86
  MIT
package/dist/index.js CHANGED
@@ -10,6 +10,28 @@ import { execSync } from 'child_process';
10
10
  var CLI_NAME = "tigercat";
11
11
  var CLI_VERSION = "0.9.0";
12
12
  var TEMPLATES = ["vue3", "react"];
13
+ var TEMPLATE_VERSIONS = {
14
+ // Tigercat packages (use caret on latest major)
15
+ tigercat: "^1.0.0",
16
+ // Frameworks
17
+ vue: "^3.5.33",
18
+ react: "^19.2.5",
19
+ reactDom: "^19.2.5",
20
+ // Build toolchain
21
+ typescript: "^6.0.3",
22
+ vite: "^8.0.10",
23
+ tailwindcss: "^4.2.4",
24
+ tailwindcssVite: "^4.2.4",
25
+ // Vite plugins
26
+ vitejsPluginVue: "^6.0.6",
27
+ vitejsPluginReact: "^6.0.1",
28
+ // Type definitions
29
+ typesReact: "^19.2.14",
30
+ typesReactDom: "^19.2.3",
31
+ // Vue-specific
32
+ vueTsconfig: "^0.9.1",
33
+ vueTsc: "^3.2.7"
34
+ };
13
35
  var COMPONENT_CATEGORIES = {
14
36
  basic: [
15
37
  "Alert",
@@ -123,17 +145,18 @@ function vue3PackageJson(name) {
123
145
  preview: "vite preview"
124
146
  },
125
147
  dependencies: {
126
- "@expcat/tigercat-vue": "^0.9.0",
127
- vue: "^3.5.26"
148
+ "@expcat/tigercat-vue": TEMPLATE_VERSIONS.tigercat,
149
+ vue: TEMPLATE_VERSIONS.vue
128
150
  },
129
151
  devDependencies: {
130
- "@tailwindcss/vite": "^4.1.18",
131
- "@vitejs/plugin-vue": "^6.0.3",
132
- "@vue/tsconfig": "^0.7.0",
133
- tailwindcss: "^4.1.18",
134
- typescript: "^5.9.3",
135
- vite: "^7.3.0",
136
- "vue-tsc": "^2.2.0"
152
+ "@expcat/tigercat-core": TEMPLATE_VERSIONS.tigercat,
153
+ "@tailwindcss/vite": TEMPLATE_VERSIONS.tailwindcssVite,
154
+ "@vitejs/plugin-vue": TEMPLATE_VERSIONS.vitejsPluginVue,
155
+ "@vue/tsconfig": TEMPLATE_VERSIONS.vueTsconfig,
156
+ tailwindcss: TEMPLATE_VERSIONS.tailwindcss,
157
+ typescript: TEMPLATE_VERSIONS.typescript,
158
+ vite: TEMPLATE_VERSIONS.vite,
159
+ "vue-tsc": TEMPLATE_VERSIONS.vueTsc
137
160
  }
138
161
  },
139
162
  null,
@@ -145,9 +168,9 @@ function vue3Tsconfig() {
145
168
  {
146
169
  extends: "@vue/tsconfig/tsconfig.dom.json",
147
170
  compilerOptions: {
148
- target: "ES2020",
171
+ target: "ES2022",
149
172
  module: "ESNext",
150
- lib: ["ES2020", "DOM", "DOM.Iterable"],
173
+ lib: ["ES2022", "DOM", "DOM.Iterable"],
151
174
  skipLibCheck: true,
152
175
  moduleResolution: "bundler",
153
176
  resolveJsonModule: true,
@@ -204,18 +227,58 @@ createApp(App).mount('#app')
204
227
  }
205
228
  function vue3App() {
206
229
  return `<script setup lang="ts">
207
- import { Button, Alert } from '@expcat/tigercat-vue'
230
+ import { ref } from 'vue'
231
+ import { Button, Alert, Switch } from '@expcat/tigercat-vue'
232
+
233
+ const dark = ref(false)
234
+ const modern = ref(true)
235
+
236
+ function syncRoot() {
237
+ const root = document.documentElement
238
+ root.classList.toggle('dark', dark.value)
239
+ if (modern.value) {
240
+ root.setAttribute('data-tiger-style', 'modern')
241
+ } else {
242
+ root.removeAttribute('data-tiger-style')
243
+ }
244
+ }
245
+
246
+ syncRoot()
247
+
248
+ function toggleDark(v: boolean) {
249
+ dark.value = v
250
+ syncRoot()
251
+ }
252
+
253
+ function toggleModern(v: boolean) {
254
+ modern.value = v
255
+ syncRoot()
256
+ }
208
257
  </script>
209
258
 
210
259
  <template>
211
260
  <div class="min-h-screen bg-[var(--tiger-surface,#ffffff)] p-8">
212
- <h1 class="text-2xl font-bold text-[var(--tiger-text,#111827)] mb-6">
213
- Tigercat + Vue 3
214
- </h1>
261
+ <div class="flex items-center justify-between mb-6">
262
+ <h1 class="text-2xl font-bold text-[var(--tiger-text,#111827)]">
263
+ Tigercat + Vue 3
264
+ </h1>
265
+ <div class="flex items-center gap-4 text-sm text-[var(--tiger-text-muted,#6b7280)]">
266
+ <label class="flex items-center gap-2">
267
+ <span>Modern</span>
268
+ <Switch :checked="modern" size="sm" @update:checked="toggleModern" />
269
+ </label>
270
+ <label class="flex items-center gap-2">
271
+ <span>Dark</span>
272
+ <Switch :checked="dark" size="sm" @update:checked="toggleDark" />
273
+ </label>
274
+ </div>
275
+ </div>
215
276
 
216
277
  <div class="space-y-4">
217
278
  <Alert variant="info">
218
279
  Welcome to your Tigercat project! Edit src/App.vue to get started.
280
+ Toggle <code>Modern</code> to preview the opt-in modern visual style
281
+ (radius / shadow / motion tokens).
219
282
  </Alert>
220
283
 
221
284
  <div class="flex gap-2">
@@ -240,31 +303,19 @@ declare module '*.vue' {
240
303
  }
241
304
  function commonStyleCss() {
242
305
  return `@import "tailwindcss";
306
+ @plugin "@expcat/tigercat-core/tailwind/modern";
243
307
 
244
- :root {
245
- --tiger-primary: #2563eb;
246
- --tiger-primary-hover: #1d4ed8;
247
- --tiger-surface: #ffffff;
248
- --tiger-surface-muted: #f9fafb;
249
- --tiger-text: #111827;
250
- --tiger-text-muted: #6b7280;
251
- --tiger-border: #e5e7eb;
252
- }
253
-
254
- @media (prefers-color-scheme: dark) {
255
- :root {
256
- --tiger-primary: #3b82f6;
257
- --tiger-primary-hover: #2563eb;
258
- --tiger-surface: #111827;
259
- --tiger-surface-muted: #1f2937;
260
- --tiger-text: #f9fafb;
261
- --tiger-text-muted: #9ca3af;
262
- --tiger-border: #374151;
263
- }
308
+ /*
309
+ * The tigercat tailwind plugin injects every --tiger-* design token for
310
+ * both light (:root) and dark (.dark) modes, plus the opt-in modern
311
+ * overrides activated by data-tiger-style="modern". The demo App toggles
312
+ * dark mode via .dark on <html> and prefers-color-scheme via the rule
313
+ * below. Swap the @plugin line for a tailwind.config.ts calling
314
+ * createTigercatPlugin({ preset }) to use a custom preset.
315
+ */
264
316
 
265
- html {
266
- color-scheme: dark;
267
- }
317
+ html {
318
+ color-scheme: light dark;
268
319
  }
269
320
  `;
270
321
  }
@@ -295,18 +346,19 @@ function reactPackageJson(name) {
295
346
  preview: "vite preview"
296
347
  },
297
348
  dependencies: {
298
- "@expcat/tigercat-react": "^0.9.0",
299
- react: "^19.2.3",
300
- "react-dom": "^19.2.3"
349
+ "@expcat/tigercat-react": TEMPLATE_VERSIONS.tigercat,
350
+ react: TEMPLATE_VERSIONS.react,
351
+ "react-dom": TEMPLATE_VERSIONS.reactDom
301
352
  },
302
353
  devDependencies: {
303
- "@tailwindcss/vite": "^4.1.18",
304
- "@types/react": "^19.2.7",
305
- "@types/react-dom": "^19.2.2",
306
- "@vitejs/plugin-react": "^4.3.4",
307
- tailwindcss: "^4.1.18",
308
- typescript: "^5.9.3",
309
- vite: "^7.3.0"
354
+ "@expcat/tigercat-core": TEMPLATE_VERSIONS.tigercat,
355
+ "@tailwindcss/vite": TEMPLATE_VERSIONS.tailwindcssVite,
356
+ "@types/react": TEMPLATE_VERSIONS.typesReact,
357
+ "@types/react-dom": TEMPLATE_VERSIONS.typesReactDom,
358
+ "@vitejs/plugin-react": TEMPLATE_VERSIONS.vitejsPluginReact,
359
+ tailwindcss: TEMPLATE_VERSIONS.tailwindcss,
360
+ typescript: TEMPLATE_VERSIONS.typescript,
361
+ vite: TEMPLATE_VERSIONS.vite
310
362
  }
311
363
  },
312
364
  null,
@@ -317,9 +369,9 @@ function reactTsconfig() {
317
369
  return JSON.stringify(
318
370
  {
319
371
  compilerOptions: {
320
- target: "ES2020",
372
+ target: "ES2022",
321
373
  useDefineForClassFields: true,
322
- lib: ["ES2020", "DOM", "DOM.Iterable"],
374
+ lib: ["ES2022", "DOM", "DOM.Iterable"],
323
375
  module: "ESNext",
324
376
  skipLibCheck: true,
325
377
  moduleResolution: "bundler",
@@ -400,18 +452,49 @@ createRoot(document.getElementById('root')!).render(
400
452
  `;
401
453
  }
402
454
  function reactApp() {
403
- return `import { Button, Alert } from '@expcat/tigercat-react'
455
+ return `import { useState, useCallback, useEffect } from 'react'
456
+ import { Button, Alert, Switch } from '@expcat/tigercat-react'
404
457
 
405
458
  export default function App() {
459
+ const [dark, setDark] = useState(false)
460
+ const [modern, setModern] = useState(true)
461
+
462
+ useEffect(() => {
463
+ const root = document.documentElement
464
+ root.classList.toggle('dark', dark)
465
+ if (modern) {
466
+ root.setAttribute('data-tiger-style', 'modern')
467
+ } else {
468
+ root.removeAttribute('data-tiger-style')
469
+ }
470
+ }, [dark, modern])
471
+
472
+ const onDark = useCallback((v: boolean) => setDark(v), [])
473
+ const onModern = useCallback((v: boolean) => setModern(v), [])
474
+
406
475
  return (
407
476
  <div className="min-h-screen bg-[var(--tiger-surface,#ffffff)] p-8">
408
- <h1 className="text-2xl font-bold text-[var(--tiger-text,#111827)] mb-6">
409
- Tigercat + React
410
- </h1>
477
+ <div className="flex items-center justify-between mb-6">
478
+ <h1 className="text-2xl font-bold text-[var(--tiger-text,#111827)]">
479
+ Tigercat + React
480
+ </h1>
481
+ <div className="flex items-center gap-4 text-sm text-[var(--tiger-text-muted,#6b7280)]">
482
+ <label className="flex items-center gap-2">
483
+ <span>Modern</span>
484
+ <Switch checked={modern} size="sm" onChange={onModern} />
485
+ </label>
486
+ <label className="flex items-center gap-2">
487
+ <span>Dark</span>
488
+ <Switch checked={dark} size="sm" onChange={onDark} />
489
+ </label>
490
+ </div>
491
+ </div>
411
492
 
412
493
  <div className="space-y-4">
413
494
  <Alert variant="info">
414
495
  Welcome to your Tigercat project! Edit src/App.tsx to get started.
496
+ Toggle <code>Modern</code> to preview the opt-in modern visual style
497
+ (radius / shadow / motion tokens).
415
498
  </Alert>
416
499
 
417
500
  <div className="flex gap-2">
@@ -427,31 +510,19 @@ export default function App() {
427
510
  }
428
511
  function commonStyleCss2() {
429
512
  return `@import "tailwindcss";
513
+ @plugin "@expcat/tigercat-core/tailwind/modern";
430
514
 
431
- :root {
432
- --tiger-primary: #2563eb;
433
- --tiger-primary-hover: #1d4ed8;
434
- --tiger-surface: #ffffff;
435
- --tiger-surface-muted: #f9fafb;
436
- --tiger-text: #111827;
437
- --tiger-text-muted: #6b7280;
438
- --tiger-border: #e5e7eb;
439
- }
440
-
441
- @media (prefers-color-scheme: dark) {
442
- :root {
443
- --tiger-primary: #3b82f6;
444
- --tiger-primary-hover: #2563eb;
445
- --tiger-surface: #111827;
446
- --tiger-surface-muted: #1f2937;
447
- --tiger-text: #f9fafb;
448
- --tiger-text-muted: #9ca3af;
449
- --tiger-border: #374151;
450
- }
515
+ /*
516
+ * The tigercat tailwind plugin injects every --tiger-* design token for
517
+ * both light (:root) and dark (.dark) modes, plus the opt-in modern
518
+ * overrides activated by data-tiger-style="modern". The demo App toggles
519
+ * dark mode via .dark on <html> and prefers-color-scheme via the rule
520
+ * below. Swap the @plugin line for a tailwind.config.ts calling
521
+ * createTigercatPlugin({ preset }) to use a custom preset.
522
+ */
451
523
 
452
- html {
453
- color-scheme: dark;
454
- }
524
+ html {
525
+ color-scheme: light dark;
455
526
  }
456
527
  `;
457
528
  }
@@ -779,6 +850,289 @@ async function runGenerateDocs(inputDir, outputDir) {
779
850
  writeFileSafe(join(resolvedOutput, "index.md"), indexLines.join("\n"));
780
851
  logSuccess(`Generated docs for ${docs.length} components in ${outputDir}`);
781
852
  }
853
+ var MIN_NODE_MAJOR = 20;
854
+ var MIN_PNPM_MAJOR = 8;
855
+ var REQUIRED_TAILWIND_MAJOR = 4;
856
+ var REQUIRED_TIGERCAT_MAJOR = 1;
857
+ var FRAMEWORK_REQUIREMENTS = {
858
+ vue3: {
859
+ peers: ["@expcat/tigercat-vue", "@expcat/tigercat-core", "vue"],
860
+ templateDeps: ["@tailwindcss/vite", "@vitejs/plugin-vue", "typescript", "vite", "vue-tsc"]
861
+ },
862
+ react: {
863
+ peers: ["@expcat/tigercat-react", "@expcat/tigercat-core", "react", "react-dom"],
864
+ templateDeps: ["@tailwindcss/vite", "@vitejs/plugin-react", "typescript", "vite"]
865
+ }
866
+ };
867
+ function createDoctorCommand() {
868
+ return new Command("doctor").description("Check whether the current project is compatible with Tigercat").action(() => {
869
+ runDoctor();
870
+ });
871
+ }
872
+ function collectDoctorChecks(options = {}) {
873
+ const cwd = options.cwd ?? process.cwd();
874
+ const env = options.env ?? process.env;
875
+ const packageResult = readProjectPackage(cwd);
876
+ const nodeVersion = options.nodeVersion ?? process.versions.node;
877
+ const checks = [createPackageCheck(packageResult)];
878
+ checks.push(createNodeCheck(nodeVersion));
879
+ checks.push(createPnpmCheck(packageResult.packageJson, env));
880
+ if (!packageResult.packageJson) {
881
+ return checks;
882
+ }
883
+ checks.push(createTailwindCheck(packageResult.packageJson));
884
+ checks.push(createPeerDepsCheck(packageResult.packageJson));
885
+ checks.push(createTemplateCompatibilityCheck(packageResult.packageJson));
886
+ return checks;
887
+ }
888
+ function runDoctor() {
889
+ const checks = collectDoctorChecks();
890
+ logInfo("Running Tigercat project checks...");
891
+ console.log();
892
+ for (const check of checks) {
893
+ printCheck(check);
894
+ }
895
+ console.log();
896
+ const failures = checks.filter((check) => check.status === "fail");
897
+ const warnings = checks.filter((check) => check.status === "warn");
898
+ if (failures.length > 0) {
899
+ logError(`${failures.length} check${failures.length === 1 ? "" : "s"} failed`);
900
+ process.exit(1);
901
+ }
902
+ if (warnings.length > 0) {
903
+ logWarn(`${warnings.length} warning${warnings.length === 1 ? "" : "s"} found`);
904
+ return;
905
+ }
906
+ logSuccess("All checks passed");
907
+ }
908
+ function readProjectPackage(cwd) {
909
+ const packagePath = join(cwd, "package.json");
910
+ const content = readFileSafe(packagePath);
911
+ if (!content) {
912
+ return { packageJson: null, error: `package.json not found in ${cwd}` };
913
+ }
914
+ try {
915
+ return { packageJson: JSON.parse(content) };
916
+ } catch {
917
+ return { packageJson: null, error: "package.json is not valid JSON" };
918
+ }
919
+ }
920
+ function createPackageCheck(result) {
921
+ if (!result.packageJson) {
922
+ return {
923
+ name: "Project package",
924
+ status: "fail",
925
+ message: result.error ?? "package.json could not be read"
926
+ };
927
+ }
928
+ return {
929
+ name: "Project package",
930
+ status: "pass",
931
+ message: "package.json is readable"
932
+ };
933
+ }
934
+ function createNodeCheck(version) {
935
+ const parsed = parseVersion(version);
936
+ if (!parsed || parsed.major < MIN_NODE_MAJOR) {
937
+ return {
938
+ name: "Node.js",
939
+ status: "fail",
940
+ message: `Node ${MIN_NODE_MAJOR}+ is required, current version is ${version}`
941
+ };
942
+ }
943
+ return {
944
+ name: "Node.js",
945
+ status: "pass",
946
+ message: `Node ${version} satisfies >=${MIN_NODE_MAJOR}`
947
+ };
948
+ }
949
+ function createPnpmCheck(packageJson, env) {
950
+ const version = getPnpmVersion(packageJson, env);
951
+ if (!version) {
952
+ return {
953
+ name: "pnpm",
954
+ status: "warn",
955
+ message: `Could not detect pnpm version; Tigercat templates expect pnpm ${MIN_PNPM_MAJOR}+`
956
+ };
957
+ }
958
+ const parsed = parseVersion(version);
959
+ if (!parsed || parsed.major < MIN_PNPM_MAJOR) {
960
+ return {
961
+ name: "pnpm",
962
+ status: "fail",
963
+ message: `pnpm ${MIN_PNPM_MAJOR}+ is required, detected ${version}`
964
+ };
965
+ }
966
+ return {
967
+ name: "pnpm",
968
+ status: "pass",
969
+ message: `pnpm ${version} satisfies >=${MIN_PNPM_MAJOR}`
970
+ };
971
+ }
972
+ function createTailwindCheck(packageJson) {
973
+ const allDeps = collectDependencies(packageJson);
974
+ const tailwindRange = allDeps.tailwindcss;
975
+ const vitePluginRange = allDeps["@tailwindcss/vite"];
976
+ if (!tailwindRange) {
977
+ return {
978
+ name: "Tailwind CSS",
979
+ status: "fail",
980
+ message: "tailwindcss is missing; Tigercat requires Tailwind CSS 4+"
981
+ };
982
+ }
983
+ const tailwindMajor = getRangeMajor(tailwindRange);
984
+ const pluginMajor = vitePluginRange ? getRangeMajor(vitePluginRange) : null;
985
+ if (tailwindMajor !== null && tailwindMajor < REQUIRED_TAILWIND_MAJOR) {
986
+ return {
987
+ name: "Tailwind CSS",
988
+ status: "fail",
989
+ message: `tailwindcss ${tailwindRange} is not compatible; use Tailwind CSS ${REQUIRED_TAILWIND_MAJOR}+`
990
+ };
991
+ }
992
+ if (tailwindMajor === null) {
993
+ return {
994
+ name: "Tailwind CSS",
995
+ status: "warn",
996
+ message: `Could not verify tailwindcss range ${tailwindRange}; expected ${REQUIRED_TAILWIND_MAJOR}+`
997
+ };
998
+ }
999
+ if (vitePluginRange && pluginMajor !== null && pluginMajor < REQUIRED_TAILWIND_MAJOR) {
1000
+ return {
1001
+ name: "Tailwind CSS",
1002
+ status: "fail",
1003
+ message: `@tailwindcss/vite ${vitePluginRange} is not compatible; use ${REQUIRED_TAILWIND_MAJOR}+`
1004
+ };
1005
+ }
1006
+ const details = vitePluginRange ? [`@tailwindcss/vite ${vitePluginRange}`] : ["@tailwindcss/vite is recommended for Vite templates"];
1007
+ return {
1008
+ name: "Tailwind CSS",
1009
+ status: vitePluginRange ? "pass" : "warn",
1010
+ message: `tailwindcss ${tailwindRange} satisfies Tigercat requirements`,
1011
+ details
1012
+ };
1013
+ }
1014
+ function createPeerDepsCheck(packageJson) {
1015
+ const allDeps = collectDependencies(packageJson);
1016
+ const frameworks = detectTigercatFrameworks(allDeps);
1017
+ if (frameworks.length === 0) {
1018
+ return {
1019
+ name: "Peer dependencies",
1020
+ status: "warn",
1021
+ message: "No Tigercat Vue or React package was detected"
1022
+ };
1023
+ }
1024
+ const missing = [
1025
+ ...new Set(
1026
+ frameworks.flatMap(
1027
+ (framework) => FRAMEWORK_REQUIREMENTS[framework].peers.filter((dependency) => !allDeps[dependency])
1028
+ )
1029
+ )
1030
+ ];
1031
+ const incompatible = frameworks.flatMap(
1032
+ (framework) => FRAMEWORK_REQUIREMENTS[framework].peers.filter((dependency) => dependency.startsWith("@expcat/tigercat-")).filter((dependency) => isOlderMajor(allDeps[dependency], REQUIRED_TIGERCAT_MAJOR)).map((dependency) => `${dependency}@${allDeps[dependency]}`)
1033
+ );
1034
+ if (missing.length > 0 || incompatible.length > 0) {
1035
+ return {
1036
+ name: "Peer dependencies",
1037
+ status: "fail",
1038
+ message: "Tigercat peer dependencies are incomplete or incompatible",
1039
+ details: [...missing.map((dependency) => `Missing ${dependency}`), ...incompatible]
1040
+ };
1041
+ }
1042
+ return {
1043
+ name: "Peer dependencies",
1044
+ status: "pass",
1045
+ message: `${frameworks.map(formatFramework).join(" + ")} peer dependencies are present`
1046
+ };
1047
+ }
1048
+ function createTemplateCompatibilityCheck(packageJson) {
1049
+ const allDeps = collectDependencies(packageJson);
1050
+ const frameworks = detectTigercatFrameworks(allDeps);
1051
+ if (frameworks.length === 0) {
1052
+ return {
1053
+ name: "Template compatibility",
1054
+ status: "warn",
1055
+ message: "Skipped because no supported Tigercat framework package was detected"
1056
+ };
1057
+ }
1058
+ const missing = [
1059
+ ...new Set(
1060
+ frameworks.flatMap(
1061
+ (framework) => FRAMEWORK_REQUIREMENTS[framework].templateDeps.filter((dependency) => !allDeps[dependency])
1062
+ )
1063
+ )
1064
+ ];
1065
+ if (missing.length > 0) {
1066
+ return {
1067
+ name: "Template compatibility",
1068
+ status: "warn",
1069
+ message: "Project differs from current CLI template dependencies",
1070
+ details: missing.map((dependency) => `Template dependency not found: ${dependency}`)
1071
+ };
1072
+ }
1073
+ return {
1074
+ name: "Template compatibility",
1075
+ status: "pass",
1076
+ message: `${frameworks.map(formatFramework).join(" + ")} template dependencies are present`
1077
+ };
1078
+ }
1079
+ function collectDependencies(packageJson) {
1080
+ return {
1081
+ ...packageJson.peerDependencies,
1082
+ ...packageJson.dependencies,
1083
+ ...packageJson.devDependencies
1084
+ };
1085
+ }
1086
+ function detectTigercatFrameworks(dependencies) {
1087
+ const frameworks = [];
1088
+ if (dependencies["@expcat/tigercat-vue"]) {
1089
+ frameworks.push("vue3");
1090
+ }
1091
+ if (dependencies["@expcat/tigercat-react"]) {
1092
+ frameworks.push("react");
1093
+ }
1094
+ return frameworks;
1095
+ }
1096
+ function getPnpmVersion(packageJson, env) {
1097
+ const packageManager = packageJson?.packageManager;
1098
+ if (typeof packageManager === "string") {
1099
+ const match2 = /^pnpm@(.+)$/.exec(packageManager);
1100
+ if (match2) return match2[1];
1101
+ }
1102
+ const userAgent = env.npm_config_user_agent;
1103
+ const match = userAgent ? /pnpm\/(\d+\.\d+\.\d+)/.exec(userAgent) : null;
1104
+ return match?.[1] ?? null;
1105
+ }
1106
+ function parseVersion(value) {
1107
+ const match = /^(?:v)?(\d+)(?:\.(\d+))?(?:\.(\d+))?/.exec(value.trim());
1108
+ if (!match) return null;
1109
+ return {
1110
+ major: Number(match[1]),
1111
+ minor: Number(match[2] ?? 0),
1112
+ patch: Number(match[3] ?? 0)
1113
+ };
1114
+ }
1115
+ function getRangeMajor(range) {
1116
+ if (!range) return null;
1117
+ if (/^(workspace|file|link|catalog):/.test(range)) return null;
1118
+ const match = /(?:\^|~|>=|<=|>|<|=)?\s*v?(\d+)/.exec(range);
1119
+ return match ? Number(match[1]) : null;
1120
+ }
1121
+ function isOlderMajor(range, expectedMajor) {
1122
+ const major = getRangeMajor(range);
1123
+ return major !== null && major < expectedMajor;
1124
+ }
1125
+ function formatFramework(framework) {
1126
+ return framework === "vue3" ? "Vue 3" : "React";
1127
+ }
1128
+ function printCheck(check) {
1129
+ const symbol = check.status === "pass" ? pc.green("\u2714") : check.status === "warn" ? pc.yellow("\u26A0") : pc.red("\u2716");
1130
+ const name = pc.bold(check.name);
1131
+ console.log(`${symbol} ${name}: ${check.message}`);
1132
+ for (const detail of check.details ?? []) {
1133
+ console.log(` ${pc.dim("-")} ${detail}`);
1134
+ }
1135
+ }
782
1136
 
783
1137
  // src/index.ts
784
1138
  var program = new Command();
@@ -787,4 +1141,5 @@ program.addCommand(createCreateCommand());
787
1141
  program.addCommand(createAddCommand());
788
1142
  program.addCommand(createPlaygroundCommand());
789
1143
  program.addCommand(createGenerateCommand());
1144
+ program.addCommand(createDoctorCommand());
790
1145
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expcat/tigercat-cli",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "CLI tooling for Tigercat UI library — project scaffolding, component generation, and more",
6
6
  "license": "MIT",
@@ -22,11 +22,11 @@
22
22
  "code-generator"
23
23
  ],
24
24
  "bin": {
25
- "tigercat": "./dist/index.mjs"
25
+ "tigercat": "./dist/index.js"
26
26
  },
27
- "main": "./dist/index.mjs",
28
- "module": "./dist/index.mjs",
29
- "types": "./dist/index.d.mts",
27
+ "main": "./dist/index.js",
28
+ "module": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
30
  "files": [
31
31
  "dist",
32
32
  "templates"
@@ -36,13 +36,13 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "commander": "^13.1.0",
39
- "prompts": "^2.4.2",
40
- "picocolors": "^1.1.1"
39
+ "picocolors": "^1.1.1",
40
+ "prompts": "^2.4.2"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/prompts": "^2.4.9",
44
44
  "tsup": "^8.5.1",
45
- "typescript": "^5.9.3"
45
+ "typescript": "^6.0.3"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "tsup --config tsup.config.ts",