@deneb-ui/cli 2.0.21 → 2.0.22

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/bin/index.js CHANGED
@@ -444,6 +444,31 @@ function getComponentRegistry(importPkg) {
444
444
  component: 'EditableProductCard',
445
445
  code: `'use client';\n\nimport { EditableProductCard, type EditableProductCardProps } from '${importPkg}';\n\nexport function ProductCard(props: EditableProductCardProps) {\n return <EditableProductCard {...props} />;\n}\n`,
446
446
  },
447
+ 'product-grid': {
448
+ file: 'ProductGrid.tsx',
449
+ component: 'EditableProductGrid',
450
+ code: `'use client';\n\nimport { EditableProductGrid, ProductGrid, type EditableProductGridProps, type ProductGridItem } from '${importPkg}';\n\nexport { EditableProductGrid, ProductGrid, type EditableProductGridProps, type ProductGridItem };\n`,
451
+ },
452
+ 'product-detail': {
453
+ file: 'ProductDetail.tsx',
454
+ component: 'EditableProductDetail',
455
+ code: `'use client';\n\nimport { EditableProductDetail, ProductDetail, type EditableProductDetailProps, type ProductDetailItem } from '${importPkg}';\n\nexport { EditableProductDetail, ProductDetail, type EditableProductDetailProps, type ProductDetailItem };\n`,
456
+ },
457
+ 'customer-reviews': {
458
+ file: 'CustomerReviews.tsx',
459
+ component: 'EditableCustomerReviews',
460
+ code: `'use client';\n\nimport { EditableCustomerReviews, CustomerReviews, type EditableCustomerReviewsProps, type CustomerReviewItem } from '${importPkg}';\n\nexport { EditableCustomerReviews, CustomerReviews, type EditableCustomerReviewsProps, type CustomerReviewItem };\n`,
461
+ },
462
+ 'cart-drawer': {
463
+ file: 'CartDrawer.tsx',
464
+ component: 'EditableCartDrawer',
465
+ code: `'use client';\n\nimport { EditableCartDrawer, CartDrawer, type EditableCartDrawerProps } from '${importPkg}';\n\nexport { EditableCartDrawer, CartDrawer, type EditableCartDrawerProps };\n`,
466
+ },
467
+ 'filter-sidebar': {
468
+ file: 'FilterSidebar.tsx',
469
+ component: 'EditableFilterSidebar',
470
+ code: `'use client';\n\nimport { EditableFilterSidebar, FilterSidebar, type EditableFilterSidebarProps, type FilterOptionGroup } from '${importPkg}';\n\nexport { EditableFilterSidebar, FilterSidebar, type EditableFilterSidebarProps, type FilterOptionGroup };\n`,
471
+ },
447
472
  'pricing-card': {
448
473
  file: 'PricingCard.tsx',
449
474
  component: 'EditablePricingCard',
@@ -572,7 +597,7 @@ function getComponentRegistry(importPkg) {
572
597
  };
573
598
  }
574
599
 
575
- function initProject(targetInput) {
600
+ function initProject(targetInput, options = {}) {
576
601
  const targetDir = path.resolve(process.cwd(), targetInput || '.');
577
602
  const pkgPath = path.join(targetDir, 'package.json');
578
603
 
@@ -621,7 +646,7 @@ function initProject(targetInput) {
621
646
  let conversionRes = null;
622
647
  try {
623
648
  const { runUniversalTemplateConversion } = require('../src/tools/template-converter.cjs');
624
- conversionRes = runUniversalTemplateConversion(targetDir, projectName, detectedPages);
649
+ conversionRes = runUniversalTemplateConversion(targetDir, projectName, detectedPages, options);
625
650
  } catch (err) {
626
651
  console.error(`\x1b[33mâš  Note:\x1b[0m Automated conversion encountered an issue: ${err.message}. Falling back to default generation.`);
627
652
  }
@@ -957,198 +982,9 @@ Options:
957
982
  ], 58) + '\n');
958
983
  }
959
984
 
960
- function runDoctor(targetDirInput) {
961
- const targetDir = path.resolve(targetDirInput || '.');
962
-
963
- console.log('\n' + createBox([
964
- '\x1b[1m\x1b[36m🩺 DENEB SYSTEM & TEMPLATE DOCTOR\x1b[0m',
965
- '\x1b[90mComprehensive diagnostic analysis for Fivora & Next.js\x1b[0m',
966
- `\x1b[37mTarget:\x1b[0m ${targetDir}`
967
- ], 60) + '\n');
968
-
969
- let passed = 0;
970
- let warnings = 0;
971
- let errors = 0;
972
-
973
- function report(type, title, detail) {
974
- if (type === 'pass') {
975
- passed++;
976
- console.log(` \x1b[32m✔\x1b[0m \x1b[1m${title}\x1b[0m${detail ? ` \x1b[90m(${detail})\x1b[0m` : ''}`);
977
- } else if (type === 'warn') {
978
- warnings++;
979
- console.log(` \x1b[33mâš \x1b[0m \x1b[33m${title}\x1b[0m${detail ? ` \x1b[90m- ${detail}\x1b[0m` : ''}`);
980
- } else {
981
- errors++;
982
- console.log(` \x1b[31m✖\x1b[0m \x1b[31m${title}\x1b[0m${detail ? ` \x1b[90m- ${detail}\x1b[0m` : ''}`);
983
- }
984
- }
985
-
986
- console.log('\x1b[1m[1/6] System & Runtime Environment:\x1b[0m');
987
- const nodeVersion = process.version;
988
- const majorNode = parseInt(nodeVersion.replace(/^v/, '').split('.')[0], 10);
989
- if (majorNode >= 18) {
990
- report('pass', 'Node.js Runtime', `${nodeVersion} (Supported)`);
991
- } else {
992
- report('err', 'Node.js Runtime', `${nodeVersion} (Requires Node.js >= 18.0.0)`);
993
- }
994
-
995
- const npmBin = process.platform === 'win32' ? 'npm.cmd' : 'npm';
996
- const npmCheck = spawnSync(npmBin, ['--version'], { encoding: 'utf-8', shell: process.platform === 'win32' });
997
- if (!npmCheck.error && npmCheck.status === 0) {
998
- report('pass', 'Package Manager', `npm v${npmCheck.stdout.trim()}`);
999
- } else {
1000
- report('warn', 'Package Manager', 'npm not found in system PATH');
1001
- }
1002
-
1003
- console.log('\n\x1b[1m[2/6] Project Package Configuration:\x1b[0m');
1004
- const pkgPath = path.join(targetDir, 'package.json');
1005
- let pkg = null;
1006
- if (fs.existsSync(pkgPath)) {
1007
- try {
1008
- pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
1009
- report('pass', 'package.json', `Found "${pkg.name || 'unnamed'}"`);
1010
- const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
1011
-
1012
- if (allDeps['next']) {
1013
- report('pass', 'Next.js Framework', allDeps['next']);
1014
- } else {
1015
- report('err', 'Next.js Framework', 'next dependency missing in package.json');
1016
- }
1017
-
1018
- if (allDeps['@deneb-ui/ui']) {
1019
- report('pass', '@deneb-ui/ui Library', allDeps['@deneb-ui/ui']);
1020
- } else {
1021
- report('warn', '@deneb-ui/ui Library', 'Not installed (run "npm i @deneb-ui/ui")');
1022
- }
1023
-
1024
- if (allDeps['@deneb-ui/cli']) {
1025
- report('pass', '@deneb-ui/cli Tooling', allDeps['@deneb-ui/cli']);
1026
- } else {
1027
- report('warn', '@deneb-ui/cli Tooling', 'Recommended for local CLI scripts');
1028
- }
1029
- } catch (e) {
1030
- report('err', 'package.json Syntax', e.message);
1031
- }
1032
- } else {
1033
- report('err', 'package.json', `Not found at ${pkgPath}`);
1034
- }
1035
-
1036
- console.log('\n\x1b[1m[3/6] Static Export Configuration:\x1b[0m');
1037
- const nextConfigTs = path.join(targetDir, 'next.config.ts');
1038
- const nextConfigMjs = path.join(targetDir, 'next.config.mjs');
1039
- const nextConfigJs = path.join(targetDir, 'next.config.js');
1040
- let nextConfigFile = [nextConfigTs, nextConfigMjs, nextConfigJs].find((p) => fs.existsSync(p));
1041
-
1042
- if (nextConfigFile) {
1043
- const content = fs.readFileSync(nextConfigFile, 'utf-8');
1044
- if (content.includes("output: 'export'") || content.includes('output: "export"')) {
1045
- report('pass', 'Next.js Static Export', `output: 'export' verified in ${path.basename(nextConfigFile)}`);
1046
- } else {
1047
- report('err', 'Next.js Static Export', `Missing output: 'export' in ${path.basename(nextConfigFile)} (Required by Fivora)`);
1048
- }
1049
- } else {
1050
- report('err', 'Next.js Config', 'No next.config.ts, next.config.mjs, or next.config.js found');
1051
- }
1052
-
1053
- console.log('\n\x1b[1m[4/6] Fivora Manifest v2 Contract:\x1b[0m');
1054
- const manifestPath = path.join(targetDir, 'fivora-template.json');
1055
- let manifestData = null;
1056
- if (fs.existsSync(manifestPath)) {
1057
- try {
1058
- manifestData = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
1059
- report('pass', 'fivora-template.json', `Valid JSON (strict=${manifestData.strict !== false})`);
1060
-
1061
- if (manifestData.version === 2 || manifestData.version === '2') {
1062
- report('pass', 'Manifest Version', 'Version 2 (Current standard)');
1063
- } else {
1064
- report('warn', 'Manifest Version', `Version ${manifestData.version} detected (Recommend version 2)`);
1065
- }
1066
-
1067
- const hasHome = Array.isArray(manifestData.pages) && manifestData.pages.some((p) =>
1068
- p.route === '/' || p.slug === '/' || p.path === '/' || p.id === 'home'
1069
- );
1070
- if (hasHome) {
1071
- report('pass', 'Home Page Entry', 'Home page ("/") declared in manifest');
1072
- } else {
1073
- report('err', 'Home Page Entry', 'Manifest pages array missing root slug or route: "/"');
1074
- }
1075
-
1076
- if (manifestData.theme && (manifestData.theme.primary || manifestData.theme.accent)) {
1077
- report('pass', 'Theme Configuration', 'Primary and accent color tokens declared');
1078
- } else {
1079
- // Will check site-data.json below as alternative
1080
- }
1081
- } catch (e) {
1082
- report('err', 'fivora-template.json Syntax', e.message);
1083
- }
1084
- } else {
1085
- report('err', 'fivora-template.json', 'File not found. Run "deneb init" to generate it');
1086
- }
1087
-
1088
- console.log('\n\x1b[1m[5/6] Reactive Site Data & Visual Editing:\x1b[0m');
1089
- const siteDataPath = path.join(targetDir, 'src', 'data', 'site-data.json');
1090
- if (fs.existsSync(siteDataPath)) {
1091
- try {
1092
- const siteData = JSON.parse(fs.readFileSync(siteDataPath, 'utf-8'));
1093
- report('pass', 'site-data.json', 'src/data/site-data.json exists & valid');
1094
- const merchantName = (siteData.merchant && (siteData.merchant.businessName || siteData.merchant.name)) || null;
1095
- if (merchantName) {
1096
- report('pass', 'Merchant Metadata', `Name: "${merchantName}"`);
1097
- } else {
1098
- report('warn', 'Merchant Metadata', 'Missing merchant name in site-data.json');
1099
- }
1100
-
1101
- const themeTokens = manifestData?.theme || siteData?.template?.structure?.theme;
1102
- if (themeTokens && (themeTokens.primaryColor || themeTokens.primary || themeTokens.accentColor || themeTokens.accent)) {
1103
- report('pass', 'Theme Design Tokens', 'Theme color tokens declared');
1104
- } else {
1105
- report('warn', 'Theme Design Tokens', 'No theme color tokens found in manifest or site-data.json');
1106
- }
1107
-
1108
- if (siteData.content) {
1109
- report('pass', 'Visual Content Bindings', 'Content section ready for live sync');
1110
- } else {
1111
- report('warn', 'Visual Content Bindings', 'Missing content section in site-data.json');
1112
- }
1113
- } catch (e) {
1114
- report('err', 'site-data.json Syntax', e.message);
1115
- }
1116
- } else {
1117
- report('warn', 'site-data.json', 'src/data/site-data.json not found. Recommended for Fivora live editor');
1118
- }
1119
-
1120
- console.log('\n\x1b[1m[6/6] Cleanliness & Security Check:\x1b[0m');
1121
- const envFiles = ['.env', '.env.local', '.env.production', '.env.development'];
1122
- const foundEnv = envFiles.filter((f) => fs.existsSync(path.join(targetDir, f)));
1123
- if (foundEnv.length === 0) {
1124
- report('pass', 'Secrets Isolation', 'No raw .env files detected in root directory');
1125
- } else {
1126
- report('warn', 'Secrets Isolation', `Active env files: ${foundEnv.join(', ')} (Excluded during packaging)`);
1127
- }
1128
-
1129
- const previewExists = fs.existsSync(path.join(targetDir, 'preview.png')) ||
1130
- fs.existsSync(path.join(targetDir, 'thumbnail.png')) ||
1131
- fs.existsSync(path.join(targetDir, 'public', 'fivora-logo.png'));
1132
- if (previewExists) {
1133
- report('pass', 'Storefront Assets', 'Brand/preview graphics verified');
1134
- } else {
1135
- report('warn', 'Storefront Assets', 'preview.png not found in template root');
1136
- }
1137
-
1138
- // Summary
1139
- console.log('\n' + createBox([
1140
- '\x1b[1mDOCTOR DIAGNOSTIC SUMMARY\x1b[0m',
1141
- `\x1b[32m✔ Passed:\x1b[0m ${passed}`,
1142
- `\x1b[33mâš  Warnings:\x1b[0m ${warnings}`,
1143
- `\x1b[31m✖ Errors:\x1b[0m ${errors}`,
1144
- errors === 0
1145
- ? '\x1b[32mStatus: HEALTHY — Ready for Fivora packaging & build!\x1b[0m'
1146
- : '\x1b[31mStatus: ATTENTION REQUIRED — Fix errors before deployment\x1b[0m'
1147
- ], 58) + '\n');
1148
-
1149
- if (errors > 0) {
1150
- process.exit(1);
1151
- }
985
+ function runDoctor(targetDirInput, options = {}) {
986
+ const { runDoctor: executeDoctor } = require('../src/tools/deneb-doctor.cjs');
987
+ return executeDoctor(targetDirInput, options);
1152
988
  }
1153
989
 
1154
990
  // Normalize multi-word "validate and zip" or "validate & zip"
@@ -1161,13 +997,41 @@ if (command === 'validate' && (commandArgs[0] === 'and' || commandArgs[0] === '&
1161
997
  }
1162
998
 
1163
999
  if (command === 'init') {
1164
- initProject(commandArgs[0]);
1000
+ let targetInput = '.';
1001
+ let recipeName = null;
1002
+ for (let i = 0; i < commandArgs.length; i++) {
1003
+ const arg = commandArgs[i];
1004
+ if (arg === '--recipe' || arg === '-r') {
1005
+ recipeName = commandArgs[++i];
1006
+ } else if (arg.startsWith('--recipe=')) {
1007
+ recipeName = arg.split('=')[1];
1008
+ } else if (!arg.startsWith('-')) {
1009
+ targetInput = arg;
1010
+ }
1011
+ }
1012
+ initProject(targetInput, { recipeName });
1165
1013
  } else if (command === 'create') {
1166
1014
  createTemplate(commandArgs[0]);
1167
1015
  } else if (command === 'add') {
1168
1016
  addComponent(commandArgs[0], commandArgs[1]);
1169
1017
  } else if (command === 'doctor' || command === 'check') {
1170
- runDoctor(commandArgs[0]);
1018
+ let targetInput = '.';
1019
+ let fix = false;
1020
+ let json = false;
1021
+ for (let i = 0; i < commandArgs.length; i++) {
1022
+ const arg = commandArgs[i];
1023
+ if (arg === '--fix' || arg === '-f') {
1024
+ fix = true;
1025
+ } else if (arg === '--json') {
1026
+ json = true;
1027
+ } else if (!arg.startsWith('-')) {
1028
+ targetInput = arg;
1029
+ }
1030
+ }
1031
+ const res = runDoctor(targetInput, { fix, json });
1032
+ if (res && res.errors > 0) {
1033
+ process.exit(1);
1034
+ }
1171
1035
  } else if (command === 'lab') {
1172
1036
  const script = path.join(toolsDir, 'local-template-lab.cjs');
1173
1037
  const res = spawnSync(process.execPath, [script, ...commandArgs], { stdio: 'inherit' });
@@ -1208,12 +1072,12 @@ if (command === 'init') {
1208
1072
  DENEB UI Framework — Powered by DENEB-UI Collaborate with FIVORA
1209
1073
 
1210
1074
  Core Commands:
1211
- init Auto-convert & configure existing Next.js (shadcn/HeroUI/Tailwind) into editable Fivora template
1075
+ init Auto-convert & configure existing Next.js into editable Fivora storefront (e.g. deneb init --recipe fashion)
1076
+ doctor Run comprehensive environment, manifest, visual editing AST & asset diagnostic checks (flags: --fix, --json)
1212
1077
  save-recipe Learn and save calibrated fixes & schemas into reusable recipe bank (e.g. deneb save-recipe . shoes-store)
1213
1078
  learn Alias for save-recipe
1214
1079
  update Update DENEB packages (@deneb-ui/ui, @deneb-ui/cli) and UI components
1215
1080
  validate Validate website configuration and visual editing contracts with Fivora platform
1216
- doctor Run comprehensive environment, manifest & asset diagnostic checks
1217
1081
  zip Zip the project without unnecessary folders or files (node_modules, .next, .git, .env)
1218
1082
  validate-and-zip Validate website configuration and immediately package clean upload-ready ZIP
1219
1083
 
@@ -1226,7 +1090,12 @@ Development & Scaffolding:
1226
1090
 
1227
1091
  Examples:
1228
1092
  deneb doctor
1093
+ deneb doctor --fix
1094
+ deneb doctor --json
1229
1095
  deneb init
1096
+ deneb init --recipe fashion
1097
+ deneb init --recipe electronics
1098
+ deneb init --recipe cosmetics
1230
1099
  deneb update
1231
1100
  deneb validate .
1232
1101
  deneb validate --zip
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deneb-ui/cli",
3
- "version": "2.0.21",
3
+ "version": "2.0.22",
4
4
  "description": "Official developer CLI for DENEB UI — Validating, scaffolding, testing, and packaging storefront templates. Created by Chamika Gayashan & Induranga Kawishwara.",
5
5
  "bin": {
6
6
  "deneb": "bin/index.js",