@onexapis/cli 1.1.36 → 1.1.38

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
@@ -4,18 +4,18 @@
4
4
  var chalk4 = require('chalk');
5
5
  var ora = require('ora');
6
6
  var esbuild = require('esbuild');
7
- var path8 = require('path');
8
- var fs7 = require('fs/promises');
9
- var crypto2 = require('crypto');
7
+ var path10 = require('path');
8
+ var fs9 = require('fs/promises');
9
+ var crypto = require('crypto');
10
10
  var glob = require('glob');
11
11
  var module$1 = require('module');
12
- var os3 = require('os');
12
+ var os = require('os');
13
13
  var dotenv = require('dotenv');
14
14
  var fs = require('fs-extra');
15
15
  var ejs = require('ejs');
16
- var child_process = require('child_process');
16
+ var spawn2 = require('cross-spawn');
17
17
  var commander = require('commander');
18
- var fs2 = require('fs');
18
+ var fs4 = require('fs');
19
19
  var inquirer = require('inquirer');
20
20
  var archiver = require('archiver');
21
21
  var FormData = require('form-data');
@@ -25,6 +25,7 @@ var AdmZip = require('adm-zip');
25
25
  var chokidar = require('chokidar');
26
26
  var http = require('http');
27
27
  var ws = require('ws');
28
+ var semver = require('semver');
28
29
 
29
30
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
30
31
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -50,14 +51,15 @@ function _interopNamespace(e) {
50
51
  var chalk4__default = /*#__PURE__*/_interopDefault(chalk4);
51
52
  var ora__default = /*#__PURE__*/_interopDefault(ora);
52
53
  var esbuild__namespace = /*#__PURE__*/_interopNamespace(esbuild);
53
- var path8__default = /*#__PURE__*/_interopDefault(path8);
54
- var fs7__default = /*#__PURE__*/_interopDefault(fs7);
55
- var crypto2__default = /*#__PURE__*/_interopDefault(crypto2);
56
- var os3__default = /*#__PURE__*/_interopDefault(os3);
54
+ var path10__default = /*#__PURE__*/_interopDefault(path10);
55
+ var fs9__default = /*#__PURE__*/_interopDefault(fs9);
56
+ var crypto__default = /*#__PURE__*/_interopDefault(crypto);
57
+ var os__default = /*#__PURE__*/_interopDefault(os);
57
58
  var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
58
59
  var fs__default = /*#__PURE__*/_interopDefault(fs);
59
60
  var ejs__default = /*#__PURE__*/_interopDefault(ejs);
60
- var fs2__default = /*#__PURE__*/_interopDefault(fs2);
61
+ var spawn2__default = /*#__PURE__*/_interopDefault(spawn2);
62
+ var fs4__default = /*#__PURE__*/_interopDefault(fs4);
61
63
  var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
62
64
  var archiver__default = /*#__PURE__*/_interopDefault(archiver);
63
65
  var FormData__default = /*#__PURE__*/_interopDefault(FormData);
@@ -65,6 +67,7 @@ var fetch2__default = /*#__PURE__*/_interopDefault(fetch2);
65
67
  var AdmZip__default = /*#__PURE__*/_interopDefault(AdmZip);
66
68
  var chokidar__default = /*#__PURE__*/_interopDefault(chokidar);
67
69
  var http__default = /*#__PURE__*/_interopDefault(http);
70
+ var semver__default = /*#__PURE__*/_interopDefault(semver);
68
71
 
69
72
  var __defProp = Object.defineProperty;
70
73
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -146,8 +149,8 @@ async function generateThemeCSS(themePath, outDir) {
146
149
  const tailwindcss = (await import('tailwindcss')).default;
147
150
  const tailwindConfig = {
148
151
  content: [
149
- path8__default.default.join(themePath, "sections/**/*.{ts,tsx}"),
150
- path8__default.default.join(themePath, "components/**/*.{ts,tsx}")
152
+ path10__default.default.join(themePath, "sections/**/*.{ts,tsx}"),
153
+ path10__default.default.join(themePath, "components/**/*.{ts,tsx}")
151
154
  ],
152
155
  theme: { extend: {} },
153
156
  plugins: []
@@ -157,7 +160,7 @@ async function generateThemeCSS(themePath, outDir) {
157
160
  inputCSS,
158
161
  { from: void 0 }
159
162
  );
160
- await fs7__default.default.writeFile(path8__default.default.join(outDir, "bundle.css"), result.css);
163
+ await fs9__default.default.writeFile(path10__default.default.join(outDir, "bundle.css"), result.css);
161
164
  logger.info("Generated bundle.css");
162
165
  } catch (err) {
163
166
  logger.warning(
@@ -168,12 +171,12 @@ async function generateThemeCSS(themePath, outDir) {
168
171
  async function resolveNodeModulesFile(startDir, relativePath) {
169
172
  let dir = startDir;
170
173
  while (true) {
171
- const candidate = path8__default.default.join(dir, "node_modules", relativePath);
174
+ const candidate = path10__default.default.join(dir, "node_modules", relativePath);
172
175
  try {
173
- await fs7__default.default.access(candidate);
176
+ await fs9__default.default.access(candidate);
174
177
  return candidate;
175
178
  } catch {
176
- const parent = path8__default.default.dirname(dir);
179
+ const parent = path10__default.default.dirname(dir);
177
180
  if (parent === dir) break;
178
181
  dir = parent;
179
182
  }
@@ -197,7 +200,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
197
200
  });
198
201
  for (const file of sourceFiles) {
199
202
  try {
200
- const content = await fs7__default.default.readFile(path8__default.default.join(sourceDir, file), "utf-8");
203
+ const content = await fs9__default.default.readFile(path10__default.default.join(sourceDir, file), "utf-8");
201
204
  for (const match of content.matchAll(namespaceImportRegex)) {
202
205
  const subpath = match[1] ? match[1].slice(1) : "";
203
206
  if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
@@ -251,17 +254,17 @@ function createCoreGlobalPlugin(themePath) {
251
254
  const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
252
255
  let distPath = await resolveNodeModulesFile(
253
256
  themePath,
254
- path8__default.default.join("@onexapis", "core", "dist", distFileName)
257
+ path10__default.default.join("@onexapis", "core", "dist", distFileName)
255
258
  );
256
259
  if (!distPath) {
257
260
  distPath = await resolveNodeModulesFile(
258
261
  __dirname,
259
- path8__default.default.join("@onexapis", "core", "dist", distFileName)
262
+ path10__default.default.join("@onexapis", "core", "dist", distFileName)
260
263
  );
261
264
  }
262
265
  try {
263
266
  if (!distPath) throw new Error("not found");
264
- const distContent = await fs7__default.default.readFile(distPath, "utf-8");
267
+ const distContent = await fs9__default.default.readFile(distPath, "utf-8");
265
268
  const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
266
269
  for (const m of exportMatches) {
267
270
  const names = m[1].split(",").map((n) => {
@@ -490,7 +493,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
490
493
  const pages = {};
491
494
  for (const ext of [".ts", ".js"]) {
492
495
  try {
493
- const mod = await jiti.import(path8__default.default.join(themePath, `theme.config${ext}`));
496
+ const mod = await jiti.import(path10__default.default.join(themePath, `theme.config${ext}`));
494
497
  themeConfig = mod.default || mod;
495
498
  break;
496
499
  } catch {
@@ -498,20 +501,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
498
501
  }
499
502
  for (const ext of [".ts", ".js"]) {
500
503
  try {
501
- const mod = await jiti.import(path8__default.default.join(themePath, `theme.layout${ext}`));
504
+ const mod = await jiti.import(path10__default.default.join(themePath, `theme.layout${ext}`));
502
505
  layoutConfig = mod.default || mod;
503
506
  break;
504
507
  } catch {
505
508
  }
506
509
  }
507
510
  const schemas = {};
508
- const sectionsDir = path8__default.default.join(themePath, "sections");
511
+ const sectionsDir = path10__default.default.join(themePath, "sections");
509
512
  try {
510
- const sectionDirs = await fs7__default.default.readdir(sectionsDir);
513
+ const sectionDirs = await fs9__default.default.readdir(sectionsDir);
511
514
  for (const dir of sectionDirs) {
512
- const schemaFile = path8__default.default.join(sectionsDir, dir, `${dir}.schema.ts`);
515
+ const schemaFile = path10__default.default.join(sectionsDir, dir, `${dir}.schema.ts`);
513
516
  try {
514
- await fs7__default.default.access(schemaFile);
517
+ await fs9__default.default.access(schemaFile);
515
518
  const mod = await jiti.import(schemaFile);
516
519
  for (const [key, value] of Object.entries(mod)) {
517
520
  if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
@@ -523,14 +526,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
523
526
  }
524
527
  } catch {
525
528
  }
526
- const pagesDir = path8__default.default.join(themePath, "pages");
529
+ const pagesDir = path10__default.default.join(themePath, "pages");
527
530
  try {
528
- const files = await fs7__default.default.readdir(pagesDir);
531
+ const files = await fs9__default.default.readdir(pagesDir);
529
532
  for (const file of files) {
530
533
  if (!file.match(/\.(ts|js)$/)) continue;
531
534
  const name = file.replace(/\.(ts|js)$/, "");
532
535
  try {
533
- const mod = await jiti.import(path8__default.default.join(pagesDir, file));
536
+ const mod = await jiti.import(path10__default.default.join(pagesDir, file));
534
537
  const config = mod.default || mod;
535
538
  const sections = (config.sections || []).map((section) => {
536
539
  const schema = schemas[section.type];
@@ -558,8 +561,8 @@ async function generateThemeData(themePath, outputDir, themeId) {
558
561
  }
559
562
  } catch {
560
563
  }
561
- await fs7__default.default.writeFile(
562
- path8__default.default.join(outputDir, "theme-data.json"),
564
+ await fs9__default.default.writeFile(
565
+ path10__default.default.join(outputDir, "theme-data.json"),
563
566
  JSON.stringify(
564
567
  {
565
568
  themeId,
@@ -582,53 +585,53 @@ async function generateThemeData(themePath, outputDir, themeId) {
582
585
  logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
583
586
  }
584
587
  async function contentHashEntry(outputDir) {
585
- const entryPath = path8__default.default.join(outputDir, "bundle-entry.js");
586
- const mapPath = path8__default.default.join(outputDir, "bundle-entry.js.map");
588
+ const entryPath = path10__default.default.join(outputDir, "bundle-entry.js");
589
+ const mapPath = path10__default.default.join(outputDir, "bundle-entry.js.map");
587
590
  const oldFiles = await glob.glob("bundle-entry-*.js*", { cwd: outputDir });
588
591
  for (const f of oldFiles) {
589
- await fs7__default.default.unlink(path8__default.default.join(outputDir, f));
592
+ await fs9__default.default.unlink(path10__default.default.join(outputDir, f));
590
593
  }
591
594
  let entryContent;
592
595
  try {
593
- entryContent = await fs7__default.default.readFile(entryPath, "utf-8");
596
+ entryContent = await fs9__default.default.readFile(entryPath, "utf-8");
594
597
  } catch {
595
- const indexPath = path8__default.default.join(outputDir, "index.js");
598
+ const indexPath = path10__default.default.join(outputDir, "index.js");
596
599
  try {
597
- entryContent = await fs7__default.default.readFile(indexPath, "utf-8");
600
+ entryContent = await fs9__default.default.readFile(indexPath, "utf-8");
598
601
  } catch {
599
602
  logger.warning("No entry file found in output, skipping content hash");
600
603
  return;
601
604
  }
602
- const hash2 = crypto2__default.default.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
605
+ const hash2 = crypto__default.default.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
603
606
  const hashedName2 = `bundle-entry-${hash2}.js`;
604
- const indexMapPath = path8__default.default.join(outputDir, "index.js.map");
607
+ const indexMapPath = path10__default.default.join(outputDir, "index.js.map");
605
608
  const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
606
609
  entryContent = entryContent.replace(
607
610
  /\/\/# sourceMappingURL=index\.js\.map/,
608
611
  `//# sourceMappingURL=${hashedMapName2}`
609
612
  );
610
- await fs7__default.default.writeFile(path8__default.default.join(outputDir, hashedName2), entryContent);
611
- await fs7__default.default.unlink(indexPath);
613
+ await fs9__default.default.writeFile(path10__default.default.join(outputDir, hashedName2), entryContent);
614
+ await fs9__default.default.unlink(indexPath);
612
615
  try {
613
- await fs7__default.default.access(indexMapPath);
614
- await fs7__default.default.rename(indexMapPath, path8__default.default.join(outputDir, hashedMapName2));
616
+ await fs9__default.default.access(indexMapPath);
617
+ await fs9__default.default.rename(indexMapPath, path10__default.default.join(outputDir, hashedMapName2));
615
618
  } catch {
616
619
  }
617
620
  logger.info(`Entry hashed: ${hashedName2}`);
618
621
  return;
619
622
  }
620
- const hash = crypto2__default.default.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
623
+ const hash = crypto__default.default.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
621
624
  const hashedName = `bundle-entry-${hash}.js`;
622
625
  const hashedMapName = `bundle-entry-${hash}.js.map`;
623
626
  entryContent = entryContent.replace(
624
627
  /\/\/# sourceMappingURL=bundle-entry\.js\.map/,
625
628
  `//# sourceMappingURL=${hashedMapName}`
626
629
  );
627
- await fs7__default.default.writeFile(path8__default.default.join(outputDir, hashedName), entryContent);
628
- await fs7__default.default.unlink(entryPath);
630
+ await fs9__default.default.writeFile(path10__default.default.join(outputDir, hashedName), entryContent);
631
+ await fs9__default.default.unlink(entryPath);
629
632
  try {
630
- await fs7__default.default.access(mapPath);
631
- await fs7__default.default.rename(mapPath, path8__default.default.join(outputDir, hashedMapName));
633
+ await fs9__default.default.access(mapPath);
634
+ await fs9__default.default.rename(mapPath, path10__default.default.join(outputDir, hashedMapName));
632
635
  } catch {
633
636
  }
634
637
  logger.info(`Entry hashed: ${hashedName}`);
@@ -640,7 +643,7 @@ async function extractDataRequirements(themePath) {
640
643
  const requirements = {};
641
644
  for (const file of schemaFiles) {
642
645
  try {
643
- const mod = await jiti.import(path8__default.default.join(themePath, file));
646
+ const mod = await jiti.import(path10__default.default.join(themePath, file));
644
647
  const exports$1 = mod;
645
648
  for (const value of Object.values(exports$1)) {
646
649
  if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
@@ -659,8 +662,8 @@ async function generateManifest(themeName, themePath, outputDir) {
659
662
  let version2 = "1.0.0";
660
663
  let themeId = themeName;
661
664
  try {
662
- const pkgContent = await fs7__default.default.readFile(
663
- path8__default.default.join(themePath, "package.json"),
665
+ const pkgContent = await fs9__default.default.readFile(
666
+ path10__default.default.join(themePath, "package.json"),
664
667
  "utf-8"
665
668
  );
666
669
  const pkg = JSON.parse(pkgContent);
@@ -678,7 +681,7 @@ async function generateManifest(themeName, themePath, outputDir) {
678
681
  const dataRequirements = await extractDataRequirements(themePath);
679
682
  let hasThemeConfig = false;
680
683
  try {
681
- await fs7__default.default.access(path8__default.default.join(themePath, "theme.config.ts"));
684
+ await fs9__default.default.access(path10__default.default.join(themePath, "theme.config.ts"));
682
685
  hasThemeConfig = true;
683
686
  } catch {
684
687
  }
@@ -719,24 +722,24 @@ async function generateManifest(themeName, themePath, outputDir) {
719
722
  // Section data requirements for server-side prefetching (keyed by section type)
720
723
  dataRequirements
721
724
  };
722
- await fs7__default.default.writeFile(
723
- path8__default.default.join(outputDir, "manifest.json"),
725
+ await fs9__default.default.writeFile(
726
+ path10__default.default.join(outputDir, "manifest.json"),
724
727
  JSON.stringify(manifest, null, 2)
725
728
  );
726
729
  }
727
730
  async function compileStandaloneTheme(themePath, themeName) {
728
- const outputDir = path8__default.default.join(themePath, "dist");
729
- const bundleEntry = path8__default.default.join(themePath, "bundle-entry.ts");
730
- const indexEntry = path8__default.default.join(themePath, "index.ts");
731
+ const outputDir = path10__default.default.join(themePath, "dist");
732
+ const bundleEntry = path10__default.default.join(themePath, "bundle-entry.ts");
733
+ const indexEntry = path10__default.default.join(themePath, "index.ts");
731
734
  let entryPoint = indexEntry;
732
735
  try {
733
- await fs7__default.default.access(bundleEntry);
736
+ await fs9__default.default.access(bundleEntry);
734
737
  entryPoint = bundleEntry;
735
738
  } catch {
736
739
  }
737
- const shimPath = path8__default.default.join(outputDir, ".process-shim.js");
738
- await fs7__default.default.mkdir(outputDir, { recursive: true });
739
- await fs7__default.default.writeFile(shimPath, PROCESS_SHIM);
740
+ const shimPath = path10__default.default.join(outputDir, ".process-shim.js");
741
+ await fs9__default.default.mkdir(outputDir, { recursive: true });
742
+ await fs9__default.default.writeFile(shimPath, PROCESS_SHIM);
740
743
  const buildOptions = {
741
744
  entryPoints: [entryPoint],
742
745
  bundle: true,
@@ -786,7 +789,7 @@ async function compileStandaloneTheme(themePath, themeName) {
786
789
  try {
787
790
  const result = await esbuild__namespace.build(buildOptions);
788
791
  try {
789
- await fs7__default.default.unlink(shimPath);
792
+ await fs9__default.default.unlink(shimPath);
790
793
  } catch {
791
794
  }
792
795
  await contentHashEntry(outputDir);
@@ -805,7 +808,7 @@ async function compileStandaloneTheme(themePath, themeName) {
805
808
  return true;
806
809
  } catch (error) {
807
810
  try {
808
- await fs7__default.default.unlink(shimPath);
811
+ await fs9__default.default.unlink(shimPath);
809
812
  } catch {
810
813
  }
811
814
  logger.error(`esbuild compilation failed: ${error}`);
@@ -813,18 +816,18 @@ async function compileStandaloneTheme(themePath, themeName) {
813
816
  }
814
817
  }
815
818
  async function compileStandaloneThemeDev(themePath, themeName) {
816
- const outputDir = path8__default.default.join(themePath, "dist");
817
- const bundleEntry = path8__default.default.join(themePath, "bundle-entry.ts");
818
- const indexEntry = path8__default.default.join(themePath, "index.ts");
819
+ const outputDir = path10__default.default.join(themePath, "dist");
820
+ const bundleEntry = path10__default.default.join(themePath, "bundle-entry.ts");
821
+ const indexEntry = path10__default.default.join(themePath, "index.ts");
819
822
  let entryPoint = indexEntry;
820
823
  try {
821
- await fs7__default.default.access(bundleEntry);
824
+ await fs9__default.default.access(bundleEntry);
822
825
  entryPoint = bundleEntry;
823
826
  } catch {
824
827
  }
825
- const shimPath = path8__default.default.join(outputDir, ".process-shim.js");
826
- await fs7__default.default.mkdir(outputDir, { recursive: true });
827
- await fs7__default.default.writeFile(shimPath, PROCESS_SHIM);
828
+ const shimPath = path10__default.default.join(outputDir, ".process-shim.js");
829
+ await fs9__default.default.mkdir(outputDir, { recursive: true });
830
+ await fs9__default.default.writeFile(shimPath, PROCESS_SHIM);
828
831
  const buildOptions = {
829
832
  entryPoints: [entryPoint],
830
833
  bundle: true,
@@ -877,18 +880,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
877
880
  return { context: context2, outputDir };
878
881
  }
879
882
  async function compilePreviewRuntime(themePath) {
880
- const outputDir = path8__default.default.join(themePath, "dist");
881
- await fs7__default.default.mkdir(outputDir, { recursive: true });
882
- const outputPath = path8__default.default.join(outputDir, "preview-runtime.js");
883
+ const outputDir = path10__default.default.join(themePath, "dist");
884
+ await fs9__default.default.mkdir(outputDir, { recursive: true });
885
+ const outputPath = path10__default.default.join(outputDir, "preview-runtime.js");
883
886
  const locations = [
884
- path8__default.default.join(__dirname, "..", "preview", "preview-app.tsx"),
885
- path8__default.default.join(__dirname, "preview", "preview-app.tsx"),
886
- path8__default.default.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
887
+ path10__default.default.join(__dirname, "..", "preview", "preview-app.tsx"),
888
+ path10__default.default.join(__dirname, "preview", "preview-app.tsx"),
889
+ path10__default.default.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
887
890
  ];
888
891
  let previewEntryPath = null;
889
892
  for (const loc of locations) {
890
893
  try {
891
- await fs7__default.default.access(loc);
894
+ await fs9__default.default.access(loc);
892
895
  previewEntryPath = loc;
893
896
  break;
894
897
  } catch {
@@ -971,10 +974,10 @@ ${locations.join("\n")}`
971
974
  if (!lucideScanned) {
972
975
  lucideScanned = true;
973
976
  const coreSrcCandidates = [
974
- path8__default.default.join(themePath, "node_modules", "@onexapis", "core", "src"),
975
- path8__default.default.join(themePath, "..", "..", "packages", "core", "src"),
977
+ path10__default.default.join(themePath, "node_modules", "@onexapis", "core", "src"),
978
+ path10__default.default.join(themePath, "..", "..", "packages", "core", "src"),
976
979
  // monorepo sibling
977
- path8__default.default.join(
980
+ path10__default.default.join(
978
981
  __dirname,
979
982
  "..",
980
983
  "..",
@@ -989,7 +992,7 @@ ${locations.join("\n")}`
989
992
  let coreSourceDir = null;
990
993
  for (const candidate of coreSrcCandidates) {
991
994
  try {
992
- await fs7__default.default.access(candidate);
995
+ await fs9__default.default.access(candidate);
993
996
  coreSourceDir = candidate;
994
997
  break;
995
998
  } catch {
@@ -1008,21 +1011,21 @@ ${locations.join("\n")}`
1008
1011
  }
1009
1012
  } else {
1010
1013
  const coreDistCandidates = [
1011
- path8__default.default.join(themePath, "node_modules", "@onexapis", "core", "dist")
1014
+ path10__default.default.join(themePath, "node_modules", "@onexapis", "core", "dist")
1012
1015
  ];
1013
1016
  const resolvedDist = await resolveNodeModulesFile(
1014
1017
  __dirname,
1015
- path8__default.default.join("@onexapis", "core", "dist")
1018
+ path10__default.default.join("@onexapis", "core", "dist")
1016
1019
  );
1017
1020
  if (resolvedDist) coreDistCandidates.push(resolvedDist);
1018
1021
  for (const candidate of coreDistCandidates) {
1019
1022
  try {
1020
- await fs7__default.default.access(candidate);
1023
+ await fs9__default.default.access(candidate);
1021
1024
  const mjsFiles = await glob.glob("*.mjs", { cwd: candidate });
1022
1025
  const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
1023
1026
  for (const file of mjsFiles) {
1024
- const content = await fs7__default.default.readFile(
1025
- path8__default.default.join(candidate, file),
1027
+ const content = await fs9__default.default.readFile(
1028
+ path10__default.default.join(candidate, file),
1026
1029
  "utf-8"
1027
1030
  );
1028
1031
  for (const match of content.matchAll(importRegex)) {
@@ -1077,7 +1080,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
1077
1080
  const req = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)) || __filename);
1078
1081
  const cjsPath = req.resolve("framer-motion");
1079
1082
  const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
1080
- const esmEntry = path8__default.default.join(pkgDir, "dist", "es", "index.mjs");
1083
+ const esmEntry = path10__default.default.join(pkgDir, "dist", "es", "index.mjs");
1081
1084
  const { existsSync } = await import('fs');
1082
1085
  if (existsSync(esmEntry)) {
1083
1086
  return { path: esmEntry, namespace: "file" };
@@ -1176,8 +1179,8 @@ export function headers() { return new Headers(); }
1176
1179
  });
1177
1180
  }
1178
1181
  };
1179
- const shimPath = path8__default.default.join(outputDir, ".process-shim-preview.js");
1180
- await fs7__default.default.writeFile(shimPath, PROCESS_SHIM);
1182
+ const shimPath = path10__default.default.join(outputDir, ".process-shim-preview.js");
1183
+ await fs9__default.default.writeFile(shimPath, PROCESS_SHIM);
1181
1184
  await esbuild__namespace.build({
1182
1185
  entryPoints: [previewEntryPath],
1183
1186
  bundle: true,
@@ -1212,7 +1215,7 @@ export function headers() { return new Headers(); }
1212
1215
  }
1213
1216
  });
1214
1217
  try {
1215
- await fs7__default.default.unlink(shimPath);
1218
+ await fs9__default.default.unlink(shimPath);
1216
1219
  } catch {
1217
1220
  }
1218
1221
  return outputPath;
@@ -1345,18 +1348,18 @@ async function renderTemplate(templatePath, data) {
1345
1348
  return ejs__default.default.render(template, data);
1346
1349
  }
1347
1350
  async function writeFile(filePath, content) {
1348
- await fs__default.default.ensureDir(path8__default.default.dirname(filePath));
1351
+ await fs__default.default.ensureDir(path10__default.default.dirname(filePath));
1349
1352
  await fs__default.default.writeFile(filePath, content, "utf-8");
1350
1353
  }
1351
1354
  function getTemplatesDir() {
1352
1355
  const locations = [
1353
- path8__default.default.join(__dirname, "../../templates"),
1356
+ path10__default.default.join(__dirname, "../../templates"),
1354
1357
  // Development
1355
- path8__default.default.join(__dirname, "../templates"),
1358
+ path10__default.default.join(__dirname, "../templates"),
1356
1359
  // Production (dist/)
1357
- path8__default.default.join(process.cwd(), "templates"),
1360
+ path10__default.default.join(process.cwd(), "templates"),
1358
1361
  // Fallback
1359
- path8__default.default.join(process.cwd(), "packages/cli/templates")
1362
+ path10__default.default.join(process.cwd(), "packages/cli/templates")
1360
1363
  // Monorepo
1361
1364
  ];
1362
1365
  for (const location of locations) {
@@ -1368,7 +1371,7 @@ function getTemplatesDir() {
1368
1371
  }
1369
1372
  async function copyTemplate(templateName, targetDir, data) {
1370
1373
  const templatesDir = getTemplatesDir();
1371
- const templateDir = path8__default.default.join(templatesDir, templateName);
1374
+ const templateDir = path10__default.default.join(templatesDir, templateName);
1372
1375
  if (!fs__default.default.existsSync(templateDir)) {
1373
1376
  throw new Error(
1374
1377
  `Template "${templateName}" not found at ${templateDir}. Available templates: ${fs__default.default.readdirSync(templatesDir).join(", ")}`
@@ -1377,8 +1380,8 @@ async function copyTemplate(templateName, targetDir, data) {
1377
1380
  await fs__default.default.ensureDir(targetDir);
1378
1381
  const files = await fs__default.default.readdir(templateDir);
1379
1382
  for (const file of files) {
1380
- const templatePath = path8__default.default.join(templateDir, file);
1381
- const targetPath = path8__default.default.join(targetDir, file);
1383
+ const templatePath = path10__default.default.join(templateDir, file);
1384
+ const targetPath = path10__default.default.join(targetDir, file);
1382
1385
  const stat = await fs__default.default.stat(templatePath);
1383
1386
  if (stat.isDirectory()) {
1384
1387
  await copyTemplateDir(templatePath, targetPath, data);
@@ -1395,8 +1398,8 @@ async function copyTemplateDir(templateDir, targetDir, data) {
1395
1398
  await fs__default.default.ensureDir(targetDir);
1396
1399
  const files = await fs__default.default.readdir(templateDir);
1397
1400
  for (const file of files) {
1398
- const templatePath = path8__default.default.join(templateDir, file);
1399
- const targetPath = path8__default.default.join(targetDir, file);
1401
+ const templatePath = path10__default.default.join(templateDir, file);
1402
+ const targetPath = path10__default.default.join(targetDir, file);
1400
1403
  const stat = await fs__default.default.stat(templatePath);
1401
1404
  if (stat.isDirectory()) {
1402
1405
  await copyTemplateDir(templatePath, targetPath, data);
@@ -1411,32 +1414,32 @@ async function copyTemplateDir(templateDir, targetDir, data) {
1411
1414
  }
1412
1415
  function getProjectRoot() {
1413
1416
  let currentDir = process.cwd();
1414
- while (currentDir !== path8__default.default.parse(currentDir).root) {
1415
- const packageJsonPath = path8__default.default.join(currentDir, "package.json");
1417
+ while (currentDir !== path10__default.default.parse(currentDir).root) {
1418
+ const packageJsonPath = path10__default.default.join(currentDir, "package.json");
1416
1419
  if (fs__default.default.existsSync(packageJsonPath)) {
1417
1420
  const packageJson = fs__default.default.readJsonSync(packageJsonPath);
1418
- if (packageJson.workspaces || fs__default.default.existsSync(path8__default.default.join(currentDir, "src/themes")) || fs__default.default.existsSync(path8__default.default.join(currentDir, "themes"))) {
1421
+ if (packageJson.workspaces || fs__default.default.existsSync(path10__default.default.join(currentDir, "src/themes")) || fs__default.default.existsSync(path10__default.default.join(currentDir, "themes"))) {
1419
1422
  return currentDir;
1420
1423
  }
1421
1424
  }
1422
- currentDir = path8__default.default.dirname(currentDir);
1425
+ currentDir = path10__default.default.dirname(currentDir);
1423
1426
  }
1424
1427
  return process.cwd();
1425
1428
  }
1426
1429
  function getThemesDir() {
1427
1430
  const root = getProjectRoot();
1428
- if (fs__default.default.existsSync(path8__default.default.join(root, "themes")))
1429
- return path8__default.default.join(root, "themes");
1430
- if (fs__default.default.existsSync(path8__default.default.join(root, "src/themes")))
1431
- return path8__default.default.join(root, "src/themes");
1432
- return path8__default.default.dirname(root);
1431
+ if (fs__default.default.existsSync(path10__default.default.join(root, "themes")))
1432
+ return path10__default.default.join(root, "themes");
1433
+ if (fs__default.default.existsSync(path10__default.default.join(root, "src/themes")))
1434
+ return path10__default.default.join(root, "src/themes");
1435
+ return path10__default.default.dirname(root);
1433
1436
  }
1434
1437
  function getFeaturesDir() {
1435
- return path8__default.default.join(getProjectRoot(), "src/features");
1438
+ return path10__default.default.join(getProjectRoot(), "src/features");
1436
1439
  }
1437
1440
  function isOneXProject() {
1438
1441
  const root = getProjectRoot();
1439
- return fs__default.default.existsSync(path8__default.default.join(root, "themes")) || fs__default.default.existsSync(path8__default.default.join(root, "src/themes")) || fs__default.default.existsSync(path8__default.default.join(root, "theme.config.ts")) || fs__default.default.existsSync(path8__default.default.join(root, "bundle-entry.ts"));
1442
+ return fs__default.default.existsSync(path10__default.default.join(root, "themes")) || fs__default.default.existsSync(path10__default.default.join(root, "src/themes")) || fs__default.default.existsSync(path10__default.default.join(root, "theme.config.ts")) || fs__default.default.existsSync(path10__default.default.join(root, "bundle-entry.ts"));
1440
1443
  }
1441
1444
  function ensureOneXProject() {
1442
1445
  if (!isOneXProject()) {
@@ -1452,13 +1455,13 @@ function listThemes() {
1452
1455
  return [];
1453
1456
  }
1454
1457
  return fs__default.default.readdirSync(themesDir).filter((name) => {
1455
- const themePath = path8__default.default.join(themesDir, name);
1456
- return fs__default.default.statSync(themePath).isDirectory() && (fs__default.default.existsSync(path8__default.default.join(themePath, "theme.config.ts")) || fs__default.default.existsSync(path8__default.default.join(themePath, "bundle-entry.ts")) || fs__default.default.existsSync(path8__default.default.join(themePath, "manifest.ts")));
1458
+ const themePath = path10__default.default.join(themesDir, name);
1459
+ return fs__default.default.statSync(themePath).isDirectory() && (fs__default.default.existsSync(path10__default.default.join(themePath, "theme.config.ts")) || fs__default.default.existsSync(path10__default.default.join(themePath, "bundle-entry.ts")) || fs__default.default.existsSync(path10__default.default.join(themePath, "manifest.ts")));
1457
1460
  });
1458
1461
  }
1459
1462
  function themeExists(themeName) {
1460
- const themePath = path8__default.default.join(getThemesDir(), themeName);
1461
- return fs__default.default.existsSync(themePath) && (fs__default.default.existsSync(path8__default.default.join(themePath, "theme.config.ts")) || fs__default.default.existsSync(path8__default.default.join(themePath, "bundle-entry.ts")) || fs__default.default.existsSync(path8__default.default.join(themePath, "manifest.ts")));
1463
+ const themePath = path10__default.default.join(getThemesDir(), themeName);
1464
+ return fs__default.default.existsSync(themePath) && (fs__default.default.existsSync(path10__default.default.join(themePath, "theme.config.ts")) || fs__default.default.existsSync(path10__default.default.join(themePath, "bundle-entry.ts")) || fs__default.default.existsSync(path10__default.default.join(themePath, "manifest.ts")));
1462
1465
  }
1463
1466
  function detectPackageManager() {
1464
1467
  const userAgent = process.env.npm_config_user_agent || "";
@@ -1466,24 +1469,22 @@ function detectPackageManager() {
1466
1469
  if (userAgent.includes("yarn")) return "yarn";
1467
1470
  if (userAgent.includes("bun")) return "bun";
1468
1471
  const cwd = process.cwd();
1469
- if (fs__default.default.existsSync(path8__default.default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1470
- if (fs__default.default.existsSync(path8__default.default.join(cwd, "yarn.lock"))) return "yarn";
1471
- if (fs__default.default.existsSync(path8__default.default.join(cwd, "bun.lockb"))) return "bun";
1472
+ if (fs__default.default.existsSync(path10__default.default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1473
+ if (fs__default.default.existsSync(path10__default.default.join(cwd, "yarn.lock"))) return "yarn";
1474
+ if (fs__default.default.existsSync(path10__default.default.join(cwd, "bun.lockb"))) return "bun";
1472
1475
  return "npm";
1473
1476
  }
1474
1477
  async function installDependencies(projectPath, packageManager = "npm") {
1475
- return new Promise((resolve, reject) => {
1476
- try {
1477
- const installCmd = packageManager === "yarn" ? "yarn" : `${packageManager} install`;
1478
- child_process.execSync(installCmd, {
1479
- cwd: projectPath,
1480
- stdio: "inherit"
1481
- });
1482
- resolve();
1483
- } catch (error) {
1484
- reject(error);
1485
- }
1478
+ const args = packageManager === "yarn" ? [] : ["install"];
1479
+ const result = spawn2__default.default.sync(packageManager, args, {
1480
+ cwd: projectPath,
1481
+ stdio: "inherit"
1486
1482
  });
1483
+ if (result.status !== 0) {
1484
+ throw new Error(
1485
+ `${packageManager} install failed with exit code ${result.status}`
1486
+ );
1487
+ }
1487
1488
  }
1488
1489
 
1489
1490
  // src/commands/init.ts
@@ -1517,6 +1518,184 @@ function getValidCategories() {
1517
1518
  "contact"
1518
1519
  ];
1519
1520
  }
1521
+ var AUTH_DIR = path10__default.default.join(os__default.default.homedir(), ".onexthm");
1522
+ var AUTH_FILE = path10__default.default.join(AUTH_DIR, "auth.json");
1523
+ function getApiUrl() {
1524
+ return process.env.ONEXTHM_API_URL || process.env.NEXT_PUBLIC_API_URL || "https://platform-dev.onexeos.com";
1525
+ }
1526
+ async function saveAuthTokens(tokens) {
1527
+ await fs__default.default.ensureDir(AUTH_DIR);
1528
+ const key = getMachineKey();
1529
+ const data = JSON.stringify(tokens);
1530
+ const encrypted = encrypt(data, key);
1531
+ await fs__default.default.writeFile(AUTH_FILE, encrypted, "utf-8");
1532
+ }
1533
+ function loadAuthTokens() {
1534
+ try {
1535
+ if (!fs__default.default.existsSync(AUTH_FILE)) return null;
1536
+ const encrypted = fs__default.default.readFileSync(AUTH_FILE, "utf-8");
1537
+ const key = getMachineKey();
1538
+ const data = decrypt(encrypted, key);
1539
+ return JSON.parse(data);
1540
+ } catch {
1541
+ return null;
1542
+ }
1543
+ }
1544
+ async function clearAuthTokens() {
1545
+ try {
1546
+ await fs__default.default.remove(AUTH_FILE);
1547
+ } catch {
1548
+ }
1549
+ }
1550
+ function isTokenExpired(tokens) {
1551
+ return Date.now() / 1e3 > tokens.expiresAt - 60;
1552
+ }
1553
+ async function getValidTokens() {
1554
+ const tokens = loadAuthTokens();
1555
+ if (!tokens) return null;
1556
+ if (!isTokenExpired(tokens)) return tokens;
1557
+ try {
1558
+ const apiUrl = getApiUrl();
1559
+ const response = await fetch(`${apiUrl}/auth/refresh`, {
1560
+ method: "POST",
1561
+ headers: { "Content-Type": "application/json" },
1562
+ body: JSON.stringify({ refresh_token: tokens.refreshToken })
1563
+ });
1564
+ if (!response.ok) {
1565
+ await clearAuthTokens();
1566
+ return null;
1567
+ }
1568
+ const data = await response.json();
1569
+ const body = data.statusCode ? data.body : data;
1570
+ const refreshed = {
1571
+ ...tokens,
1572
+ accessToken: body.AccessToken || tokens.accessToken,
1573
+ idToken: body.IdToken || tokens.idToken,
1574
+ expiresAt: Math.floor(Date.now() / 1e3) + (body.ExpiresIn || 3600)
1575
+ };
1576
+ await saveAuthTokens(refreshed);
1577
+ return refreshed;
1578
+ } catch {
1579
+ await clearAuthTokens();
1580
+ return null;
1581
+ }
1582
+ }
1583
+ async function authenticatedFetch(url, init) {
1584
+ const tokens = await getValidTokens();
1585
+ if (!tokens) {
1586
+ throw new Error("Not logged in. Run: onexthm login");
1587
+ }
1588
+ const headers = new Headers(init?.headers);
1589
+ headers.set("Authorization", `Bearer ${tokens.idToken}`);
1590
+ headers.set("Content-Type", "application/json");
1591
+ return fetch(url, { ...init, headers });
1592
+ }
1593
+ function getMachineKey() {
1594
+ let seed;
1595
+ if (process.platform === "darwin") {
1596
+ seed = `onexthm:${os__default.default.hostname()}:${os__default.default.userInfo().username}`;
1597
+ } else if (process.platform === "linux") {
1598
+ try {
1599
+ seed = `onexthm:${fs__default.default.readFileSync("/etc/machine-id", "utf-8").trim()}`;
1600
+ } catch {
1601
+ seed = `onexthm:${os__default.default.hostname()}:${os__default.default.userInfo().username}`;
1602
+ }
1603
+ } else {
1604
+ seed = `onexthm:${os__default.default.hostname()}:${os__default.default.userInfo().username}`;
1605
+ }
1606
+ return crypto__default.default.createHash("sha256").update(seed).digest();
1607
+ }
1608
+ function encrypt(text, key) {
1609
+ const iv = crypto__default.default.randomBytes(16);
1610
+ const cipher = crypto__default.default.createCipheriv("aes-256-gcm", key, iv);
1611
+ let encrypted = cipher.update(text, "utf-8", "hex");
1612
+ encrypted += cipher.final("hex");
1613
+ const tag = cipher.getAuthTag();
1614
+ return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted}`;
1615
+ }
1616
+ function decrypt(text, key) {
1617
+ const [ivHex, tagHex, encrypted] = text.split(":");
1618
+ const iv = Buffer.from(ivHex, "hex");
1619
+ const tag = Buffer.from(tagHex, "hex");
1620
+ const decipher = crypto__default.default.createDecipheriv("aes-256-gcm", key, iv);
1621
+ decipher.setAuthTag(tag);
1622
+ let decrypted = decipher.update(encrypted, "hex", "utf-8");
1623
+ decrypted += decipher.final("utf-8");
1624
+ return decrypted;
1625
+ }
1626
+ function parseJwtClaims(idToken) {
1627
+ try {
1628
+ const payload = idToken.split(".")[1];
1629
+ const decoded = Buffer.from(payload, "base64url").toString("utf-8");
1630
+ return JSON.parse(decoded);
1631
+ } catch {
1632
+ return {};
1633
+ }
1634
+ }
1635
+ function getNpxCommand() {
1636
+ return process.platform === "win32" ? "npx.cmd" : "npx";
1637
+ }
1638
+ function getDefaultMcpConfig() {
1639
+ return {
1640
+ mcpServers: {
1641
+ onexthm: {
1642
+ command: getNpxCommand(),
1643
+ args: ["-y", "@onexapis/theme-mcp"]
1644
+ }
1645
+ }
1646
+ };
1647
+ }
1648
+ function ensureMcpJson(projectPath, figmaApiKey) {
1649
+ const mcpJsonPath = path10__default.default.join(projectPath, ".mcp.json");
1650
+ const npx = getNpxCommand();
1651
+ let mcpConfig;
1652
+ if (fs4__default.default.existsSync(mcpJsonPath)) {
1653
+ try {
1654
+ mcpConfig = JSON.parse(fs4__default.default.readFileSync(mcpJsonPath, "utf-8"));
1655
+ if (!mcpConfig.mcpServers) {
1656
+ mcpConfig.mcpServers = {};
1657
+ }
1658
+ } catch {
1659
+ mcpConfig = getDefaultMcpConfig();
1660
+ }
1661
+ } else {
1662
+ mcpConfig = getDefaultMcpConfig();
1663
+ }
1664
+ mcpConfig.mcpServers.onexthm = {
1665
+ command: npx,
1666
+ args: ["-y", "@onexapis/theme-mcp"]
1667
+ };
1668
+ if (figmaApiKey) {
1669
+ mcpConfig.mcpServers.figma = {
1670
+ command: npx,
1671
+ args: [
1672
+ "-y",
1673
+ "figma-developer-mcp",
1674
+ `--figma-api-key=${figmaApiKey}`,
1675
+ "--stdio"
1676
+ ]
1677
+ };
1678
+ } else {
1679
+ delete mcpConfig.mcpServers.figma;
1680
+ }
1681
+ fs4__default.default.writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, 2) + "\n");
1682
+ ensureThemeMcpDependency(projectPath);
1683
+ }
1684
+ function ensureThemeMcpDependency(projectPath) {
1685
+ const pkgJsonPath = path10__default.default.join(projectPath, "package.json");
1686
+ if (!fs4__default.default.existsSync(pkgJsonPath)) return;
1687
+ try {
1688
+ const pkg = JSON.parse(fs4__default.default.readFileSync(pkgJsonPath, "utf-8"));
1689
+ if (!pkg.devDependencies) {
1690
+ pkg.devDependencies = {};
1691
+ }
1692
+ if (!pkg.devDependencies["@onexapis/theme-mcp"]) {
1693
+ pkg.devDependencies["@onexapis/theme-mcp"] = "^0.1.0";
1694
+ fs4__default.default.writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2) + "\n");
1695
+ }
1696
+ } catch {
1697
+ }
1698
+ }
1520
1699
 
1521
1700
  // src/commands/init.ts
1522
1701
  async function initCommand(projectName, options = {}) {
@@ -1534,7 +1713,7 @@ async function initCommand(projectName, options = {}) {
1534
1713
  if (!validateThemeName(kebabName)) {
1535
1714
  return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
1536
1715
  }
1537
- if (fs2__default.default.existsSync(path8__default.default.join(process.cwd(), kebabName))) {
1716
+ if (fs4__default.default.existsSync(path10__default.default.join(process.cwd(), kebabName))) {
1538
1717
  return `Directory "${kebabName}" already exists`;
1539
1718
  }
1540
1719
  return true;
@@ -1545,11 +1724,46 @@ async function initCommand(projectName, options = {}) {
1545
1724
  } else {
1546
1725
  name = toKebabCase(projectName);
1547
1726
  }
1548
- const projectPath = path8__default.default.join(process.cwd(), name);
1549
- if (fs2__default.default.existsSync(projectPath)) {
1727
+ const projectPath = path10__default.default.join(process.cwd(), name);
1728
+ if (fs4__default.default.existsSync(projectPath)) {
1550
1729
  logger.error(`Directory "${name}" already exists.`);
1551
1730
  process.exit(1);
1552
1731
  }
1732
+ if (!options.yes) {
1733
+ try {
1734
+ const apiUrl = getApiUrl();
1735
+ const controller = new AbortController();
1736
+ const timeout = setTimeout(() => controller.abort(), 3e3);
1737
+ const response = await fetch(
1738
+ `${apiUrl}/website-api/themes/${encodeURIComponent(name)}/exists`,
1739
+ { signal: controller.signal }
1740
+ );
1741
+ clearTimeout(timeout);
1742
+ if (response.ok) {
1743
+ const data2 = await response.json();
1744
+ const body = data2.statusCode ? data2.body : data2;
1745
+ if (body.exists && body.owner === "other") {
1746
+ logger.warning(
1747
+ `Theme ID "${name}" is already registered by another developer.
1748
+ You can still create this locally, but publishing will fail.
1749
+ Consider using a different name.`
1750
+ );
1751
+ const { proceed } = await inquirer__default.default.prompt([
1752
+ {
1753
+ type: "confirm",
1754
+ name: "proceed",
1755
+ message: "Continue anyway?",
1756
+ default: false
1757
+ }
1758
+ ]);
1759
+ if (!proceed) {
1760
+ process.exit(0);
1761
+ }
1762
+ }
1763
+ }
1764
+ } catch {
1765
+ }
1766
+ }
1553
1767
  let displayName;
1554
1768
  let description;
1555
1769
  let author;
@@ -1617,7 +1831,7 @@ async function initCommand(projectName, options = {}) {
1617
1831
  }
1618
1832
  logger.startSpinner("Creating project structure...");
1619
1833
  try {
1620
- fs2__default.default.mkdirSync(projectPath, { recursive: true });
1834
+ fs4__default.default.mkdirSync(projectPath, { recursive: true });
1621
1835
  await copyTemplate(template, projectPath, data);
1622
1836
  await renameThemeInFiles(
1623
1837
  projectPath,
@@ -1626,28 +1840,14 @@ async function initCommand(projectName, options = {}) {
1626
1840
  description,
1627
1841
  author
1628
1842
  );
1629
- const mcpJsonPath = path8__default.default.join(projectPath, ".mcp.json");
1630
- if (fs2__default.default.existsSync(mcpJsonPath)) {
1631
- let mcpContent = fs2__default.default.readFileSync(mcpJsonPath, "utf-8");
1632
- if (figmaApiKey) {
1633
- mcpContent = mcpContent.replace("__FIGMA_API_KEY__", figmaApiKey);
1634
- } else {
1635
- try {
1636
- const mcpJson = JSON.parse(mcpContent);
1637
- delete mcpJson.mcpServers.figma;
1638
- mcpContent = JSON.stringify(mcpJson, null, 2) + "\n";
1639
- } catch {
1640
- }
1641
- }
1642
- fs2__default.default.writeFileSync(mcpJsonPath, mcpContent, "utf-8");
1643
- }
1843
+ ensureMcpJson(projectPath, figmaApiKey || void 0);
1644
1844
  logger.stopSpinner(true, "Project structure created!");
1645
1845
  if (options.git) {
1646
1846
  logger.startSpinner("Initializing git repository...");
1647
1847
  try {
1648
- child_process.execSync("git init", { cwd: projectPath, stdio: "ignore" });
1649
- child_process.execSync("git add .", { cwd: projectPath, stdio: "ignore" });
1650
- child_process.execSync('git commit -m "Initial commit from onexthm init"', {
1848
+ spawn2__default.default.sync("git", ["init"], { cwd: projectPath, stdio: "ignore" });
1849
+ spawn2__default.default.sync("git", ["add", "."], { cwd: projectPath, stdio: "ignore" });
1850
+ spawn2__default.default.sync("git", ["commit", "-m", "Initial commit from onexthm init"], {
1651
1851
  cwd: projectPath,
1652
1852
  stdio: "ignore"
1653
1853
  });
@@ -1699,16 +1899,16 @@ async function initCommand(projectName, options = {}) {
1699
1899
  logger.error(
1700
1900
  error instanceof Error ? error.message : "Unknown error occurred"
1701
1901
  );
1702
- if (fs2__default.default.existsSync(projectPath)) {
1703
- fs2__default.default.rmSync(projectPath, { recursive: true, force: true });
1902
+ if (fs4__default.default.existsSync(projectPath)) {
1903
+ fs4__default.default.rmSync(projectPath, { recursive: true, force: true });
1704
1904
  }
1705
1905
  process.exit(1);
1706
1906
  }
1707
1907
  }
1708
1908
  async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
1709
- const configPath = path8__default.default.join(projectPath, "theme.config.ts");
1710
- if (fs2__default.default.existsSync(configPath)) {
1711
- let content = fs2__default.default.readFileSync(configPath, "utf-8");
1909
+ const configPath = path10__default.default.join(projectPath, "theme.config.ts");
1910
+ if (fs4__default.default.existsSync(configPath)) {
1911
+ let content = fs4__default.default.readFileSync(configPath, "utf-8");
1712
1912
  content = content.replace(
1713
1913
  /name: "My Simple Theme"/,
1714
1914
  `name: "${displayName}"`
@@ -1717,11 +1917,11 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
1717
1917
  /description: ".*?"/,
1718
1918
  `description: "${description}"`
1719
1919
  );
1720
- fs2__default.default.writeFileSync(configPath, content, "utf-8");
1920
+ fs4__default.default.writeFileSync(configPath, content, "utf-8");
1721
1921
  }
1722
- const pkgPath = path8__default.default.join(projectPath, "package.json");
1723
- if (fs2__default.default.existsSync(pkgPath)) {
1724
- let content = fs2__default.default.readFileSync(pkgPath, "utf-8");
1922
+ const pkgPath = path10__default.default.join(projectPath, "package.json");
1923
+ if (fs4__default.default.existsSync(pkgPath)) {
1924
+ let content = fs4__default.default.readFileSync(pkgPath, "utf-8");
1725
1925
  content = content.replace(
1726
1926
  /@onex-themes\/my-simple/g,
1727
1927
  `@onex-themes/${themeName}`
@@ -1730,7 +1930,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
1730
1930
  /"description": ".*?"/,
1731
1931
  `"description": "${description}"`
1732
1932
  );
1733
- fs2__default.default.writeFileSync(pkgPath, content, "utf-8");
1933
+ fs4__default.default.writeFileSync(pkgPath, content, "utf-8");
1734
1934
  }
1735
1935
  }
1736
1936
 
@@ -1741,10 +1941,10 @@ async function createSectionCommand(name, options) {
1741
1941
  ensureOneXProject();
1742
1942
  if (!options.theme) {
1743
1943
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
1744
- (f) => fs__default.default.existsSync(path8__default.default.join(process.cwd(), f))
1944
+ (f) => fs__default.default.existsSync(path10__default.default.join(process.cwd(), f))
1745
1945
  );
1746
1946
  if (isStandaloneTheme) {
1747
- options.theme = path8__default.default.basename(process.cwd());
1947
+ options.theme = path10__default.default.basename(process.cwd());
1748
1948
  }
1749
1949
  }
1750
1950
  const sectionName = toKebabCase(name);
@@ -1807,35 +2007,35 @@ async function createSectionCommand(name, options) {
1807
2007
  };
1808
2008
  logger.startSpinner("Creating section files...");
1809
2009
  try {
1810
- const themePath = path8__default.default.join(getThemesDir(), themeName);
1811
- const sectionPath = path8__default.default.join(themePath, "sections", sectionName);
2010
+ const themePath = path10__default.default.join(getThemesDir(), themeName);
2011
+ const sectionPath = path10__default.default.join(themePath, "sections", sectionName);
1812
2012
  const schemaContent = generateSectionSchema(data);
1813
2013
  await writeFile(
1814
- path8__default.default.join(sectionPath, `${sectionName}.schema.ts`),
2014
+ path10__default.default.join(sectionPath, `${sectionName}.schema.ts`),
1815
2015
  schemaContent
1816
2016
  );
1817
2017
  if (createTemplate) {
1818
2018
  const templateContent = generateSectionTemplate(data);
1819
2019
  await writeFile(
1820
- path8__default.default.join(sectionPath, `${sectionName}-default.tsx`),
2020
+ path10__default.default.join(sectionPath, `${sectionName}-default.tsx`),
1821
2021
  templateContent
1822
2022
  );
1823
2023
  }
1824
2024
  const indexContent = generateSectionIndex(data, createTemplate);
1825
- await writeFile(path8__default.default.join(sectionPath, "index.ts"), indexContent);
2025
+ await writeFile(path10__default.default.join(sectionPath, "index.ts"), indexContent);
1826
2026
  logger.stopSpinner(true, "Section files created successfully!");
1827
2027
  logger.newLine();
1828
2028
  logger.section("Next steps:");
1829
2029
  logger.log(
1830
- ` 1. Edit schema: ${path8__default.default.relative(process.cwd(), path8__default.default.join(sectionPath, `${sectionName}.schema.ts`))}`
2030
+ ` 1. Edit schema: ${path10__default.default.relative(process.cwd(), path10__default.default.join(sectionPath, `${sectionName}.schema.ts`))}`
1831
2031
  );
1832
2032
  if (createTemplate) {
1833
2033
  logger.log(
1834
- ` 2. Edit template: ${path8__default.default.relative(process.cwd(), path8__default.default.join(sectionPath, `${sectionName}-default.tsx`))}`
2034
+ ` 2. Edit template: ${path10__default.default.relative(process.cwd(), path10__default.default.join(sectionPath, `${sectionName}-default.tsx`))}`
1835
2035
  );
1836
2036
  }
1837
2037
  logger.log(
1838
- ` 3. Add to theme manifest: ${path8__default.default.relative(process.cwd(), path8__default.default.join(themePath, "manifest.ts"))}`
2038
+ ` 3. Add to theme manifest: ${path10__default.default.relative(process.cwd(), path10__default.default.join(themePath, "manifest.ts"))}`
1839
2039
  );
1840
2040
  logger.newLine();
1841
2041
  logger.success("Section created successfully!");
@@ -1983,10 +2183,10 @@ async function createBlockCommand(name, options) {
1983
2183
  ensureOneXProject();
1984
2184
  if (!options.theme) {
1985
2185
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
1986
- (f) => fs__default.default.existsSync(path8__default.default.join(process.cwd(), f))
2186
+ (f) => fs__default.default.existsSync(path10__default.default.join(process.cwd(), f))
1987
2187
  );
1988
2188
  if (isStandaloneTheme) {
1989
- options.theme = path8__default.default.basename(process.cwd());
2189
+ options.theme = path10__default.default.basename(process.cwd());
1990
2190
  }
1991
2191
  }
1992
2192
  const blockName = toKebabCase(name);
@@ -2061,24 +2261,24 @@ async function createBlockCommand(name, options) {
2061
2261
  };
2062
2262
  logger.startSpinner("Creating block files...");
2063
2263
  try {
2064
- const blockPath = scope === "shared" ? path8__default.default.join(getFeaturesDir(), "blocks", blockName) : path8__default.default.join(getThemesDir(), themeName, "blocks", blockName);
2264
+ const blockPath = scope === "shared" ? path10__default.default.join(getFeaturesDir(), "blocks", blockName) : path10__default.default.join(getThemesDir(), themeName, "blocks", blockName);
2065
2265
  const schemaContent = generateBlockSchema(data);
2066
2266
  await writeFile(
2067
- path8__default.default.join(blockPath, `${blockName}.schema.ts`),
2267
+ path10__default.default.join(blockPath, `${blockName}.schema.ts`),
2068
2268
  schemaContent
2069
2269
  );
2070
2270
  const componentContent = generateBlockComponent(data);
2071
- await writeFile(path8__default.default.join(blockPath, `${blockName}.tsx`), componentContent);
2271
+ await writeFile(path10__default.default.join(blockPath, `${blockName}.tsx`), componentContent);
2072
2272
  const indexContent = generateBlockIndex(data);
2073
- await writeFile(path8__default.default.join(blockPath, "index.ts"), indexContent);
2273
+ await writeFile(path10__default.default.join(blockPath, "index.ts"), indexContent);
2074
2274
  logger.stopSpinner(true, "Block files created successfully!");
2075
2275
  logger.newLine();
2076
2276
  logger.section("Next steps:");
2077
2277
  logger.log(
2078
- ` 1. Edit schema: ${path8__default.default.relative(process.cwd(), path8__default.default.join(blockPath, `${blockName}.schema.ts`))}`
2278
+ ` 1. Edit schema: ${path10__default.default.relative(process.cwd(), path10__default.default.join(blockPath, `${blockName}.schema.ts`))}`
2079
2279
  );
2080
2280
  logger.log(
2081
- ` 2. Edit component: ${path8__default.default.relative(process.cwd(), path8__default.default.join(blockPath, `${blockName}.tsx`))}`
2281
+ ` 2. Edit component: ${path10__default.default.relative(process.cwd(), path10__default.default.join(blockPath, `${blockName}.tsx`))}`
2082
2282
  );
2083
2283
  logger.log(
2084
2284
  ` 3. Register in block registry: src/lib/registry/block-registry.ts`
@@ -2256,31 +2456,31 @@ async function createComponentCommand(name, options) {
2256
2456
  };
2257
2457
  logger.startSpinner("Creating component files...");
2258
2458
  try {
2259
- const componentPath = path8__default.default.join(
2459
+ const componentPath = path10__default.default.join(
2260
2460
  getFeaturesDir(),
2261
2461
  "components",
2262
2462
  componentName
2263
2463
  );
2264
2464
  const schemaContent = generateComponentSchema(data);
2265
2465
  await writeFile(
2266
- path8__default.default.join(componentPath, `${componentName}.schema.ts`),
2466
+ path10__default.default.join(componentPath, `${componentName}.schema.ts`),
2267
2467
  schemaContent
2268
2468
  );
2269
2469
  const componentContent = generateComponent(data);
2270
2470
  await writeFile(
2271
- path8__default.default.join(componentPath, `${componentName}.tsx`),
2471
+ path10__default.default.join(componentPath, `${componentName}.tsx`),
2272
2472
  componentContent
2273
2473
  );
2274
2474
  const indexContent = generateComponentIndex(data);
2275
- await writeFile(path8__default.default.join(componentPath, "index.ts"), indexContent);
2475
+ await writeFile(path10__default.default.join(componentPath, "index.ts"), indexContent);
2276
2476
  logger.stopSpinner(true, "Component files created successfully!");
2277
2477
  logger.newLine();
2278
2478
  logger.section("Next steps:");
2279
2479
  logger.log(
2280
- ` 1. Edit schema: ${path8__default.default.relative(process.cwd(), path8__default.default.join(componentPath, `${componentName}.schema.ts`))}`
2480
+ ` 1. Edit schema: ${path10__default.default.relative(process.cwd(), path10__default.default.join(componentPath, `${componentName}.schema.ts`))}`
2281
2481
  );
2282
2482
  logger.log(
2283
- ` 2. Edit component: ${path8__default.default.relative(process.cwd(), path8__default.default.join(componentPath, `${componentName}.tsx`))}`
2483
+ ` 2. Edit component: ${path10__default.default.relative(process.cwd(), path10__default.default.join(componentPath, `${componentName}.tsx`))}`
2284
2484
  );
2285
2485
  logger.log(
2286
2486
  ` 3. Register in component registry: src/lib/registry/component-registry.ts`
@@ -2437,13 +2637,13 @@ async function listSections(themeFilter) {
2437
2637
  return;
2438
2638
  }
2439
2639
  for (const theme of themes) {
2440
- const sectionsDir = path8__default.default.join(getThemesDir(), theme, "sections");
2640
+ const sectionsDir = path10__default.default.join(getThemesDir(), theme, "sections");
2441
2641
  if (!fs__default.default.existsSync(sectionsDir)) {
2442
2642
  continue;
2443
2643
  }
2444
2644
  const sections = fs__default.default.readdirSync(sectionsDir).filter((name) => {
2445
- const sectionPath = path8__default.default.join(sectionsDir, name);
2446
- return fs__default.default.statSync(sectionPath).isDirectory() && fs__default.default.existsSync(path8__default.default.join(sectionPath, "index.ts"));
2645
+ const sectionPath = path10__default.default.join(sectionsDir, name);
2646
+ return fs__default.default.statSync(sectionPath).isDirectory() && fs__default.default.existsSync(path10__default.default.join(sectionPath, "index.ts"));
2447
2647
  });
2448
2648
  if (sections.length > 0) {
2449
2649
  logger.log(chalk4__default.default.cyan(`
@@ -2457,11 +2657,11 @@ async function listSections(themeFilter) {
2457
2657
  }
2458
2658
  async function listBlocks(themeFilter) {
2459
2659
  logger.section("\u{1F9F1} Blocks");
2460
- const sharedBlocksDir = path8__default.default.join(getFeaturesDir(), "blocks");
2660
+ const sharedBlocksDir = path10__default.default.join(getFeaturesDir(), "blocks");
2461
2661
  if (fs__default.default.existsSync(sharedBlocksDir)) {
2462
2662
  const sharedBlocks = fs__default.default.readdirSync(sharedBlocksDir).filter((name) => {
2463
- const blockPath = path8__default.default.join(sharedBlocksDir, name);
2464
- return fs__default.default.statSync(blockPath).isDirectory() && fs__default.default.existsSync(path8__default.default.join(blockPath, "index.ts"));
2663
+ const blockPath = path10__default.default.join(sharedBlocksDir, name);
2664
+ return fs__default.default.statSync(blockPath).isDirectory() && fs__default.default.existsSync(path10__default.default.join(blockPath, "index.ts"));
2465
2665
  });
2466
2666
  if (sharedBlocks.length > 0) {
2467
2667
  logger.log(chalk4__default.default.cyan("\n Shared:"));
@@ -2472,13 +2672,13 @@ async function listBlocks(themeFilter) {
2472
2672
  }
2473
2673
  const themes = themeFilter ? [themeFilter] : listThemes();
2474
2674
  for (const theme of themes) {
2475
- const blocksDir = path8__default.default.join(getThemesDir(), theme, "blocks");
2675
+ const blocksDir = path10__default.default.join(getThemesDir(), theme, "blocks");
2476
2676
  if (!fs__default.default.existsSync(blocksDir)) {
2477
2677
  continue;
2478
2678
  }
2479
2679
  const blocks = fs__default.default.readdirSync(blocksDir).filter((name) => {
2480
- const blockPath = path8__default.default.join(blocksDir, name);
2481
- return fs__default.default.statSync(blockPath).isDirectory() && fs__default.default.existsSync(path8__default.default.join(blockPath, "index.ts"));
2680
+ const blockPath = path10__default.default.join(blocksDir, name);
2681
+ return fs__default.default.statSync(blockPath).isDirectory() && fs__default.default.existsSync(path10__default.default.join(blockPath, "index.ts"));
2482
2682
  });
2483
2683
  if (blocks.length > 0) {
2484
2684
  logger.log(chalk4__default.default.cyan(`
@@ -2492,14 +2692,14 @@ async function listBlocks(themeFilter) {
2492
2692
  }
2493
2693
  async function listComponents() {
2494
2694
  logger.section("\u2699\uFE0F Components");
2495
- const componentsDir = path8__default.default.join(getFeaturesDir(), "components");
2695
+ const componentsDir = path10__default.default.join(getFeaturesDir(), "components");
2496
2696
  if (!fs__default.default.existsSync(componentsDir)) {
2497
2697
  logger.warning("No components directory found");
2498
2698
  return;
2499
2699
  }
2500
2700
  const components = fs__default.default.readdirSync(componentsDir).filter((name) => {
2501
- const componentPath = path8__default.default.join(componentsDir, name);
2502
- return fs__default.default.statSync(componentPath).isDirectory() && fs__default.default.existsSync(path8__default.default.join(componentPath, "index.ts"));
2701
+ const componentPath = path10__default.default.join(componentsDir, name);
2702
+ return fs__default.default.statSync(componentPath).isDirectory() && fs__default.default.existsSync(path10__default.default.join(componentPath, "index.ts"));
2503
2703
  });
2504
2704
  if (components.length === 0) {
2505
2705
  logger.warning("No components found");
@@ -2520,11 +2720,11 @@ async function listThemesInfo() {
2520
2720
  }
2521
2721
  logger.log("");
2522
2722
  for (const theme of themes) {
2523
- const themeDir = path8__default.default.join(getThemesDir(), theme);
2723
+ const themeDir = path10__default.default.join(getThemesDir(), theme);
2524
2724
  const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
2525
2725
  let manifestContent = "";
2526
2726
  for (const candidate of candidates) {
2527
- const candidatePath = path8__default.default.join(themeDir, candidate);
2727
+ const candidatePath = path10__default.default.join(themeDir, candidate);
2528
2728
  if (fs__default.default.existsSync(candidatePath)) {
2529
2729
  manifestContent = fs__default.default.readFileSync(candidatePath, "utf-8");
2530
2730
  break;
@@ -2562,9 +2762,9 @@ async function validateCommand(options) {
2562
2762
  "theme.config.ts",
2563
2763
  "bundle-entry.ts",
2564
2764
  "manifest.ts"
2565
- ].some((f) => fs__default.default.existsSync(path8__default.default.join(process.cwd(), f)));
2765
+ ].some((f) => fs__default.default.existsSync(path10__default.default.join(process.cwd(), f)));
2566
2766
  if (isThemeDir) {
2567
- themeToValidate = path8__default.default.basename(process.cwd());
2767
+ themeToValidate = path10__default.default.basename(process.cwd());
2568
2768
  logger.info(`Validating current theme: ${themeToValidate}`);
2569
2769
  } else {
2570
2770
  logger.error(
@@ -2573,11 +2773,11 @@ async function validateCommand(options) {
2573
2773
  process.exit(1);
2574
2774
  }
2575
2775
  }
2576
- const themePath = path8__default.default.join(getThemesDir(), themeToValidate);
2776
+ const themePath = path10__default.default.join(getThemesDir(), themeToValidate);
2577
2777
  logger.startSpinner("Running validation checks...");
2578
2778
  const entryFiles = ["manifest.ts", "theme.config.ts", "bundle-entry.ts"];
2579
2779
  const foundEntry = entryFiles.find(
2580
- (f) => fs__default.default.existsSync(path8__default.default.join(themePath, f))
2780
+ (f) => fs__default.default.existsSync(path10__default.default.join(themePath, f))
2581
2781
  );
2582
2782
  if (!foundEntry) {
2583
2783
  issues.push({
@@ -2587,7 +2787,7 @@ async function validateCommand(options) {
2587
2787
  });
2588
2788
  } else if (foundEntry === "manifest.ts") {
2589
2789
  const manifestContent = fs__default.default.readFileSync(
2590
- path8__default.default.join(themePath, foundEntry),
2790
+ path10__default.default.join(themePath, foundEntry),
2591
2791
  "utf-8"
2592
2792
  );
2593
2793
  if (!manifestContent.includes("export const") && !manifestContent.includes("export default") && !manifestContent.includes("export interface")) {
@@ -2598,7 +2798,7 @@ async function validateCommand(options) {
2598
2798
  });
2599
2799
  }
2600
2800
  }
2601
- const configPath = path8__default.default.join(themePath, "theme.config.ts");
2801
+ const configPath = path10__default.default.join(themePath, "theme.config.ts");
2602
2802
  if (!fs__default.default.existsSync(configPath)) {
2603
2803
  issues.push({
2604
2804
  type: "warning",
@@ -2606,7 +2806,7 @@ async function validateCommand(options) {
2606
2806
  message: "Theme config file not found (recommended)"
2607
2807
  });
2608
2808
  }
2609
- const indexPath = path8__default.default.join(themePath, "index.ts");
2809
+ const indexPath = path10__default.default.join(themePath, "index.ts");
2610
2810
  if (!fs__default.default.existsSync(indexPath)) {
2611
2811
  issues.push({
2612
2812
  type: "warning",
@@ -2614,7 +2814,7 @@ async function validateCommand(options) {
2614
2814
  message: "Index file not found (recommended)"
2615
2815
  });
2616
2816
  }
2617
- const sectionsDir = path8__default.default.join(themePath, "sections");
2817
+ const sectionsDir = path10__default.default.join(themePath, "sections");
2618
2818
  if (!fs__default.default.existsSync(sectionsDir)) {
2619
2819
  issues.push({
2620
2820
  type: "warning",
@@ -2623,16 +2823,16 @@ async function validateCommand(options) {
2623
2823
  });
2624
2824
  } else {
2625
2825
  const sections = fs__default.default.readdirSync(sectionsDir).filter(
2626
- (name) => fs__default.default.statSync(path8__default.default.join(sectionsDir, name)).isDirectory()
2826
+ (name) => fs__default.default.statSync(path10__default.default.join(sectionsDir, name)).isDirectory()
2627
2827
  );
2628
2828
  for (const sectionName of sections) {
2629
- const sectionPath = path8__default.default.join(sectionsDir, sectionName);
2630
- const schemaFile = path8__default.default.join(sectionPath, `${sectionName}.schema.ts`);
2631
- const defaultTemplate = path8__default.default.join(
2829
+ const sectionPath = path10__default.default.join(sectionsDir, sectionName);
2830
+ const schemaFile = path10__default.default.join(sectionPath, `${sectionName}.schema.ts`);
2831
+ const defaultTemplate = path10__default.default.join(
2632
2832
  sectionPath,
2633
2833
  `${sectionName}-default.tsx`
2634
2834
  );
2635
- const indexFile = path8__default.default.join(sectionPath, "index.ts");
2835
+ const indexFile = path10__default.default.join(sectionPath, "index.ts");
2636
2836
  if (!fs__default.default.existsSync(schemaFile)) {
2637
2837
  issues.push({
2638
2838
  type: "error",
@@ -2656,14 +2856,14 @@ async function validateCommand(options) {
2656
2856
  }
2657
2857
  }
2658
2858
  }
2659
- const blocksDir = path8__default.default.join(themePath, "blocks");
2859
+ const blocksDir = path10__default.default.join(themePath, "blocks");
2660
2860
  if (fs__default.default.existsSync(blocksDir)) {
2661
- const blocks = fs__default.default.readdirSync(blocksDir).filter((name) => fs__default.default.statSync(path8__default.default.join(blocksDir, name)).isDirectory());
2861
+ const blocks = fs__default.default.readdirSync(blocksDir).filter((name) => fs__default.default.statSync(path10__default.default.join(blocksDir, name)).isDirectory());
2662
2862
  for (const blockName of blocks) {
2663
- const blockPath = path8__default.default.join(blocksDir, blockName);
2664
- const schemaFile = path8__default.default.join(blockPath, `${blockName}.schema.ts`);
2665
- const componentFile = path8__default.default.join(blockPath, `${blockName}.tsx`);
2666
- const indexFile = path8__default.default.join(blockPath, "index.ts");
2863
+ const blockPath = path10__default.default.join(blocksDir, blockName);
2864
+ const schemaFile = path10__default.default.join(blockPath, `${blockName}.schema.ts`);
2865
+ const componentFile = path10__default.default.join(blockPath, `${blockName}.tsx`);
2866
+ const indexFile = path10__default.default.join(blockPath, "index.ts");
2667
2867
  if (!fs__default.default.existsSync(schemaFile)) {
2668
2868
  issues.push({
2669
2869
  type: "error",
@@ -2689,13 +2889,13 @@ async function validateCommand(options) {
2689
2889
  }
2690
2890
  if (fs__default.default.existsSync(sectionsDir)) {
2691
2891
  const sections = fs__default.default.readdirSync(sectionsDir).filter(
2692
- (name) => fs__default.default.statSync(path8__default.default.join(sectionsDir, name)).isDirectory()
2892
+ (name) => fs__default.default.statSync(path10__default.default.join(sectionsDir, name)).isDirectory()
2693
2893
  );
2694
2894
  for (const sectionName of sections) {
2695
- const sectionPath = path8__default.default.join(sectionsDir, sectionName);
2895
+ const sectionPath = path10__default.default.join(sectionsDir, sectionName);
2696
2896
  const tsxFiles = fs__default.default.readdirSync(sectionPath).filter((f) => f.endsWith(".tsx") && !f.endsWith(".schema.ts"));
2697
2897
  for (const tsxFile of tsxFiles) {
2698
- const filePath = path8__default.default.join(sectionPath, tsxFile);
2898
+ const filePath = path10__default.default.join(sectionPath, tsxFile);
2699
2899
  const content = fs__default.default.readFileSync(filePath, "utf-8");
2700
2900
  const relPath = `sections/${sectionName}/${tsxFile}`;
2701
2901
  if (!content.includes('"use client"') && !content.includes("'use client'")) {
@@ -2743,23 +2943,46 @@ async function validateCommand(options) {
2743
2943
  }
2744
2944
  }
2745
2945
  }
2746
- const registryPath = path8__default.default.join(themePath, "sections-registry.ts");
2747
- const bundleEntryPath = path8__default.default.join(themePath, "bundle-entry.ts");
2946
+ const registryPath = path10__default.default.join(themePath, "sections-registry.ts");
2947
+ const bundleEntryPath = path10__default.default.join(themePath, "bundle-entry.ts");
2748
2948
  const registryContent = fs__default.default.existsSync(registryPath) ? fs__default.default.readFileSync(registryPath, "utf-8") : fs__default.default.existsSync(bundleEntryPath) ? fs__default.default.readFileSync(bundleEntryPath, "utf-8") : "";
2749
2949
  if (fs__default.default.existsSync(sectionsDir) && registryContent) {
2750
2950
  const sections = fs__default.default.readdirSync(sectionsDir).filter(
2751
- (name) => fs__default.default.statSync(path8__default.default.join(sectionsDir, name)).isDirectory()
2951
+ (name) => fs__default.default.statSync(path10__default.default.join(sectionsDir, name)).isDirectory()
2752
2952
  );
2753
2953
  for (const sectionName of sections) {
2754
2954
  if (!registryContent.includes(`sections/${sectionName}`) && !registryContent.includes(`"${sectionName}"`)) {
2755
2955
  issues.push({
2756
- type: "warning",
2956
+ type: "error",
2757
2957
  file: `sections/${sectionName}/`,
2758
- message: "Section not found in sections-registry.ts or bundle-entry.ts \u2014 may not be included in build"
2958
+ message: "Section not exported in sections-registry.ts or bundle-entry.ts \u2014 will not be included in build"
2759
2959
  });
2760
2960
  }
2761
2961
  }
2762
2962
  }
2963
+ if (fs__default.default.existsSync(sectionsDir)) {
2964
+ const schemaTypes = await loadSchemaTypes(themePath, sectionsDir);
2965
+ for (const { folderName, schemaType } of schemaTypes) {
2966
+ if (schemaType && schemaType !== folderName) {
2967
+ issues.push({
2968
+ type: "error",
2969
+ file: `sections/${folderName}/${folderName}.schema.ts`,
2970
+ message: `Schema type "${schemaType}" doesn't match folder name "${folderName}". Rename folder to "${schemaType}/" or change schema type to "${folderName}".`
2971
+ });
2972
+ }
2973
+ }
2974
+ const pagesDir = path10__default.default.join(themePath, "pages");
2975
+ if (fs__default.default.existsSync(pagesDir)) {
2976
+ const allSchemaTypeSet = new Set(
2977
+ schemaTypes.map((s) => s.schemaType || s.folderName)
2978
+ );
2979
+ const pageIssues = await validatePageSectionTypes(
2980
+ pagesDir,
2981
+ allSchemaTypeSet
2982
+ );
2983
+ issues.push(...pageIssues);
2984
+ }
2985
+ }
2763
2986
  logger.stopSpinner(true, "Validation complete");
2764
2987
  const errors = issues.filter((i) => i.type === "error");
2765
2988
  const warnings = issues.filter((i) => i.type === "warning");
@@ -2798,6 +3021,83 @@ async function validateCommand(options) {
2798
3021
  }
2799
3022
  }
2800
3023
  }
3024
+ async function loadSchemaTypes(themePath, sectionsDir) {
3025
+ const results = [];
3026
+ const sections = fs__default.default.readdirSync(sectionsDir).filter((name) => fs__default.default.statSync(path10__default.default.join(sectionsDir, name)).isDirectory());
3027
+ for (const sectionName of sections) {
3028
+ const schemaFile = path10__default.default.join(
3029
+ sectionsDir,
3030
+ sectionName,
3031
+ `${sectionName}.schema.ts`
3032
+ );
3033
+ if (!fs__default.default.existsSync(schemaFile)) {
3034
+ results.push({ folderName: sectionName, schemaType: null });
3035
+ continue;
3036
+ }
3037
+ const content = fs__default.default.readFileSync(schemaFile, "utf-8");
3038
+ const typeMatch = content.match(/\btype:\s*["']([^"']+)["']/);
3039
+ results.push({
3040
+ folderName: sectionName,
3041
+ schemaType: typeMatch ? typeMatch[1] : null
3042
+ });
3043
+ }
3044
+ return results;
3045
+ }
3046
+ async function validatePageSectionTypes(pagesDir, validTypes) {
3047
+ const issues = [];
3048
+ const files = fs__default.default.readdirSync(pagesDir).filter((f) => f.match(/\.(ts|js)$/));
3049
+ for (const file of files) {
3050
+ const content = fs__default.default.readFileSync(path10__default.default.join(pagesDir, file), "utf-8");
3051
+ const pageName = file.replace(/\.(ts|js)$/, "");
3052
+ const typeMatches = content.matchAll(/\btype:\s*["']([^"']+)["']/g);
3053
+ for (const match of typeMatches) {
3054
+ const sectionType = match[1];
3055
+ if (isFieldType(sectionType)) continue;
3056
+ if (!validTypes.has(sectionType)) {
3057
+ issues.push({
3058
+ type: "error",
3059
+ file: `pages/${file}`,
3060
+ message: `Page "${pageName}" uses section type "${sectionType}" which doesn't exist in sections/`
3061
+ });
3062
+ }
3063
+ }
3064
+ }
3065
+ return issues;
3066
+ }
3067
+ var FIELD_TYPES = /* @__PURE__ */ new Set([
3068
+ "text",
3069
+ "textarea",
3070
+ "richtext",
3071
+ "number",
3072
+ "range",
3073
+ "toggle",
3074
+ "switch",
3075
+ "select",
3076
+ "radio",
3077
+ "checkbox",
3078
+ "color",
3079
+ "image",
3080
+ "video",
3081
+ "url",
3082
+ "link",
3083
+ "icon",
3084
+ "date",
3085
+ "datetime",
3086
+ "collection",
3087
+ "product",
3088
+ "blog",
3089
+ "page",
3090
+ "html",
3091
+ "code",
3092
+ "json",
3093
+ "array",
3094
+ "object",
3095
+ "group",
3096
+ "section"
3097
+ ]);
3098
+ function isFieldType(type) {
3099
+ return FIELD_TYPES.has(type);
3100
+ }
2801
3101
 
2802
3102
  // src/commands/build.ts
2803
3103
  init_logger();
@@ -2808,14 +3108,14 @@ async function buildCommand(options) {
2808
3108
  if (options.theme) {
2809
3109
  themeName = options.theme;
2810
3110
  try {
2811
- const workspaceThemePath = path8__default.default.join(getThemesDir(), themeName);
3111
+ const workspaceThemePath = path10__default.default.join(getThemesDir(), themeName);
2812
3112
  if (fs__default.default.existsSync(workspaceThemePath)) {
2813
3113
  themePath = workspaceThemePath;
2814
3114
  } else {
2815
- themePath = path8__default.default.join(process.cwd(), themeName);
3115
+ themePath = path10__default.default.join(process.cwd(), themeName);
2816
3116
  }
2817
3117
  } catch {
2818
- themePath = path8__default.default.join(process.cwd(), themeName);
3118
+ themePath = path10__default.default.join(process.cwd(), themeName);
2819
3119
  }
2820
3120
  if (!fs__default.default.existsSync(themePath)) {
2821
3121
  logger.error(`Theme "${themeName}" not found.`);
@@ -2826,10 +3126,10 @@ async function buildCommand(options) {
2826
3126
  "theme.config.ts",
2827
3127
  "bundle-entry.ts",
2828
3128
  "manifest.ts"
2829
- ].some((f) => fs__default.default.existsSync(path8__default.default.join(process.cwd(), f)));
3129
+ ].some((f) => fs__default.default.existsSync(path10__default.default.join(process.cwd(), f)));
2830
3130
  if (isThemeDir) {
2831
3131
  themePath = process.cwd();
2832
- themeName = path8__default.default.basename(themePath);
3132
+ themeName = path10__default.default.basename(themePath);
2833
3133
  logger.info(`Building current theme: ${themeName}`);
2834
3134
  } else {
2835
3135
  logger.error(
@@ -2838,7 +3138,7 @@ async function buildCommand(options) {
2838
3138
  process.exit(1);
2839
3139
  }
2840
3140
  }
2841
- const packageJsonPath = path8__default.default.join(themePath, "package.json");
3141
+ const packageJsonPath = path10__default.default.join(themePath, "package.json");
2842
3142
  const hasPkgJson = fs__default.default.existsSync(packageJsonPath);
2843
3143
  if (!hasPkgJson) {
2844
3144
  logger.warning(
@@ -2894,9 +3194,9 @@ async function buildCommand(options) {
2894
3194
  logger.success("\u2713 Theme built successfully!");
2895
3195
  logger.newLine();
2896
3196
  logger.info(`Theme: ${themeName}`);
2897
- const distPath = path8__default.default.join(themePath, "dist");
3197
+ const distPath = path10__default.default.join(themePath, "dist");
2898
3198
  if (fs__default.default.existsSync(distPath)) {
2899
- logger.log(`Output: ${path8__default.default.relative(process.cwd(), distPath)}`);
3199
+ logger.log(`Output: ${path10__default.default.relative(process.cwd(), distPath)}`);
2900
3200
  const files = fs__default.default.readdirSync(distPath);
2901
3201
  logger.log(`Files: ${files.length}`);
2902
3202
  }
@@ -2904,17 +3204,17 @@ async function buildCommand(options) {
2904
3204
  }
2905
3205
  function runCommand(command, args, cwd) {
2906
3206
  return new Promise((resolve) => {
2907
- const proc = child_process.spawn(command, args, {
3207
+ const proc = spawn2__default.default(command, args, {
2908
3208
  cwd,
2909
3209
  stdio: ["pipe", "pipe", "pipe"],
2910
3210
  shell: true
2911
3211
  });
2912
3212
  let stdout = "";
2913
3213
  let stderr = "";
2914
- proc.stdout.on("data", (data) => {
3214
+ proc.stdout?.on("data", (data) => {
2915
3215
  stdout += data.toString();
2916
3216
  });
2917
- proc.stderr.on("data", (data) => {
3217
+ proc.stderr?.on("data", (data) => {
2918
3218
  stderr += data.toString();
2919
3219
  });
2920
3220
  proc.on("close", (code) => {
@@ -2952,7 +3252,7 @@ async function packageCommand(options) {
2952
3252
  let themeName;
2953
3253
  if (options.theme) {
2954
3254
  themeName = options.theme;
2955
- themePath = path8__default.default.join(getThemesDir(), themeName);
3255
+ themePath = path10__default.default.join(getThemesDir(), themeName);
2956
3256
  if (!fs__default.default.existsSync(themePath)) {
2957
3257
  logger.error(`Theme "${themeName}" not found.`);
2958
3258
  process.exit(1);
@@ -2962,10 +3262,10 @@ async function packageCommand(options) {
2962
3262
  "theme.config.ts",
2963
3263
  "bundle-entry.ts",
2964
3264
  "manifest.ts"
2965
- ].some((f) => fs__default.default.existsSync(path8__default.default.join(process.cwd(), f)));
3265
+ ].some((f) => fs__default.default.existsSync(path10__default.default.join(process.cwd(), f)));
2966
3266
  if (isThemeDir) {
2967
3267
  themePath = process.cwd();
2968
- themeName = path8__default.default.basename(themePath);
3268
+ themeName = path10__default.default.basename(themePath);
2969
3269
  logger.info(`Packaging current theme: ${themeName}`);
2970
3270
  } else {
2971
3271
  logger.error(
@@ -2974,7 +3274,7 @@ async function packageCommand(options) {
2974
3274
  process.exit(1);
2975
3275
  }
2976
3276
  }
2977
- const packageJsonPath = path8__default.default.join(themePath, "package.json");
3277
+ const packageJsonPath = path10__default.default.join(themePath, "package.json");
2978
3278
  let version2 = "1.0.0";
2979
3279
  if (fs__default.default.existsSync(packageJsonPath)) {
2980
3280
  const packageJson = await fs__default.default.readJson(packageJsonPath);
@@ -2984,7 +3284,7 @@ async function packageCommand(options) {
2984
3284
  logger.info(`Theme: ${themeName}`);
2985
3285
  logger.info(`Version: ${version2}`);
2986
3286
  logger.newLine();
2987
- const compiledThemePath = path8__default.default.join(
3287
+ const compiledThemePath = path10__default.default.join(
2988
3288
  process.cwd(),
2989
3289
  "themes",
2990
3290
  themeName,
@@ -3018,8 +3318,8 @@ async function packageCommand(options) {
3018
3318
  logger.newLine();
3019
3319
  logger.section("Step 2: Create Package");
3020
3320
  const packageName = options.name || `${themeName}-${version2}`;
3021
- const outputDir = options.output || path8__default.default.join(process.cwd(), "dist");
3022
- const outputPath = path8__default.default.join(outputDir, `${packageName}.zip`);
3321
+ const outputDir = options.output || path10__default.default.join(process.cwd(), "dist");
3322
+ const outputPath = path10__default.default.join(outputDir, `${packageName}.zip`);
3023
3323
  await fs__default.default.ensureDir(outputDir);
3024
3324
  logger.startSpinner("Creating zip archive...");
3025
3325
  try {
@@ -3032,11 +3332,11 @@ async function packageCommand(options) {
3032
3332
  logger.newLine();
3033
3333
  logger.info(`Package: ${packageName}.zip`);
3034
3334
  logger.log(`Size: ${sizeMB} MB`);
3035
- logger.log(`Location: ${path8__default.default.relative(process.cwd(), outputPath)}`);
3335
+ logger.log(`Location: ${path10__default.default.relative(process.cwd(), outputPath)}`);
3036
3336
  logger.newLine();
3037
3337
  logger.section("Next steps:");
3038
3338
  logger.log(
3039
- ` onexthm deploy --package ${path8__default.default.relative(process.cwd(), outputPath)}`
3339
+ ` onexthm deploy --package ${path10__default.default.relative(process.cwd(), outputPath)}`
3040
3340
  );
3041
3341
  } catch (error) {
3042
3342
  logger.stopSpinner(false, "Failed to create package");
@@ -3048,13 +3348,13 @@ async function packageCommand(options) {
3048
3348
  }
3049
3349
  function runCommand2(command, args) {
3050
3350
  return new Promise((resolve) => {
3051
- const proc = child_process.spawn(command, args, {
3351
+ const proc = spawn2__default.default(command, args, {
3052
3352
  cwd: process.cwd(),
3053
3353
  stdio: "pipe",
3054
3354
  shell: true
3055
3355
  });
3056
3356
  let hasError = false;
3057
- proc.stderr.on("data", (data) => {
3357
+ proc.stderr?.on("data", (data) => {
3058
3358
  const message = data.toString();
3059
3359
  if (message.includes("error") || message.includes("Error") || message.includes("ERROR")) {
3060
3360
  hasError = true;
@@ -3094,9 +3394,9 @@ async function deployCommand(options) {
3094
3394
  ensureOneXProject();
3095
3395
  let packagePath;
3096
3396
  if (options.package) {
3097
- packagePath = path8__default.default.resolve(options.package);
3397
+ packagePath = path10__default.default.resolve(options.package);
3098
3398
  } else if (options.theme) {
3099
- const distDir = path8__default.default.join(process.cwd(), "dist");
3399
+ const distDir = path10__default.default.join(process.cwd(), "dist");
3100
3400
  if (!fs__default.default.existsSync(distDir)) {
3101
3401
  logger.error("No dist/ directory found. Run 'onexthm package' first.");
3102
3402
  process.exit(1);
@@ -3111,7 +3411,7 @@ async function deployCommand(options) {
3111
3411
  process.exit(1);
3112
3412
  }
3113
3413
  packageFiles.sort().reverse();
3114
- packagePath = path8__default.default.join(distDir, packageFiles[0]);
3414
+ packagePath = path10__default.default.join(distDir, packageFiles[0]);
3115
3415
  } else {
3116
3416
  logger.error("Either --package or --theme must be specified.");
3117
3417
  logger.info("Examples:");
@@ -3125,11 +3425,11 @@ async function deployCommand(options) {
3125
3425
  }
3126
3426
  const stats = await fs__default.default.stat(packagePath);
3127
3427
  const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
3128
- const fileName = path8__default.default.basename(packagePath);
3428
+ const fileName = path10__default.default.basename(packagePath);
3129
3429
  logger.newLine();
3130
3430
  logger.info(`Package: ${fileName}`);
3131
3431
  logger.log(`Size: ${sizeMB} MB`);
3132
- logger.log(`Path: ${path8__default.default.relative(process.cwd(), packagePath)}`);
3432
+ logger.log(`Path: ${path10__default.default.relative(process.cwd(), packagePath)}`);
3133
3433
  logger.newLine();
3134
3434
  const apiUrl = options.apiUrl || process.env.ONEX_API_URL || "http://localhost:3001";
3135
3435
  const uploadEndpoint = `${apiUrl}/website-api/themes/upload`;
@@ -3233,11 +3533,11 @@ function getBucketName(env) {
3233
3533
  return environment === "production" ? "theme-s3-bucket" : "theme-s3-bucket";
3234
3534
  }
3235
3535
  async function findCompiledThemeDir(themeId, version2) {
3236
- const searchPaths = [path8__default.default.resolve(process.cwd(), "dist")];
3536
+ const searchPaths = [path10__default.default.resolve(process.cwd(), "dist")];
3237
3537
  for (const dir of searchPaths) {
3238
3538
  if (await fs__default.default.pathExists(dir)) {
3239
- const hasManifest = await fs__default.default.pathExists(path8__default.default.join(dir, "manifest.json"));
3240
- const hasThemeEntry = await fs__default.default.pathExists(path8__default.default.join(dir, "bundle-entry.js")) || await fs__default.default.pathExists(path8__default.default.join(dir, "theme.config.js")) || await fs__default.default.pathExists(path8__default.default.join(dir, "index.js"));
3539
+ const hasManifest = await fs__default.default.pathExists(path10__default.default.join(dir, "manifest.json"));
3540
+ const hasThemeEntry = await fs__default.default.pathExists(path10__default.default.join(dir, "bundle-entry.js")) || await fs__default.default.pathExists(path10__default.default.join(dir, "theme.config.js")) || await fs__default.default.pathExists(path10__default.default.join(dir, "index.js"));
3241
3541
  if (hasManifest || hasThemeEntry) {
3242
3542
  return dir;
3243
3543
  }
@@ -3246,7 +3546,7 @@ async function findCompiledThemeDir(themeId, version2) {
3246
3546
  return null;
3247
3547
  }
3248
3548
  async function readManifest() {
3249
- const manifestTsPath = path8__default.default.resolve(process.cwd(), "manifest.ts");
3549
+ const manifestTsPath = path10__default.default.resolve(process.cwd(), "manifest.ts");
3250
3550
  if (await fs__default.default.pathExists(manifestTsPath)) {
3251
3551
  try {
3252
3552
  const module = await import(manifestTsPath);
@@ -3255,7 +3555,7 @@ async function readManifest() {
3255
3555
  logger.warning("Failed to import manifest.ts, trying package.json");
3256
3556
  }
3257
3557
  }
3258
- const packageJsonPath = path8__default.default.resolve(process.cwd(), "package.json");
3558
+ const packageJsonPath = path10__default.default.resolve(process.cwd(), "package.json");
3259
3559
  if (await fs__default.default.pathExists(packageJsonPath)) {
3260
3560
  const pkg = await fs__default.default.readJson(packageJsonPath);
3261
3561
  return {
@@ -3289,13 +3589,13 @@ async function findSourceDir(themeId, explicitDir) {
3289
3589
  }
3290
3590
  const searchPaths = [
3291
3591
  process.cwd(),
3292
- path8__default.default.resolve(process.cwd(), `../../themes/${themeId}`),
3293
- path8__default.default.resolve(process.cwd(), `../themes/${themeId}`)
3592
+ path10__default.default.resolve(process.cwd(), `../../themes/${themeId}`),
3593
+ path10__default.default.resolve(process.cwd(), `../themes/${themeId}`)
3294
3594
  ];
3295
3595
  const markers = ["theme.config.ts", "bundle-entry.ts"];
3296
3596
  for (const dir of searchPaths) {
3297
3597
  for (const marker of markers) {
3298
- if (await fs__default.default.pathExists(path8__default.default.join(dir, marker))) {
3598
+ if (await fs__default.default.pathExists(path10__default.default.join(dir, marker))) {
3299
3599
  return dir;
3300
3600
  }
3301
3601
  }
@@ -3346,8 +3646,8 @@ async function uploadCommand(options) {
3346
3646
  }
3347
3647
  spinner.succeed(`Found compiled theme at: ${compiledDir}`);
3348
3648
  spinner.start("Creating bundle.zip...");
3349
- const tmpDir = os3__default.default.tmpdir();
3350
- const bundleZipPath = path8__default.default.join(tmpDir, `${themeId}-${version2}-bundle.zip`);
3649
+ const tmpDir = os__default.default.tmpdir();
3650
+ const bundleZipPath = path10__default.default.join(tmpDir, `${themeId}-${version2}-bundle.zip`);
3351
3651
  await createZipFromDir(compiledDir, bundleZipPath);
3352
3652
  const bundleZipBuffer = await fs__default.default.readFile(bundleZipPath);
3353
3653
  const bundleSizeMB = (bundleZipBuffer.length / 1024 / 1024).toFixed(2);
@@ -3401,7 +3701,7 @@ async function uploadCommand(options) {
3401
3701
  if (sourceDir) {
3402
3702
  spinner.succeed(`Found source at: ${sourceDir}`);
3403
3703
  spinner.start("Creating source.zip...");
3404
- const sourceZipPath = path8__default.default.join(
3704
+ const sourceZipPath = path10__default.default.join(
3405
3705
  tmpDir,
3406
3706
  `${themeId}-${version2}-source.zip`
3407
3707
  );
@@ -3535,8 +3835,8 @@ async function resolveLatestVersion(s3Client, bucket, themeId) {
3535
3835
  async function createCompatibilityFiles(outputDir, manifest) {
3536
3836
  const entryFile = manifest.output?.entry || "bundle-entry.js";
3537
3837
  if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
3538
- const hashedPath = path8__default.default.join(outputDir, entryFile);
3539
- const stablePath = path8__default.default.join(outputDir, "bundle-entry.js");
3838
+ const hashedPath = path10__default.default.join(outputDir, entryFile);
3839
+ const stablePath = path10__default.default.join(outputDir, "bundle-entry.js");
3540
3840
  if (await fs__default.default.pathExists(hashedPath)) {
3541
3841
  await fs__default.default.copy(hashedPath, stablePath);
3542
3842
  const mapPath = hashedPath + ".map";
@@ -3545,13 +3845,13 @@ async function createCompatibilityFiles(outputDir, manifest) {
3545
3845
  }
3546
3846
  }
3547
3847
  }
3548
- const sectionsRegistryPath = path8__default.default.join(outputDir, "sections-registry.js");
3848
+ const sectionsRegistryPath = path10__default.default.join(outputDir, "sections-registry.js");
3549
3849
  const content = `// Re-export all sections from bundle-entry
3550
3850
  // This file exists to maintain compatibility with the import path
3551
3851
  export * from './bundle-entry.js';
3552
3852
  `;
3553
3853
  await fs__default.default.writeFile(sectionsRegistryPath, content, "utf-8");
3554
- const pkgJsonPath = path8__default.default.join(outputDir, "package.json");
3854
+ const pkgJsonPath = path10__default.default.join(outputDir, "package.json");
3555
3855
  await fs__default.default.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
3556
3856
  }
3557
3857
  function showDownloadFailureHelp(themeId, bucket) {
@@ -3613,6 +3913,18 @@ async function downloadCommand(options) {
3613
3913
  spinner.succeed(
3614
3914
  `Resolved latest version: ${chalk4__default.default.cyan(resolvedVersion)}`
3615
3915
  );
3916
+ const isCI = !!(process.env.CI || process.env.GITHUB_ACTIONS || process.env.VERCEL);
3917
+ if (isCI) {
3918
+ console.log(
3919
+ chalk4__default.default.yellow(
3920
+ `
3921
+ Warning: Resolved "latest" to ${resolvedVersion} in CI environment.
3922
+ For production builds, pin to a specific version:
3923
+ THEME_VERSION=${resolvedVersion}
3924
+ `
3925
+ )
3926
+ );
3927
+ }
3616
3928
  }
3617
3929
  spinner.start(
3618
3930
  `Downloading bundle.zip for ${themeId}@${resolvedVersion}...`
@@ -3634,7 +3946,7 @@ async function downloadCommand(options) {
3634
3946
  zip.extractAllTo(outputDir, true);
3635
3947
  const entries = zip.getEntries().filter((e) => !e.isDirectory);
3636
3948
  spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
3637
- const manifestPath = path8__default.default.join(outputDir, "manifest.json");
3949
+ const manifestPath = path10__default.default.join(outputDir, "manifest.json");
3638
3950
  const manifest = await fs__default.default.readJson(manifestPath);
3639
3951
  await createCompatibilityFiles(outputDir, manifest);
3640
3952
  console.log();
@@ -3734,10 +4046,9 @@ async function resolveLatestVersion2(s3Client, bucket, themeId) {
3734
4046
  }
3735
4047
  function runInstall(cwd) {
3736
4048
  return new Promise((resolve) => {
3737
- const proc = child_process.spawn("pnpm", ["install"], {
4049
+ const proc = spawn2__default.default("pnpm", ["install"], {
3738
4050
  cwd,
3739
- stdio: "inherit",
3740
- shell: true
4051
+ stdio: "inherit"
3741
4052
  });
3742
4053
  proc.on("close", (code) => resolve(code === 0));
3743
4054
  proc.on("error", () => resolve(false));
@@ -3768,7 +4079,7 @@ async function renameTheme(themeDir, oldName, newName) {
3768
4079
  const oldPrefix = `${oldName}-`;
3769
4080
  const newPrefix = `${newName}-`;
3770
4081
  const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3771
- const pkgPath = path8__default.default.join(themeDir, "package.json");
4082
+ const pkgPath = path10__default.default.join(themeDir, "package.json");
3772
4083
  if (await fs__default.default.pathExists(pkgPath)) {
3773
4084
  const pkg = await fs__default.default.readJson(pkgPath);
3774
4085
  pkg.name = `@onex-themes/${newName}`;
@@ -3784,7 +4095,7 @@ async function renameTheme(themeDir, oldName, newName) {
3784
4095
  }
3785
4096
  await fs__default.default.writeJson(pkgPath, pkg, { spaces: 2 });
3786
4097
  }
3787
- const configPath = path8__default.default.join(themeDir, "theme.config.ts");
4098
+ const configPath = path10__default.default.join(themeDir, "theme.config.ts");
3788
4099
  if (await fs__default.default.pathExists(configPath)) {
3789
4100
  let content = await fs__default.default.readFile(configPath, "utf-8");
3790
4101
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
@@ -3794,7 +4105,7 @@ async function renameTheme(themeDir, oldName, newName) {
3794
4105
  );
3795
4106
  await fs__default.default.writeFile(configPath, content);
3796
4107
  }
3797
- const layoutPath = path8__default.default.join(themeDir, "theme.layout.ts");
4108
+ const layoutPath = path10__default.default.join(themeDir, "theme.layout.ts");
3798
4109
  if (await fs__default.default.pathExists(layoutPath)) {
3799
4110
  let content = await fs__default.default.readFile(layoutPath, "utf-8");
3800
4111
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
@@ -3807,7 +4118,7 @@ async function renameTheme(themeDir, oldName, newName) {
3807
4118
  const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3808
4119
  const tsFiles = await glob.glob("**/*.ts", { cwd: themeDir, nodir: true });
3809
4120
  for (const file of tsFiles) {
3810
- const filePath = path8__default.default.join(themeDir, file);
4121
+ const filePath = path10__default.default.join(themeDir, file);
3811
4122
  let content = await fs__default.default.readFile(filePath, "utf-8");
3812
4123
  const original = content;
3813
4124
  content = content.replace(
@@ -3836,7 +4147,7 @@ async function cloneCommand(themeName, options) {
3836
4147
  const spinner = ora__default.default("Initializing clone...").start();
3837
4148
  try {
3838
4149
  const bucket = options.bucket || getBucketName3(options.environment);
3839
- const outputDir = options.output || path8__default.default.resolve(process.cwd(), newName);
4150
+ const outputDir = options.output || path10__default.default.resolve(process.cwd(), newName);
3840
4151
  const s3Client = getS3Client3();
3841
4152
  if (await fs__default.default.pathExists(outputDir)) {
3842
4153
  spinner.fail(chalk4__default.default.red(`Directory already exists: ${outputDir}`));
@@ -3891,7 +4202,7 @@ async function cloneCommand(themeName, options) {
3891
4202
  spinner.succeed(
3892
4203
  `Renamed theme: ${chalk4__default.default.gray(themeName)} \u2192 ${chalk4__default.default.cyan(newName)}`
3893
4204
  );
3894
- const envExamplePath = path8__default.default.join(outputDir, ".env.example");
4205
+ const envExamplePath = path10__default.default.join(outputDir, ".env.example");
3895
4206
  if (!await fs__default.default.pathExists(envExamplePath)) {
3896
4207
  await fs__default.default.writeFile(
3897
4208
  envExamplePath,
@@ -3904,32 +4215,18 @@ async function cloneCommand(themeName, options) {
3904
4215
  ].join("\n")
3905
4216
  );
3906
4217
  }
3907
- const mcpJsonPath = path8__default.default.join(outputDir, ".mcp.json");
3908
- if (await fs__default.default.pathExists(mcpJsonPath)) {
3909
- const { default: inquirerMod } = await import('inquirer');
3910
- const { figmaApiKey } = await inquirerMod.prompt([
3911
- {
3912
- type: "password",
3913
- name: "figmaApiKey",
3914
- message: "Figma API Key (optional, for Figma-to-code MCP \u2014 press Enter to skip):"
3915
- }
3916
- ]);
3917
- let mcpContent = await fs__default.default.readFile(mcpJsonPath, "utf-8");
3918
- if (figmaApiKey) {
3919
- mcpContent = mcpContent.replace("__FIGMA_API_KEY__", figmaApiKey);
3920
- } else {
3921
- try {
3922
- const mcpJson = JSON.parse(mcpContent);
3923
- delete mcpJson.mcpServers?.figma;
3924
- mcpContent = JSON.stringify(mcpJson, null, 2) + "\n";
3925
- } catch {
3926
- }
4218
+ const { default: inquirerMod } = await import('inquirer');
4219
+ const { figmaApiKey } = await inquirerMod.prompt([
4220
+ {
4221
+ type: "password",
4222
+ name: "figmaApiKey",
4223
+ message: "Figma API Key (optional, for Figma-to-code MCP \u2014 press Enter to skip):"
3927
4224
  }
3928
- await fs__default.default.writeFile(mcpJsonPath, mcpContent, "utf-8");
3929
- }
4225
+ ]);
4226
+ ensureMcpJson(outputDir, figmaApiKey || void 0);
3930
4227
  if (options.install !== false) {
3931
4228
  const hasPkgJson = await fs__default.default.pathExists(
3932
- path8__default.default.join(outputDir, "package.json")
4229
+ path10__default.default.join(outputDir, "package.json")
3933
4230
  );
3934
4231
  if (hasPkgJson) {
3935
4232
  spinner.start("Installing dependencies...");
@@ -3956,9 +4253,10 @@ async function cloneCommand(themeName, options) {
3956
4253
  console.log(chalk4__default.default.cyan(" Files: ") + chalk4__default.default.white(entries.length));
3957
4254
  console.log();
3958
4255
  console.log(chalk4__default.default.cyan("Next steps:"));
3959
- console.log(chalk4__default.default.gray(` cd ${path8__default.default.relative(process.cwd(), outputDir)}`));
4256
+ console.log(chalk4__default.default.gray(` cd ${path10__default.default.relative(process.cwd(), outputDir)}`));
4257
+ const copyCmd = process.platform === "win32" ? "copy .env.example .env" : "cp .env.example .env";
3960
4258
  console.log(
3961
- chalk4__default.default.gray(" cp .env.example .env # then add your Company ID")
4259
+ chalk4__default.default.gray(` ${copyCmd} # then add your Company ID`)
3962
4260
  );
3963
4261
  if (options.install === false) {
3964
4262
  console.log(chalk4__default.default.gray(" pnpm install"));
@@ -3991,7 +4289,7 @@ var MIME_TYPES = {
3991
4289
  };
3992
4290
  function createDevServer(options) {
3993
4291
  const clients = /* @__PURE__ */ new Set();
3994
- const themeDataPath = path8__default.default.join(options.distDir, "theme-data.json");
4292
+ const themeDataPath = path10__default.default.join(options.distDir, "theme-data.json");
3995
4293
  const server = http__default.default.createServer((req, res) => {
3996
4294
  res.setHeader("Access-Control-Allow-Origin", "*");
3997
4295
  res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
@@ -4017,8 +4315,8 @@ function createDevServer(options) {
4017
4315
  if (pathname.startsWith("/_assets/")) {
4018
4316
  const parts = pathname.replace(/^\/_assets\//, "").split("/");
4019
4317
  const assetSubpath = parts.slice(1).join("/");
4020
- const assetPath = path8__default.default.join(options.themePath, "assets", assetSubpath);
4021
- if (!assetPath.startsWith(path8__default.default.join(options.themePath, "assets"))) {
4318
+ const assetPath = path10__default.default.join(options.themePath, "assets", assetSubpath);
4319
+ if (!assetPath.startsWith(path10__default.default.join(options.themePath, "assets"))) {
4022
4320
  res.writeHead(403);
4023
4321
  res.end("Forbidden");
4024
4322
  return;
@@ -4029,8 +4327,8 @@ function createDevServer(options) {
4029
4327
  if (pathname.startsWith("/themes/")) {
4030
4328
  const match = pathname.match(/^\/themes\/[^/]+\/assets\/(.+)/);
4031
4329
  if (match) {
4032
- const assetPath = path8__default.default.join(options.themePath, "assets", match[1]);
4033
- if (!assetPath.startsWith(path8__default.default.join(options.themePath, "assets"))) {
4330
+ const assetPath = path10__default.default.join(options.themePath, "assets", match[1]);
4331
+ if (!assetPath.startsWith(path10__default.default.join(options.themePath, "assets"))) {
4034
4332
  res.writeHead(403);
4035
4333
  res.end("Forbidden");
4036
4334
  return;
@@ -4044,26 +4342,26 @@ function createDevServer(options) {
4044
4342
  const segments = subpath.split("/");
4045
4343
  let assetPath;
4046
4344
  if (segments[0] === options.themeName || segments[0] === options.themeName.replace(/^my-/, "")) {
4047
- assetPath = path8__default.default.join(
4345
+ assetPath = path10__default.default.join(
4048
4346
  options.themePath,
4049
4347
  "assets",
4050
4348
  segments.slice(1).join("/")
4051
4349
  );
4052
4350
  } else {
4053
- assetPath = path8__default.default.join(options.themePath, "assets", subpath);
4351
+ assetPath = path10__default.default.join(options.themePath, "assets", subpath);
4054
4352
  }
4055
- if (assetPath.startsWith(path8__default.default.join(options.themePath, "assets")) && fs2__default.default.existsSync(assetPath)) {
4353
+ if (assetPath.startsWith(path10__default.default.join(options.themePath, "assets")) && fs4__default.default.existsSync(assetPath)) {
4056
4354
  serveFile(res, assetPath);
4057
4355
  return;
4058
4356
  }
4059
4357
  }
4060
- const filePath = path8__default.default.join(options.distDir, pathname);
4358
+ const filePath = path10__default.default.join(options.distDir, pathname);
4061
4359
  if (!filePath.startsWith(options.distDir)) {
4062
4360
  res.writeHead(403);
4063
4361
  res.end("Forbidden");
4064
4362
  return;
4065
4363
  }
4066
- if (fs2__default.default.existsSync(filePath) && fs2__default.default.statSync(filePath).isFile()) {
4364
+ if (fs4__default.default.existsSync(filePath) && fs4__default.default.statSync(filePath).isFile()) {
4067
4365
  serveFile(res, filePath);
4068
4366
  } else {
4069
4367
  res.writeHead(200, { "Content-Type": "text/html" });
@@ -4095,14 +4393,14 @@ function createDevServer(options) {
4095
4393
  }
4096
4394
  function serveFile(res, filePath) {
4097
4395
  try {
4098
- if (!fs2__default.default.existsSync(filePath)) {
4396
+ if (!fs4__default.default.existsSync(filePath)) {
4099
4397
  res.writeHead(404);
4100
4398
  res.end("Not Found");
4101
4399
  return;
4102
4400
  }
4103
- const ext = path8__default.default.extname(filePath);
4401
+ const ext = path10__default.default.extname(filePath);
4104
4402
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
4105
- const content = fs2__default.default.readFileSync(filePath);
4403
+ const content = fs4__default.default.readFileSync(filePath);
4106
4404
  res.writeHead(200, { "Content-Type": contentType });
4107
4405
  res.end(content);
4108
4406
  } catch {
@@ -4115,7 +4413,7 @@ function generatePreviewHTML(themeName, port, themeDataPath) {
4115
4413
  let fontVarsCSS = "";
4116
4414
  if (themeDataPath) {
4117
4415
  try {
4118
- const themeData = JSON.parse(fs2__default.default.readFileSync(themeDataPath, "utf-8"));
4416
+ const themeData = JSON.parse(fs4__default.default.readFileSync(themeDataPath, "utf-8"));
4119
4417
  const typography = (themeData?.themeConfig || themeData?.theme?.config)?.typography?.fontFamily;
4120
4418
  if (typography) {
4121
4419
  const fontFamilies = /* @__PURE__ */ new Set();
@@ -4203,14 +4501,14 @@ async function devCommand(options) {
4203
4501
  if (options.theme) {
4204
4502
  themeName = options.theme;
4205
4503
  try {
4206
- const workspaceThemePath = path8__default.default.join(getThemesDir(), themeName);
4504
+ const workspaceThemePath = path10__default.default.join(getThemesDir(), themeName);
4207
4505
  if (fs__default.default.existsSync(workspaceThemePath)) {
4208
4506
  themePath = workspaceThemePath;
4209
4507
  } else {
4210
- themePath = path8__default.default.join(process.cwd(), themeName);
4508
+ themePath = path10__default.default.join(process.cwd(), themeName);
4211
4509
  }
4212
4510
  } catch {
4213
- themePath = path8__default.default.join(process.cwd(), themeName);
4511
+ themePath = path10__default.default.join(process.cwd(), themeName);
4214
4512
  }
4215
4513
  if (!fs__default.default.existsSync(themePath)) {
4216
4514
  logger.error(`Theme "${themeName}" not found.`);
@@ -4221,10 +4519,10 @@ async function devCommand(options) {
4221
4519
  "theme.config.ts",
4222
4520
  "bundle-entry.ts",
4223
4521
  "manifest.ts"
4224
- ].some((f) => fs__default.default.existsSync(path8__default.default.join(process.cwd(), f)));
4522
+ ].some((f) => fs__default.default.existsSync(path10__default.default.join(process.cwd(), f)));
4225
4523
  if (isThemeDir) {
4226
4524
  themePath = process.cwd();
4227
- themeName = path8__default.default.basename(themePath);
4525
+ themeName = path10__default.default.basename(themePath);
4228
4526
  } else {
4229
4527
  logger.error(
4230
4528
  "Not in a theme directory and no --theme specified. Run from theme root or use --theme flag."
@@ -4293,9 +4591,9 @@ async function devCommand(options) {
4293
4591
  watcher.close();
4294
4592
  await context2.dispose();
4295
4593
  server.close();
4296
- const shimPath = path8__default.default.join(outputDir, ".process-shim.js");
4594
+ const shimPath = path10__default.default.join(outputDir, ".process-shim.js");
4297
4595
  try {
4298
- await fs7__default.default.unlink(shimPath);
4596
+ await fs9__default.default.unlink(shimPath);
4299
4597
  } catch {
4300
4598
  }
4301
4599
  process.exit(0);
@@ -4304,8 +4602,8 @@ async function devCommand(options) {
4304
4602
 
4305
4603
  // src/commands/config.ts
4306
4604
  init_logger();
4307
- var CONFIG_DIR = path8__default.default.join(os3__default.default.homedir(), ".onexthm");
4308
- var CONFIG_FILE = path8__default.default.join(CONFIG_DIR, ".env");
4605
+ var CONFIG_DIR = path10__default.default.join(os__default.default.homedir(), ".onexthm");
4606
+ var CONFIG_FILE = path10__default.default.join(CONFIG_DIR, ".env");
4309
4607
  var CONFIG_ENTRIES = [
4310
4608
  {
4311
4609
  key: "AWS_ACCESS_KEY_ID",
@@ -4447,122 +4745,6 @@ async function configCommand() {
4447
4745
 
4448
4746
  // src/commands/login.ts
4449
4747
  init_logger();
4450
- var AUTH_DIR = path8__default.default.join(os3__default.default.homedir(), ".onexthm");
4451
- var AUTH_FILE = path8__default.default.join(AUTH_DIR, "auth.json");
4452
- function getApiUrl() {
4453
- return process.env.ONEXTHM_API_URL || process.env.NEXT_PUBLIC_API_URL || "https://platform-dev.onexeos.com";
4454
- }
4455
- async function saveAuthTokens(tokens) {
4456
- await fs__default.default.ensureDir(AUTH_DIR);
4457
- const key = getMachineKey();
4458
- const data = JSON.stringify(tokens);
4459
- const encrypted = encrypt(data, key);
4460
- await fs__default.default.writeFile(AUTH_FILE, encrypted, "utf-8");
4461
- }
4462
- function loadAuthTokens() {
4463
- try {
4464
- if (!fs__default.default.existsSync(AUTH_FILE)) return null;
4465
- const encrypted = fs__default.default.readFileSync(AUTH_FILE, "utf-8");
4466
- const key = getMachineKey();
4467
- const data = decrypt(encrypted, key);
4468
- return JSON.parse(data);
4469
- } catch {
4470
- return null;
4471
- }
4472
- }
4473
- async function clearAuthTokens() {
4474
- try {
4475
- await fs__default.default.remove(AUTH_FILE);
4476
- } catch {
4477
- }
4478
- }
4479
- function isTokenExpired(tokens) {
4480
- return Date.now() / 1e3 > tokens.expiresAt - 60;
4481
- }
4482
- async function getValidTokens() {
4483
- const tokens = loadAuthTokens();
4484
- if (!tokens) return null;
4485
- if (!isTokenExpired(tokens)) return tokens;
4486
- try {
4487
- const apiUrl = getApiUrl();
4488
- const response = await fetch(`${apiUrl}/auth/refresh`, {
4489
- method: "POST",
4490
- headers: { "Content-Type": "application/json" },
4491
- body: JSON.stringify({ refresh_token: tokens.refreshToken })
4492
- });
4493
- if (!response.ok) {
4494
- await clearAuthTokens();
4495
- return null;
4496
- }
4497
- const data = await response.json();
4498
- const body = data.statusCode ? data.body : data;
4499
- const refreshed = {
4500
- ...tokens,
4501
- accessToken: body.AccessToken || tokens.accessToken,
4502
- idToken: body.IdToken || tokens.idToken,
4503
- expiresAt: Math.floor(Date.now() / 1e3) + (body.ExpiresIn || 3600)
4504
- };
4505
- await saveAuthTokens(refreshed);
4506
- return refreshed;
4507
- } catch {
4508
- await clearAuthTokens();
4509
- return null;
4510
- }
4511
- }
4512
- async function authenticatedFetch(url, init) {
4513
- const tokens = await getValidTokens();
4514
- if (!tokens) {
4515
- throw new Error("Not logged in. Run: onexthm login");
4516
- }
4517
- const headers = new Headers(init?.headers);
4518
- headers.set("Authorization", `Bearer ${tokens.idToken}`);
4519
- headers.set("Content-Type", "application/json");
4520
- return fetch(url, { ...init, headers });
4521
- }
4522
- function getMachineKey() {
4523
- let seed;
4524
- if (process.platform === "darwin") {
4525
- seed = `onexthm:${os3__default.default.hostname()}:${os3__default.default.userInfo().username}`;
4526
- } else if (process.platform === "linux") {
4527
- try {
4528
- seed = `onexthm:${fs__default.default.readFileSync("/etc/machine-id", "utf-8").trim()}`;
4529
- } catch {
4530
- seed = `onexthm:${os3__default.default.hostname()}:${os3__default.default.userInfo().username}`;
4531
- }
4532
- } else {
4533
- seed = `onexthm:${os3__default.default.hostname()}:${os3__default.default.userInfo().username}`;
4534
- }
4535
- return crypto2__default.default.createHash("sha256").update(seed).digest();
4536
- }
4537
- function encrypt(text, key) {
4538
- const iv = crypto2__default.default.randomBytes(16);
4539
- const cipher = crypto2__default.default.createCipheriv("aes-256-gcm", key, iv);
4540
- let encrypted = cipher.update(text, "utf-8", "hex");
4541
- encrypted += cipher.final("hex");
4542
- const tag = cipher.getAuthTag();
4543
- return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted}`;
4544
- }
4545
- function decrypt(text, key) {
4546
- const [ivHex, tagHex, encrypted] = text.split(":");
4547
- const iv = Buffer.from(ivHex, "hex");
4548
- const tag = Buffer.from(tagHex, "hex");
4549
- const decipher = crypto2__default.default.createDecipheriv("aes-256-gcm", key, iv);
4550
- decipher.setAuthTag(tag);
4551
- let decrypted = decipher.update(encrypted, "hex", "utf-8");
4552
- decrypted += decipher.final("utf-8");
4553
- return decrypted;
4554
- }
4555
- function parseJwtClaims(idToken) {
4556
- try {
4557
- const payload = idToken.split(".")[1];
4558
- const decoded = Buffer.from(payload, "base64url").toString("utf-8");
4559
- return JSON.parse(decoded);
4560
- } catch {
4561
- return {};
4562
- }
4563
- }
4564
-
4565
- // src/commands/login.ts
4566
4748
  async function loginCommand() {
4567
4749
  logger.header("OneX Theme Developer Login");
4568
4750
  const existing = loadAuthTokens();
@@ -4688,13 +4870,13 @@ async function publishCommand(options) {
4688
4870
  logger.info(`Logged in as: ${tokens.user.email}`);
4689
4871
  let themePath;
4690
4872
  if (options.theme) {
4691
- themePath = path8__default.default.resolve(options.theme);
4873
+ themePath = path10__default.default.resolve(options.theme);
4692
4874
  } else {
4693
4875
  const isThemeDir = [
4694
4876
  "theme.config.ts",
4695
4877
  "bundle-entry.ts",
4696
4878
  "manifest.ts"
4697
- ].some((f) => fs__default.default.existsSync(path8__default.default.join(process.cwd(), f)));
4879
+ ].some((f) => fs__default.default.existsSync(path10__default.default.join(process.cwd(), f)));
4698
4880
  if (isThemeDir) {
4699
4881
  themePath = process.cwd();
4700
4882
  } else {
@@ -4704,14 +4886,31 @@ async function publishCommand(options) {
4704
4886
  process.exit(1);
4705
4887
  }
4706
4888
  }
4707
- const pkgPath = path8__default.default.join(themePath, "package.json");
4889
+ const pkgPath = path10__default.default.join(themePath, "package.json");
4708
4890
  if (!fs__default.default.existsSync(pkgPath)) {
4709
4891
  logger.error("No package.json found in theme directory");
4710
4892
  process.exit(1);
4711
4893
  }
4712
4894
  const pkg = fs__default.default.readJsonSync(pkgPath);
4713
- const themeId = pkg.name?.replace("@onex-themes/", "") || path8__default.default.basename(themePath);
4895
+ const themeId = pkg.name?.replace("@onex-themes/", "") || path10__default.default.basename(themePath);
4896
+ if (options.bump) {
4897
+ const currentVersion = pkg.version || "1.0.0";
4898
+ const newVersion = semver__default.default.inc(currentVersion, options.bump);
4899
+ if (!newVersion) {
4900
+ logger.error(`Failed to bump version from ${currentVersion}`);
4901
+ process.exit(1);
4902
+ }
4903
+ pkg.version = newVersion;
4904
+ fs__default.default.writeJsonSync(pkgPath, pkg, { spaces: 2 });
4905
+ logger.info(`Bumped version: ${currentVersion} -> ${newVersion}`);
4906
+ }
4714
4907
  const version2 = pkg.version || "1.0.0";
4908
+ if (!semver__default.default.valid(version2)) {
4909
+ logger.error(
4910
+ `Invalid version "${version2}" in package.json. Must be valid semver (e.g., 1.0.0)`
4911
+ );
4912
+ process.exit(1);
4913
+ }
4715
4914
  logger.newLine();
4716
4915
  logger.info(`Theme: ${themeId}`);
4717
4916
  logger.info(`Version: ${version2}`);
@@ -4727,7 +4926,11 @@ async function publishCommand(options) {
4727
4926
  themeId,
4728
4927
  name: pkg.displayName || themeId,
4729
4928
  description: pkg.description || "",
4730
- email: tokens.user.email
4929
+ email: tokens.user.email,
4930
+ author: typeof pkg.author === "string" ? pkg.author : pkg.author?.name || tokens.user.name || "",
4931
+ category: pkg.onex?.category || "MINIMAL",
4932
+ tags: pkg.keywords || [],
4933
+ thumbnail_url: pkg.onex?.thumbnail || ""
4731
4934
  })
4732
4935
  }
4733
4936
  );
@@ -4744,6 +4947,38 @@ async function publishCommand(options) {
4744
4947
  logger.error(error instanceof Error ? error.message : "Connection failed");
4745
4948
  process.exit(1);
4746
4949
  }
4950
+ logger.startSpinner("Checking version availability...");
4951
+ try {
4952
+ const checkResponse = await authenticatedFetch(
4953
+ `${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/versions/${encodeURIComponent(version2)}/exists`,
4954
+ { method: "GET" }
4955
+ );
4956
+ const checkData = await checkResponse.json();
4957
+ const checkBody = checkData.statusCode ? checkData.body : checkData;
4958
+ if (checkBody.exists) {
4959
+ logger.stopSpinner(false, "Version already published");
4960
+ const patchVer = semver__default.default.inc(version2, "patch") || "?";
4961
+ const minorVer = semver__default.default.inc(version2, "minor") || "?";
4962
+ const majorVer = semver__default.default.inc(version2, "major") || "?";
4963
+ logger.error(
4964
+ `
4965
+ Version ${version2} of "${themeId}" is already published and cannot be overwritten.
4966
+
4967
+ To publish a new version:
4968
+ 1. Bump version in package.json (e.g., ${version2} -> ${patchVer})
4969
+ 2. Run: onexthm publish
4970
+
4971
+ Or use the --bump flag:
4972
+ onexthm publish --bump patch (${version2} -> ${patchVer})
4973
+ onexthm publish --bump minor (${version2} -> ${minorVer})
4974
+ onexthm publish --bump major (${version2} -> ${majorVer})`
4975
+ );
4976
+ process.exit(1);
4977
+ }
4978
+ logger.stopSpinner(true, `Version ${version2} is available`);
4979
+ } catch (error) {
4980
+ logger.stopSpinner(true, "Version check skipped (endpoint not available)");
4981
+ }
4747
4982
  logger.startSpinner("Building theme...");
4748
4983
  try {
4749
4984
  const { compileStandaloneTheme: compileStandaloneTheme2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
@@ -4789,13 +5024,13 @@ async function publishCommand(options) {
4789
5024
  try {
4790
5025
  const archiver3 = await import('archiver');
4791
5026
  const { createWriteStream } = await import('fs');
4792
- const distDir = path8__default.default.join(themePath, "dist");
5027
+ const distDir = path10__default.default.join(themePath, "dist");
4793
5028
  if (!fs__default.default.existsSync(distDir)) {
4794
5029
  logger.stopSpinner(false, "No dist/ directory");
4795
5030
  logger.error("Build the theme first: onexthm build");
4796
5031
  process.exit(1);
4797
5032
  }
4798
- const bundleZipPath = path8__default.default.join(themePath, "dist", "bundle.zip");
5033
+ const bundleZipPath = path10__default.default.join(themePath, "dist", "bundle.zip");
4799
5034
  await createZip(distDir, bundleZipPath, [
4800
5035
  "bundle.zip",
4801
5036
  "source.zip",
@@ -4820,7 +5055,7 @@ async function publishCommand(options) {
4820
5055
  }
4821
5056
  logger.startSpinner("Uploading source...");
4822
5057
  try {
4823
- const sourceZipPath = path8__default.default.join(themePath, "dist", "source.zip");
5058
+ const sourceZipPath = path10__default.default.join(themePath, "dist", "source.zip");
4824
5059
  await createZip(themePath, sourceZipPath, [
4825
5060
  "node_modules",
4826
5061
  "dist",
@@ -4908,14 +5143,14 @@ async function createZip(sourceDir, outputPath, exclude) {
4908
5143
  try {
4909
5144
  const projectRoot = getProjectRoot();
4910
5145
  dotenv__default.default.config({
4911
- path: path8__default.default.join(projectRoot, ".env.local"),
5146
+ path: path10__default.default.join(projectRoot, ".env.local"),
4912
5147
  quiet: true
4913
5148
  });
4914
- dotenv__default.default.config({ path: path8__default.default.join(projectRoot, ".env"), quiet: true });
5149
+ dotenv__default.default.config({ path: path10__default.default.join(projectRoot, ".env"), quiet: true });
4915
5150
  } catch {
4916
5151
  }
4917
5152
  dotenv__default.default.config({
4918
- path: path8__default.default.join(os3__default.default.homedir(), ".onexthm", ".env"),
5153
+ path: path10__default.default.join(os__default.default.homedir(), ".onexthm", ".env"),
4919
5154
  quiet: true
4920
5155
  });
4921
5156
  var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.js', document.baseURI).href)));
@@ -4975,7 +5210,10 @@ program.command("config").description("Configure OneX CLI credentials (AWS, API
4975
5210
  program.command("login").description("Login to OneX platform").action(loginCommand);
4976
5211
  program.command("logout").description("Logout from OneX platform").action(logoutCommand);
4977
5212
  program.command("whoami").description("Show current logged-in developer").action(whoamiCommand);
4978
- program.command("publish").description("Build, scan, and publish theme to marketplace (requires login)").option("-t, --theme <path>", "Theme directory path").action(publishCommand);
5213
+ program.command("publish").description("Build, scan, and publish theme to marketplace (requires login)").option("-t, --theme <path>", "Theme directory path").option(
5214
+ "--bump <type>",
5215
+ "Auto-bump version before publish (patch|minor|major)"
5216
+ ).action(publishCommand);
4979
5217
  program.configureOutput({
4980
5218
  writeErr: (str) => process.stderr.write(chalk4__default.default.red(str))
4981
5219
  });