@onexapis/cli 1.1.66 → 1.1.70

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.mjs CHANGED
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import chalk4 from 'chalk';
3
3
  import ora from 'ora';
4
- import path11 from 'path';
4
+ import fs3 from 'fs';
5
+ import path13 from 'path';
5
6
  import { glob } from 'glob';
6
- import fs from 'fs-extra';
7
+ import fs8 from 'fs-extra';
7
8
  import crypto from 'crypto';
9
+ import fs11 from 'fs/promises';
8
10
  import * as esbuild from 'esbuild';
9
- import fs9 from 'fs/promises';
10
11
  import { createRequire } from 'module';
11
12
  import http from 'http';
12
- import fs3 from 'fs';
13
13
  import { WebSocketServer, WebSocket } from 'ws';
14
14
  import os from 'os';
15
15
  import dotenv from 'dotenv';
16
16
  import ejs from 'ejs';
17
17
  import { execSync, spawn } from 'child_process';
18
- import { Command } from 'commander';
18
+ import { Command, Option } from 'commander';
19
19
  import inquirer from 'inquirer';
20
20
  import archiver from 'archiver';
21
21
  import FormData from 'form-data';
@@ -89,6 +89,13 @@ var init_logger = __esm({
89
89
  logger = new Logger();
90
90
  }
91
91
  });
92
+ function isNextjsProject(dir) {
93
+ return fs3.existsSync(path13.join(dir, "next.config.ts")) || fs3.existsSync(path13.join(dir, "next.config.js")) || fs3.existsSync(path13.join(dir, "next.config.mjs"));
94
+ }
95
+ var init_detect_nextjs = __esm({
96
+ "src/utils/detect-nextjs.ts"() {
97
+ }
98
+ });
92
99
  function sortedCopy(value) {
93
100
  if (Array.isArray(value)) {
94
101
  return value.map((v) => sortedCopy(v));
@@ -171,7 +178,7 @@ async function extractSchemas(themePath) {
171
178
  const sections = {};
172
179
  for (const file of schemaFiles) {
173
180
  try {
174
- const mod = await jiti.import(path11.join(themePath, file));
181
+ const mod = await jiti.import(path13.join(themePath, file));
175
182
  const exports$1 = mod;
176
183
  for (const value of Object.values(exports$1)) {
177
184
  if (value && typeof value === "object" && typeof value.type === "string" && Array.isArray(value.settings)) {
@@ -203,24 +210,24 @@ function isVideoAsset(filePath) {
203
210
  return VIDEO_EXTENSIONS.some((ext) => lower.endsWith(ext));
204
211
  }
205
212
  function mimeFor(filename) {
206
- const ext = path11.extname(filename).toLowerCase();
213
+ const ext = path13.extname(filename).toLowerCase();
207
214
  return MIME_MAP[ext] || "application/octet-stream";
208
215
  }
209
216
  async function sha256Prefix(absPath, len) {
210
- const buf = await fs.readFile(absPath);
217
+ const buf = await fs8.readFile(absPath);
211
218
  return crypto.createHash("sha256").update(buf).digest("hex").slice(0, len);
212
219
  }
213
220
  function insertHashIntoName(relPath, hash) {
214
- const dir = path11.posix.dirname(relPath);
215
- const base = path11.posix.basename(relPath);
216
- const ext = path11.posix.extname(base);
221
+ const dir = path13.posix.dirname(relPath);
222
+ const base = path13.posix.basename(relPath);
223
+ const ext = path13.posix.extname(base);
217
224
  const stem = ext ? base.slice(0, -ext.length) : base;
218
225
  const hashed = `${stem}-${hash}${ext}`;
219
226
  return dir === "." ? hashed : `${dir}/${hashed}`;
220
227
  }
221
228
  async function scanThemeAssets(distDir) {
222
- const assetsDir = path11.join(distDir, "theme-assets");
223
- if (!await fs.pathExists(assetsDir)) return [];
229
+ const assetsDir = path13.join(distDir, "theme-assets");
230
+ if (!await fs8.pathExists(assetsDir)) return [];
224
231
  const files = await glob("**/*", {
225
232
  cwd: assetsDir,
226
233
  nodir: true,
@@ -228,10 +235,10 @@ async function scanThemeAssets(distDir) {
228
235
  });
229
236
  const results = [];
230
237
  for (const rel of files) {
231
- const absPath = path11.join(assetsDir, rel);
232
- const stat = await fs.stat(absPath);
238
+ const absPath = path13.join(assetsDir, rel);
239
+ const stat = await fs8.stat(absPath);
233
240
  if (!stat.isFile()) continue;
234
- const originalPath = rel.split(path11.sep).join("/");
241
+ const originalPath = rel.split(path13.sep).join("/");
235
242
  const hash = await sha256Prefix(absPath, HASH_LEN);
236
243
  const hashedPath = insertHashIntoName(originalPath, hash);
237
244
  const contentType = mimeFor(rel);
@@ -289,6 +296,101 @@ var init_scan_theme_assets = __esm({
289
296
  ];
290
297
  }
291
298
  });
299
+ async function scanAppDirectory(themePath) {
300
+ const appDir = path13.join(themePath, "app");
301
+ let pageFiles;
302
+ try {
303
+ pageFiles = await glob("**/page.{tsx,ts,jsx,js}", { cwd: appDir });
304
+ } catch {
305
+ return [];
306
+ }
307
+ if (pageFiles.length === 0) return [];
308
+ const pages = [];
309
+ for (const pageFile of pageFiles) {
310
+ const routePath = deriveRoutePath(pageFile);
311
+ const absPageFile = path13.join(appDir, pageFile);
312
+ let source;
313
+ try {
314
+ source = await fs11.readFile(absPageFile, "utf-8");
315
+ } catch {
316
+ continue;
317
+ }
318
+ const sections = await extractSectionsFromPage(source, themePath);
319
+ pages.push({
320
+ routePath,
321
+ sourceFile: path13.join("app", pageFile),
322
+ sections
323
+ });
324
+ }
325
+ return pages;
326
+ }
327
+ function deriveRoutePath(pageFile) {
328
+ const dir = path13.dirname(pageFile);
329
+ if (dir === ".") return "/";
330
+ return "/" + dir;
331
+ }
332
+ async function extractSectionsFromPage(source, themePath) {
333
+ const importRegex = /import\s+\w+\s+from\s+["'](@\/|\.\.?\/)(components\/[^"']+)["']/g;
334
+ const sections = [];
335
+ const seen = /* @__PURE__ */ new Set();
336
+ for (const match of source.matchAll(importRegex)) {
337
+ const rawImportPath = match[2];
338
+ const componentDir = path13.dirname(rawImportPath);
339
+ const absComponentDir = path13.join(themePath, componentDir);
340
+ if (seen.has(componentDir)) continue;
341
+ seen.add(componentDir);
342
+ const sectionJsonPath = path13.join(absComponentDir, "section.json");
343
+ let sectionJson;
344
+ try {
345
+ const raw = await fs11.readFile(sectionJsonPath, "utf-8");
346
+ sectionJson = JSON.parse(raw);
347
+ } catch {
348
+ continue;
349
+ }
350
+ if (sectionJson.type !== "opaque-react") continue;
351
+ if (!sectionJson.entry) continue;
352
+ sections.push({
353
+ type: "opaque-react",
354
+ name: sectionJson.name ?? path13.basename(componentDir),
355
+ entry: path13.join(componentDir, sectionJson.entry),
356
+ componentDir
357
+ });
358
+ }
359
+ return sections;
360
+ }
361
+ function buildNextjsPagesMap(pages, themeId) {
362
+ const result = {};
363
+ for (const page of pages) {
364
+ const id = page.routePath === "/" ? "home" : page.routePath.replace(/\//g, "-").replace(/^-/, "");
365
+ const makeSectionType = (name) => `${themeId}-${name.toLowerCase().replace(/\s+/g, "-")}`;
366
+ result[id] = {
367
+ id,
368
+ name: id.charAt(0).toUpperCase() + id.slice(1),
369
+ path: page.routePath,
370
+ config: {
371
+ id,
372
+ path: page.routePath,
373
+ sections: page.sections.map((s, i) => ({
374
+ id: `${id}-section-${i}`,
375
+ type: makeSectionType(s.name),
376
+ sectionType: "opaque-react",
377
+ settings: {}
378
+ }))
379
+ },
380
+ sections: page.sections.map((s, i) => ({
381
+ id: `${id}-section-${i}`,
382
+ type: makeSectionType(s.name),
383
+ sectionType: "opaque-react",
384
+ settings: {}
385
+ }))
386
+ };
387
+ }
388
+ return result;
389
+ }
390
+ var init_nextjs_page_scanner = __esm({
391
+ "src/utils/nextjs-page-scanner.ts"() {
392
+ }
393
+ });
292
394
 
293
395
  // src/utils/compile-theme.ts
294
396
  var compile_theme_exports = {};
@@ -304,8 +406,8 @@ async function generateThemeCSS(themePath, outDir) {
304
406
  const tailwindcss = (await import('tailwindcss')).default;
305
407
  const tailwindConfig = {
306
408
  content: [
307
- path11.join(themePath, "sections/**/*.{ts,tsx}"),
308
- path11.join(themePath, "components/**/*.{ts,tsx}")
409
+ path13.join(themePath, "sections/**/*.{ts,tsx}"),
410
+ path13.join(themePath, "components/**/*.{ts,tsx}")
309
411
  ],
310
412
  theme: { extend: {} },
311
413
  plugins: []
@@ -315,7 +417,7 @@ async function generateThemeCSS(themePath, outDir) {
315
417
  inputCSS,
316
418
  { from: void 0 }
317
419
  );
318
- await fs9.writeFile(path11.join(outDir, "bundle.css"), result.css);
420
+ await fs11.writeFile(path13.join(outDir, "bundle.css"), result.css);
319
421
  logger.info("Generated bundle.css");
320
422
  } catch (err) {
321
423
  logger.warning(
@@ -326,12 +428,12 @@ async function generateThemeCSS(themePath, outDir) {
326
428
  async function resolveNodeModulesFile(startDir, relativePath) {
327
429
  let dir = startDir;
328
430
  while (true) {
329
- const candidate = path11.join(dir, "node_modules", relativePath);
431
+ const candidate = path13.join(dir, "node_modules", relativePath);
330
432
  try {
331
- await fs9.access(candidate);
433
+ await fs11.access(candidate);
332
434
  return candidate;
333
435
  } catch {
334
- const parent = path11.dirname(dir);
436
+ const parent = path13.dirname(dir);
335
437
  if (parent === dir) break;
336
438
  dir = parent;
337
439
  }
@@ -355,7 +457,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
355
457
  });
356
458
  for (const file of sourceFiles) {
357
459
  try {
358
- const content = await fs9.readFile(path11.join(sourceDir, file), "utf-8");
460
+ const content = await fs11.readFile(path13.join(sourceDir, file), "utf-8");
359
461
  for (const match of content.matchAll(namespaceImportRegex)) {
360
462
  const subpath = match[1] ? match[1].slice(1) : "";
361
463
  if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
@@ -409,17 +511,17 @@ function createCoreGlobalPlugin(themePath) {
409
511
  const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
410
512
  let distPath = await resolveNodeModulesFile(
411
513
  themePath,
412
- path11.join("@onexapis", "core", "dist", distFileName)
514
+ path13.join("@onexapis", "core", "dist", distFileName)
413
515
  );
414
516
  if (!distPath) {
415
517
  distPath = await resolveNodeModulesFile(
416
518
  __dirname,
417
- path11.join("@onexapis", "core", "dist", distFileName)
519
+ path13.join("@onexapis", "core", "dist", distFileName)
418
520
  );
419
521
  }
420
522
  try {
421
523
  if (!distPath) throw new Error("not found");
422
- const distContent = await fs9.readFile(distPath, "utf-8");
524
+ const distContent = await fs11.readFile(distPath, "utf-8");
423
525
  const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
424
526
  for (const m of exportMatches) {
425
527
  const names = m[1].split(",").map((n) => {
@@ -466,180 +568,6 @@ ${namedExportLines}
466
568
  }
467
569
  };
468
570
  }
469
- function createThemeDepsStubPlugin(themePath) {
470
- return {
471
- name: "theme-deps-stub",
472
- setup(build2) {
473
- const tryResolveOrStub = (filter, namespace) => {
474
- build2.onResolve({ filter }, async (args) => {
475
- if (args.pluginData?.skipStub) return void 0;
476
- try {
477
- const result = await build2.resolve(args.path, {
478
- kind: args.kind,
479
- resolveDir: args.resolveDir || themePath,
480
- importer: args.importer,
481
- namespace: "file",
482
- pluginData: { skipStub: true }
483
- });
484
- if (!result.errors.length) return result;
485
- } catch {
486
- }
487
- try {
488
- const req = createRequire(import.meta.url || __filename);
489
- const resolved = req.resolve(args.path);
490
- if (resolved) return { path: resolved, namespace: "file" };
491
- } catch {
492
- }
493
- return { path: args.path, namespace };
494
- });
495
- };
496
- tryResolveOrStub(/^next\//, "next-stub");
497
- build2.onLoad({ filter: /.*/, namespace: "next-stub" }, (args) => {
498
- const stubs = {
499
- "next/image": `
500
- import React from 'react';
501
- const Image = React.forwardRef((props, ref) => {
502
- const { src, alt, width, height, fill, priority, sizes, quality, placeholder, blurDataURL, onLoad, onError, style, className, ...rest } = props;
503
- const imgSrc = typeof src === 'object' ? src.src : src;
504
- const fillStyle = fill ? { position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: style?.objectFit || 'cover', display: 'block' } : {};
505
- const mergedStyle = { ...fillStyle, ...style };
506
- return React.createElement('img', {
507
- ref, src: imgSrc, alt,
508
- width: fill ? undefined : width, height: fill ? undefined : height,
509
- loading: priority ? 'eager' : 'lazy',
510
- style: Object.keys(mergedStyle).length > 0 ? mergedStyle : undefined,
511
- className, onLoad, onError, ...rest,
512
- });
513
- });
514
- export default Image;
515
- `,
516
- "next/link": `
517
- import React from 'react';
518
- const Link = ({ href, children, ...rest }) => React.createElement('a', { href, ...rest }, children);
519
- export default Link;
520
- `,
521
- "next/navigation": `
522
- export function useRouter() { return { push(u){window.location.href=u}, replace(u){window.location.href=u}, back(){window.history.back()}, forward(){window.history.forward()}, refresh(){window.location.reload()}, prefetch(){} }; }
523
- export function usePathname() { return window.location.pathname; }
524
- export function useSearchParams() { return new URLSearchParams(window.location.search); }
525
- export function useParams() { return {}; }
526
- export function redirect(url) { window.location.href = url; }
527
- export function notFound() { throw new Error('Not Found'); }
528
- `,
529
- "next/headers": `
530
- export function cookies() { return { get(){}, getAll(){ return []; }, set(){}, delete(){}, has(){ return false; } }; }
531
- export function headers() { return new Headers(); }
532
- `
533
- };
534
- return {
535
- contents: stubs[args.path] || "export default {};",
536
- loader: "jsx",
537
- resolveDir: themePath
538
- };
539
- });
540
- const lucideImports = /* @__PURE__ */ new Set();
541
- let lucideThemeScanned = false;
542
- tryResolveOrStub(/^lucide-react/, "lucide-stub");
543
- build2.onLoad({ filter: /.*/, namespace: "lucide-stub" }, async () => {
544
- if (!lucideThemeScanned) {
545
- lucideThemeScanned = true;
546
- try {
547
- const scanned = await scanImportsFromPackage(
548
- themePath,
549
- "lucide-react"
550
- );
551
- for (const names of Object.values(scanned)) {
552
- for (const name of names) lucideImports.add(name);
553
- }
554
- } catch {
555
- }
556
- }
557
- const iconNames = [...lucideImports];
558
- const exports$1 = iconNames.map((n) => `icon as ${n}`).join(", ");
559
- return {
560
- contents: `
561
- const icon = (props) => null;
562
- export { ${exports$1} };
563
- export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true : icon });
564
- `.trim(),
565
- loader: "jsx"
566
- };
567
- });
568
- tryResolveOrStub(/^framer-motion/, "motion-stub");
569
- build2.onLoad({ filter: /.*/, namespace: "motion-stub" }, () => ({
570
- contents: `
571
- import React from 'react';
572
- const handler = { get: (_, name) => {
573
- if (name === '__esModule') return true;
574
- return React.forwardRef((props, ref) => React.createElement(name, { ...props, ref }));
575
- }};
576
- export const motion = new Proxy({}, handler);
577
- export const AnimatePresence = ({ children }) => children || null;
578
- export function useInView() { return true; }
579
- export default { motion, AnimatePresence, useInView };
580
- `.trim(),
581
- loader: "jsx",
582
- resolveDir: themePath
583
- }));
584
- tryResolveOrStub(/^sonner$/, "sonner-stub");
585
- build2.onLoad({ filter: /.*/, namespace: "sonner-stub" }, () => ({
586
- contents: `
587
- export const toast = new Proxy(() => {}, { get: () => () => {} });
588
- export const Toaster = () => null;
589
- export default { toast, Toaster };
590
- `.trim(),
591
- loader: "jsx"
592
- }));
593
- tryResolveOrStub(/^react-hook-form$/, "rhf-stub");
594
- build2.onLoad({ filter: /.*/, namespace: "rhf-stub" }, () => ({
595
- contents: `
596
- export function useForm() {
597
- return {
598
- register: () => ({}),
599
- handleSubmit: (fn) => (e) => { e?.preventDefault?.(); fn({}); },
600
- formState: { errors: {}, isSubmitting: false, isValid: true },
601
- watch: () => undefined,
602
- setValue: () => {},
603
- reset: () => {},
604
- control: {},
605
- };
606
- }
607
- export function useController() { return { field: {}, fieldState: {} }; }
608
- export function useFormContext() { return useForm(); }
609
- `.trim(),
610
- loader: "js"
611
- }));
612
- tryResolveOrStub(/^@hookform\/resolvers/, "hookform-resolvers-stub");
613
- build2.onLoad(
614
- { filter: /.*/, namespace: "hookform-resolvers-stub" },
615
- () => ({
616
- contents: `export function zodResolver() { return () => ({ values: {}, errors: {} }); }`,
617
- loader: "js"
618
- })
619
- );
620
- tryResolveOrStub(/^next-intl$/, "next-intl-stub");
621
- build2.onLoad({ filter: /.*/, namespace: "next-intl-stub" }, () => ({
622
- contents: `
623
- export function useTranslations(ns) {
624
- return (key) => ns ? ns + '.' + key : key;
625
- }
626
- export function useLocale() { return 'en'; }
627
- export function useMessages() { return {}; }
628
- `.trim(),
629
- loader: "js"
630
- }));
631
- tryResolveOrStub(/^zod$/, "zod-stub");
632
- build2.onLoad({ filter: /.*/, namespace: "zod-stub" }, () => ({
633
- contents: `
634
- const schema = () => ({ parse: (v) => v, safeParse: (v) => ({ success: true, data: v }), optional: schema, min: schema, max: schema, email: schema, url: schema, regex: schema, refine: schema, transform: schema });
635
- export const z = { string: schema, number: schema, boolean: schema, object: (s) => ({ ...schema(), shape: s }), array: schema, enum: schema, union: schema, literal: schema, infer: undefined };
636
- export default z;
637
- `.trim(),
638
- loader: "js"
639
- }));
640
- }
641
- };
642
- }
643
571
  async function generateThemeData(themePath, outputDir, themeId) {
644
572
  const { createJiti } = await import('jiti');
645
573
  const jiti = createJiti(import.meta.url);
@@ -648,7 +576,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
648
576
  const pages = {};
649
577
  for (const ext of [".ts", ".js"]) {
650
578
  try {
651
- const mod = await jiti.import(path11.join(themePath, `theme.config${ext}`));
579
+ const mod = await jiti.import(path13.join(themePath, `theme.config${ext}`));
652
580
  themeConfig = mod.default || mod;
653
581
  break;
654
582
  } catch {
@@ -656,20 +584,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
656
584
  }
657
585
  for (const ext of [".ts", ".js"]) {
658
586
  try {
659
- const mod = await jiti.import(path11.join(themePath, `theme.layout${ext}`));
587
+ const mod = await jiti.import(path13.join(themePath, `theme.layout${ext}`));
660
588
  layoutConfig = mod.default || mod;
661
589
  break;
662
590
  } catch {
663
591
  }
664
592
  }
665
593
  const schemas = {};
666
- const sectionsDir = path11.join(themePath, "sections");
594
+ const sectionsDir = path13.join(themePath, "sections");
667
595
  try {
668
- const sectionDirs = await fs9.readdir(sectionsDir);
596
+ const sectionDirs = await fs11.readdir(sectionsDir);
669
597
  for (const dir of sectionDirs) {
670
- const schemaFile = path11.join(sectionsDir, dir, `${dir}.schema.ts`);
598
+ const schemaFile = path13.join(sectionsDir, dir, `${dir}.schema.ts`);
671
599
  try {
672
- await fs9.access(schemaFile);
600
+ await fs11.access(schemaFile);
673
601
  const mod = await jiti.import(schemaFile);
674
602
  for (const [key, value] of Object.entries(mod)) {
675
603
  if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
@@ -681,14 +609,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
681
609
  }
682
610
  } catch {
683
611
  }
684
- const pagesDir = path11.join(themePath, "pages");
612
+ const pagesDir = path13.join(themePath, "pages");
685
613
  try {
686
- const files = await fs9.readdir(pagesDir);
614
+ const files = await fs11.readdir(pagesDir);
687
615
  for (const file of files) {
688
616
  if (!file.match(/\.(ts|js)$/)) continue;
689
617
  const name = file.replace(/\.(ts|js)$/, "");
690
618
  try {
691
- const mod = await jiti.import(path11.join(pagesDir, file));
619
+ const mod = await jiti.import(path13.join(pagesDir, file));
692
620
  const config = mod.default || mod;
693
621
  const sections = (config.sections || []).map((section) => {
694
622
  const schema = schemas[section.type];
@@ -716,8 +644,16 @@ async function generateThemeData(themePath, outputDir, themeId) {
716
644
  }
717
645
  } catch {
718
646
  }
719
- await fs9.writeFile(
720
- path11.join(outputDir, "theme-data.json"),
647
+ if (isNextjsProject(themePath)) {
648
+ const nextjsPages = await scanAppDirectory(themePath);
649
+ if (nextjsPages.length > 0) {
650
+ const nextjsPagesMap = buildNextjsPagesMap(nextjsPages, themeId);
651
+ Object.assign(pages, nextjsPagesMap);
652
+ logger.info(`Scanned ${nextjsPages.length} Next.js app/ pages`);
653
+ }
654
+ }
655
+ await fs11.writeFile(
656
+ path13.join(outputDir, "theme-data.json"),
721
657
  JSON.stringify(
722
658
  {
723
659
  themeId,
@@ -740,22 +676,22 @@ async function generateThemeData(themePath, outputDir, themeId) {
740
676
  logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
741
677
  }
742
678
  async function contentHashEntry(outputDir) {
743
- const entryPath = path11.join(outputDir, "bundle-entry.js");
744
- const mapPath = path11.join(outputDir, "bundle-entry.js.map");
679
+ const entryPath = path13.join(outputDir, "bundle-entry.js");
680
+ const mapPath = path13.join(outputDir, "bundle-entry.js.map");
745
681
  let entryContent;
746
682
  try {
747
- entryContent = await fs9.readFile(entryPath, "utf-8");
683
+ entryContent = await fs11.readFile(entryPath, "utf-8");
748
684
  } catch {
749
- const indexPath = path11.join(outputDir, "index.js");
685
+ const indexPath = path13.join(outputDir, "index.js");
750
686
  try {
751
- entryContent = await fs9.readFile(indexPath, "utf-8");
687
+ entryContent = await fs11.readFile(indexPath, "utf-8");
752
688
  } catch {
753
689
  logger.warning("No entry file found in output, skipping content hash");
754
690
  return;
755
691
  }
756
692
  const hash2 = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
757
693
  const hashedName2 = `bundle-entry-${hash2}.js`;
758
- const indexMapPath = path11.join(outputDir, "index.js.map");
694
+ const indexMapPath = path13.join(outputDir, "index.js.map");
759
695
  const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
760
696
  entryContent = entryContent.replace(
761
697
  /\/\/# sourceMappingURL=index\.js\.map/,
@@ -763,18 +699,18 @@ async function contentHashEntry(outputDir) {
763
699
  );
764
700
  const oldFiles2 = await glob("bundle-entry-*.js*", { cwd: outputDir });
765
701
  for (const f of oldFiles2) {
766
- await fs9.unlink(path11.join(outputDir, f));
702
+ await fs11.unlink(path13.join(outputDir, f));
767
703
  }
768
- await fs9.writeFile(path11.join(outputDir, hashedName2), entryContent);
769
- await fs9.unlink(indexPath);
704
+ await fs11.writeFile(path13.join(outputDir, hashedName2), entryContent);
705
+ await fs11.unlink(indexPath);
770
706
  try {
771
- await fs9.unlink(entryPath);
707
+ await fs11.unlink(entryPath);
772
708
  } catch {
773
709
  }
774
- await fs9.writeFile(entryPath, entryContent);
710
+ await fs11.writeFile(entryPath, entryContent);
775
711
  try {
776
- await fs9.access(indexMapPath);
777
- await fs9.rename(indexMapPath, path11.join(outputDir, hashedMapName2));
712
+ await fs11.access(indexMapPath);
713
+ await fs11.rename(indexMapPath, path13.join(outputDir, hashedMapName2));
778
714
  } catch {
779
715
  }
780
716
  logger.info(`Entry hashed: ${hashedName2}`);
@@ -789,17 +725,17 @@ async function contentHashEntry(outputDir) {
789
725
  );
790
726
  const oldFiles = await glob("bundle-entry-*.js*", { cwd: outputDir });
791
727
  for (const f of oldFiles) {
792
- await fs9.unlink(path11.join(outputDir, f));
728
+ await fs11.unlink(path13.join(outputDir, f));
793
729
  }
794
- await fs9.writeFile(path11.join(outputDir, hashedName), entryContent);
730
+ await fs11.writeFile(path13.join(outputDir, hashedName), entryContent);
795
731
  try {
796
- await fs9.unlink(entryPath);
732
+ await fs11.unlink(entryPath);
797
733
  } catch {
798
734
  }
799
- await fs9.writeFile(entryPath, entryContent);
735
+ await fs11.writeFile(entryPath, entryContent);
800
736
  try {
801
- await fs9.access(mapPath);
802
- await fs9.rename(mapPath, path11.join(outputDir, hashedMapName));
737
+ await fs11.access(mapPath);
738
+ await fs11.rename(mapPath, path13.join(outputDir, hashedMapName));
803
739
  } catch {
804
740
  }
805
741
  logger.info(`Entry hashed: ${hashedName}`);
@@ -811,7 +747,7 @@ async function extractDataRequirements(themePath) {
811
747
  const requirements = {};
812
748
  for (const file of schemaFiles) {
813
749
  try {
814
- const mod = await jiti.import(path11.join(themePath, file));
750
+ const mod = await jiti.import(path13.join(themePath, file));
815
751
  const exports$1 = mod;
816
752
  for (const value of Object.values(exports$1)) {
817
753
  if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
@@ -829,8 +765,8 @@ async function extractDataRequirements(themePath) {
829
765
  async function writeGateManifests(themePath, outputDir) {
830
766
  try {
831
767
  const schemas = await extractSchemas(themePath);
832
- await fs9.writeFile(
833
- path11.join(outputDir, "schemas.json"),
768
+ await fs11.writeFile(
769
+ path13.join(outputDir, "schemas.json"),
834
770
  serializeManifest(schemas)
835
771
  );
836
772
  logger.info(
@@ -849,8 +785,8 @@ async function writeGateManifests(themePath, outputDir) {
849
785
  size: e.size,
850
786
  contentType: e.contentType
851
787
  }));
852
- await fs9.writeFile(
853
- path11.join(outputDir, "asset-manifest.json"),
788
+ await fs11.writeFile(
789
+ path13.join(outputDir, "asset-manifest.json"),
854
790
  JSON.stringify({ manifestVersion: 1, assets }, null, 2)
855
791
  );
856
792
  logger.info(`Generated asset-manifest.json (${assets.length} assets)`);
@@ -860,12 +796,71 @@ async function writeGateManifests(themePath, outputDir) {
860
796
  );
861
797
  }
862
798
  }
799
+ async function compileSections(themePath, outputDir) {
800
+ const sectionsDir = path13.join(themePath, "sections");
801
+ let sectionDirs;
802
+ try {
803
+ sectionDirs = await fs11.readdir(sectionsDir);
804
+ } catch {
805
+ return;
806
+ }
807
+ for (const dirName of sectionDirs) {
808
+ const sectionSrc = path13.join(sectionsDir, dirName);
809
+ const sectionOut = path13.join(outputDir, "sections", dirName);
810
+ let section = null;
811
+ try {
812
+ const raw = await fs11.readFile(
813
+ path13.join(sectionSrc, "section.manifest.json"),
814
+ "utf-8"
815
+ );
816
+ section = JSON.parse(raw);
817
+ } catch {
818
+ continue;
819
+ }
820
+ switch (section.type) {
821
+ case "editable":
822
+ case "opaque-react":
823
+ break;
824
+ case "html": {
825
+ await fs11.mkdir(sectionOut, { recursive: true });
826
+ const htmlSrc = path13.join(sectionSrc, section.html);
827
+ let htmlContent = await fs11.readFile(htmlSrc, "utf-8");
828
+ htmlContent = htmlContent.replace(
829
+ /<script[^>]+src=["']https?:\/\/[^"']*["'][^>]*><\/script>/gi,
830
+ ""
831
+ );
832
+ await fs11.writeFile(path13.join(sectionOut, path13.basename(section.html)), htmlContent);
833
+ if (section.css) {
834
+ await fs11.copyFile(
835
+ path13.join(sectionSrc, section.css),
836
+ path13.join(sectionOut, path13.basename(section.css))
837
+ );
838
+ }
839
+ break;
840
+ }
841
+ case "iframe":
842
+ break;
843
+ case "webcomponent": {
844
+ await fs11.mkdir(sectionOut, { recursive: true });
845
+ await fs11.copyFile(
846
+ path13.join(sectionSrc, section.bundle),
847
+ path13.join(sectionOut, path13.basename(section.bundle))
848
+ );
849
+ break;
850
+ }
851
+ default:
852
+ throw new Error(
853
+ `Unknown section type. Valid types: editable, opaque-react, html, iframe, webcomponent`
854
+ );
855
+ }
856
+ }
857
+ }
863
858
  async function generateManifest(themeName, themePath, outputDir) {
864
859
  let version2 = "1.0.0";
865
860
  let themeId = themeName;
866
861
  try {
867
- const pkgContent = await fs9.readFile(
868
- path11.join(themePath, "package.json"),
862
+ const pkgContent = await fs11.readFile(
863
+ path13.join(themePath, "package.json"),
869
864
  "utf-8"
870
865
  );
871
866
  const pkg = JSON.parse(pkgContent);
@@ -883,7 +878,7 @@ async function generateManifest(themeName, themePath, outputDir) {
883
878
  const dataRequirements = await extractDataRequirements(themePath);
884
879
  let hasThemeConfig = false;
885
880
  try {
886
- await fs9.access(path11.join(themePath, "theme.config.ts"));
881
+ await fs11.access(path13.join(themePath, "theme.config.ts"));
887
882
  hasThemeConfig = true;
888
883
  } catch {
889
884
  }
@@ -924,24 +919,34 @@ async function generateManifest(themeName, themePath, outputDir) {
924
919
  // Section data requirements for server-side prefetching (keyed by section type)
925
920
  dataRequirements
926
921
  };
927
- await fs9.writeFile(
928
- path11.join(outputDir, "manifest.json"),
922
+ await fs11.writeFile(
923
+ path13.join(outputDir, "manifest.json"),
929
924
  JSON.stringify(manifest, null, 2)
930
925
  );
931
926
  }
932
927
  async function compileStandaloneTheme(themePath, themeName) {
933
- const outputDir = path11.join(themePath, "dist");
934
- const bundleEntry = path11.join(themePath, "bundle-entry.ts");
935
- const indexEntry = path11.join(themePath, "index.ts");
928
+ const outputDir = path13.join(themePath, "dist");
929
+ const isNextjs = isNextjsProject(themePath);
930
+ if (isNextjs) {
931
+ logger.info("Detected Next.js project \u2014 using next/* shims");
932
+ }
933
+ const bundleEntry = path13.join(themePath, "bundle-entry.ts");
934
+ const indexEntry = path13.join(themePath, "index.ts");
936
935
  let entryPoint = indexEntry;
937
936
  try {
938
- await fs9.access(bundleEntry);
937
+ await fs11.access(bundleEntry);
939
938
  entryPoint = bundleEntry;
940
939
  } catch {
941
940
  }
942
- const shimPath = path11.join(outputDir, ".process-shim.js");
943
- await fs9.mkdir(outputDir, { recursive: true });
944
- await fs9.writeFile(shimPath, PROCESS_SHIM);
941
+ const shimPath = path13.join(outputDir, ".process-shim.js");
942
+ await fs11.mkdir(outputDir, { recursive: true });
943
+ await fs11.writeFile(shimPath, PROCESS_SHIM);
944
+ const plugins = [
945
+ reactGlobalPlugin,
946
+ reactQueryGlobalPlugin,
947
+ createCoreGlobalPlugin(themePath)
948
+ ];
949
+ if (isNextjs) plugins.unshift(nextShimPlugin);
945
950
  const buildOptions = {
946
951
  entryPoints: [entryPoint],
947
952
  bundle: true,
@@ -953,12 +958,7 @@ async function compileStandaloneTheme(themePath, themeName) {
953
958
  banner: {
954
959
  js: '"use client";'
955
960
  },
956
- plugins: [
957
- reactGlobalPlugin,
958
- reactQueryGlobalPlugin,
959
- createCoreGlobalPlugin(themePath),
960
- createThemeDepsStubPlugin(themePath)
961
- ],
961
+ plugins,
962
962
  external: [],
963
963
  alias: {
964
964
  events: "events/",
@@ -992,15 +992,16 @@ async function compileStandaloneTheme(themePath, themeName) {
992
992
  try {
993
993
  const result = await esbuild.build(buildOptions);
994
994
  try {
995
- await fs9.unlink(shimPath);
995
+ await fs11.unlink(shimPath);
996
996
  } catch {
997
997
  }
998
+ await compileSections(themePath, outputDir);
998
999
  await contentHashEntry(outputDir);
999
- const themeAssetsDir = path11.join(themePath, "assets");
1000
- const distThemeAssets = path11.join(outputDir, "theme-assets");
1000
+ const themeAssetsDir = path13.join(themePath, "assets");
1001
+ const distThemeAssets = path13.join(outputDir, "theme-assets");
1001
1002
  try {
1002
- await fs9.access(themeAssetsDir);
1003
- await fs9.cp(themeAssetsDir, distThemeAssets, { recursive: true });
1003
+ await fs11.access(themeAssetsDir);
1004
+ await fs11.cp(themeAssetsDir, distThemeAssets, { recursive: true });
1004
1005
  logger.info("Copied static assets to dist/theme-assets/");
1005
1006
  } catch {
1006
1007
  }
@@ -1020,7 +1021,7 @@ async function compileStandaloneTheme(themePath, themeName) {
1020
1021
  return true;
1021
1022
  } catch (error) {
1022
1023
  try {
1023
- await fs9.unlink(shimPath);
1024
+ await fs11.unlink(shimPath);
1024
1025
  } catch {
1025
1026
  }
1026
1027
  logger.error(`esbuild compilation failed: ${error}`);
@@ -1028,18 +1029,25 @@ async function compileStandaloneTheme(themePath, themeName) {
1028
1029
  }
1029
1030
  }
1030
1031
  async function compileStandaloneThemeDev(themePath, themeName) {
1031
- const outputDir = path11.join(themePath, "dist");
1032
- const bundleEntry = path11.join(themePath, "bundle-entry.ts");
1033
- const indexEntry = path11.join(themePath, "index.ts");
1032
+ const outputDir = path13.join(themePath, "dist");
1033
+ const isNextjs = isNextjsProject(themePath);
1034
+ const bundleEntry = path13.join(themePath, "bundle-entry.ts");
1035
+ const indexEntry = path13.join(themePath, "index.ts");
1034
1036
  let entryPoint = indexEntry;
1035
1037
  try {
1036
- await fs9.access(bundleEntry);
1038
+ await fs11.access(bundleEntry);
1037
1039
  entryPoint = bundleEntry;
1038
1040
  } catch {
1039
1041
  }
1040
- const shimPath = path11.join(outputDir, ".process-shim.js");
1041
- await fs9.mkdir(outputDir, { recursive: true });
1042
- await fs9.writeFile(shimPath, PROCESS_SHIM);
1042
+ const shimPath = path13.join(outputDir, ".process-shim.js");
1043
+ await fs11.mkdir(outputDir, { recursive: true });
1044
+ await fs11.writeFile(shimPath, PROCESS_SHIM);
1045
+ const devPlugins = [
1046
+ reactGlobalPlugin,
1047
+ reactQueryGlobalPlugin,
1048
+ createCoreGlobalPlugin(themePath)
1049
+ ];
1050
+ if (isNextjs) devPlugins.unshift(nextShimPlugin);
1043
1051
  const buildOptions = {
1044
1052
  entryPoints: [entryPoint],
1045
1053
  bundle: true,
@@ -1050,12 +1058,7 @@ async function compileStandaloneThemeDev(themePath, themeName) {
1050
1058
  banner: {
1051
1059
  js: '"use client";'
1052
1060
  },
1053
- plugins: [
1054
- reactGlobalPlugin,
1055
- reactQueryGlobalPlugin,
1056
- createCoreGlobalPlugin(themePath),
1057
- createThemeDepsStubPlugin(themePath)
1058
- ],
1061
+ plugins: devPlugins,
1059
1062
  external: [],
1060
1063
  alias: {
1061
1064
  events: "events/",
@@ -1093,18 +1096,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
1093
1096
  return { context: context2, outputDir };
1094
1097
  }
1095
1098
  async function compilePreviewRuntime(themePath) {
1096
- const outputDir = path11.join(themePath, "dist");
1097
- await fs9.mkdir(outputDir, { recursive: true });
1098
- const outputPath = path11.join(outputDir, "preview-runtime.js");
1099
+ const outputDir = path13.join(themePath, "dist");
1100
+ await fs11.mkdir(outputDir, { recursive: true });
1101
+ const outputPath = path13.join(outputDir, "preview-runtime.js");
1099
1102
  const locations = [
1100
- path11.join(__dirname, "..", "preview", "preview-app.tsx"),
1101
- path11.join(__dirname, "preview", "preview-app.tsx"),
1102
- path11.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
1103
+ path13.join(__dirname, "..", "preview", "preview-app.tsx"),
1104
+ path13.join(__dirname, "preview", "preview-app.tsx"),
1105
+ path13.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
1103
1106
  ];
1104
1107
  let previewEntryPath = null;
1105
1108
  for (const loc of locations) {
1106
1109
  try {
1107
- await fs9.access(loc);
1110
+ await fs11.access(loc);
1108
1111
  previewEntryPath = loc;
1109
1112
  break;
1110
1113
  } catch {
@@ -1187,10 +1190,10 @@ ${locations.join("\n")}`
1187
1190
  if (!lucideScanned) {
1188
1191
  lucideScanned = true;
1189
1192
  const coreSrcCandidates = [
1190
- path11.join(themePath, "node_modules", "@onexapis", "core", "src"),
1191
- path11.join(themePath, "..", "..", "packages", "core", "src"),
1193
+ path13.join(themePath, "node_modules", "@onexapis", "core", "src"),
1194
+ path13.join(themePath, "..", "..", "packages", "core", "src"),
1192
1195
  // monorepo sibling
1193
- path11.join(
1196
+ path13.join(
1194
1197
  __dirname,
1195
1198
  "..",
1196
1199
  "..",
@@ -1205,7 +1208,7 @@ ${locations.join("\n")}`
1205
1208
  let coreSourceDir = null;
1206
1209
  for (const candidate of coreSrcCandidates) {
1207
1210
  try {
1208
- await fs9.access(candidate);
1211
+ await fs11.access(candidate);
1209
1212
  coreSourceDir = candidate;
1210
1213
  break;
1211
1214
  } catch {
@@ -1224,21 +1227,21 @@ ${locations.join("\n")}`
1224
1227
  }
1225
1228
  } else {
1226
1229
  const coreDistCandidates = [
1227
- path11.join(themePath, "node_modules", "@onexapis", "core", "dist")
1230
+ path13.join(themePath, "node_modules", "@onexapis", "core", "dist")
1228
1231
  ];
1229
1232
  const resolvedDist = await resolveNodeModulesFile(
1230
1233
  __dirname,
1231
- path11.join("@onexapis", "core", "dist")
1234
+ path13.join("@onexapis", "core", "dist")
1232
1235
  );
1233
1236
  if (resolvedDist) coreDistCandidates.push(resolvedDist);
1234
1237
  for (const candidate of coreDistCandidates) {
1235
1238
  try {
1236
- await fs9.access(candidate);
1239
+ await fs11.access(candidate);
1237
1240
  const mjsFiles = await glob("*.mjs", { cwd: candidate });
1238
1241
  const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
1239
1242
  for (const file of mjsFiles) {
1240
- const content = await fs9.readFile(
1241
- path11.join(candidate, file),
1243
+ const content = await fs11.readFile(
1244
+ path13.join(candidate, file),
1242
1245
  "utf-8"
1243
1246
  );
1244
1247
  for (const match of content.matchAll(importRegex)) {
@@ -1293,7 +1296,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
1293
1296
  const req = createRequire(import.meta.url || __filename);
1294
1297
  const cjsPath = req.resolve("framer-motion");
1295
1298
  const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
1296
- const esmEntry = path11.join(pkgDir, "dist", "es", "index.mjs");
1299
+ const esmEntry = path13.join(pkgDir, "dist", "es", "index.mjs");
1297
1300
  const { existsSync } = await import('fs');
1298
1301
  if (existsSync(esmEntry)) {
1299
1302
  return { path: esmEntry, namespace: "file" };
@@ -1392,8 +1395,8 @@ export function headers() { return new Headers(); }
1392
1395
  });
1393
1396
  }
1394
1397
  };
1395
- const shimPath = path11.join(outputDir, ".process-shim-preview.js");
1396
- await fs9.writeFile(shimPath, PROCESS_SHIM);
1398
+ const shimPath = path13.join(outputDir, ".process-shim-preview.js");
1399
+ await fs11.writeFile(shimPath, PROCESS_SHIM);
1397
1400
  await esbuild.build({
1398
1401
  entryPoints: [previewEntryPath],
1399
1402
  bundle: true,
@@ -1428,17 +1431,19 @@ export function headers() { return new Headers(); }
1428
1431
  }
1429
1432
  });
1430
1433
  try {
1431
- await fs9.unlink(shimPath);
1434
+ await fs11.unlink(shimPath);
1432
1435
  } catch {
1433
1436
  }
1434
1437
  return outputPath;
1435
1438
  }
1436
- var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin;
1439
+ var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin, nextShimPlugin;
1437
1440
  var init_compile_theme = __esm({
1438
1441
  "src/utils/compile-theme.ts"() {
1439
1442
  init_logger();
1440
1443
  init_extract_schemas();
1441
1444
  init_scan_theme_assets();
1445
+ init_detect_nextjs();
1446
+ init_nextjs_page_scanner();
1442
1447
  PROCESS_SHIM = `
1443
1448
  if (typeof process === "undefined") {
1444
1449
  globalThis.process = {
@@ -1584,6 +1589,145 @@ export const {
1584
1589
  }));
1585
1590
  }
1586
1591
  };
1592
+ nextShimPlugin = {
1593
+ name: "next-shim",
1594
+ setup(build2) {
1595
+ for (const serverModule of ["next/headers", "next/server", "next/cache"]) {
1596
+ build2.onResolve({ filter: new RegExp(`^${serverModule.replace("/", "\\/")}`) }, (args) => ({
1597
+ path: args.path,
1598
+ namespace: "next-server-error"
1599
+ }));
1600
+ }
1601
+ build2.onLoad({ filter: /.*/, namespace: "next-server-error" }, (args) => ({
1602
+ errors: [
1603
+ {
1604
+ text: `"${args.path}" is server-only and cannot be used in a OneX theme bundle. Use client-side equivalents or remove the import.`
1605
+ }
1606
+ ]
1607
+ }));
1608
+ build2.onResolve({ filter: /^next\/navigation$/ }, () => ({
1609
+ path: "next-navigation-shim",
1610
+ namespace: "next-shim"
1611
+ }));
1612
+ build2.onLoad({ filter: /^next-navigation-shim$/, namespace: "next-shim" }, () => ({
1613
+ contents: `
1614
+ export function usePathname() {
1615
+ if (typeof window === 'undefined') return '/';
1616
+ return window.location.pathname;
1617
+ }
1618
+ export function useSearchParams() {
1619
+ if (typeof window === 'undefined') return new URLSearchParams();
1620
+ return new URLSearchParams(window.location.search);
1621
+ }
1622
+ export function useParams() {
1623
+ if (typeof window === 'undefined') return {};
1624
+ return (globalThis.__ONEX_ROUTE_PARAMS__) ?? {};
1625
+ }
1626
+ export function useRouter() {
1627
+ return {
1628
+ push(url) { if (typeof window !== 'undefined') window.location.href = url; },
1629
+ replace(url) { if (typeof window !== 'undefined') window.location.replace(url); },
1630
+ back() { if (typeof window !== 'undefined') window.history.back(); },
1631
+ forward() { if (typeof window !== 'undefined') window.history.forward(); },
1632
+ refresh() { if (typeof window !== 'undefined') window.location.reload(); },
1633
+ prefetch() {},
1634
+ };
1635
+ }
1636
+ export function redirect(url) {
1637
+ if (typeof window !== 'undefined') window.location.href = url;
1638
+ throw new Error('redirect');
1639
+ }
1640
+ export function notFound() { throw new Error('not-found'); }
1641
+ `.trim(),
1642
+ loader: "js"
1643
+ }));
1644
+ build2.onResolve({ filter: /^next\/font\// }, () => ({
1645
+ path: "next-font-shim",
1646
+ namespace: "next-shim"
1647
+ }));
1648
+ build2.onLoad({ filter: /^next-font-shim$/, namespace: "next-shim" }, () => ({
1649
+ contents: `
1650
+ function makeFont(family) {
1651
+ return function(_opts) {
1652
+ return {
1653
+ className: '',
1654
+ style: { fontFamily: family + ', system-ui, sans-serif' },
1655
+ variable: '--font-' + family.toLowerCase().replace(/\\s+/g, '-'),
1656
+ };
1657
+ };
1658
+ }
1659
+ export const Inter = makeFont('Inter');
1660
+ export const Roboto = makeFont('Roboto');
1661
+ export const Open_Sans = makeFont('Open Sans');
1662
+ export const Lato = makeFont('Lato');
1663
+ export const Montserrat = makeFont('Montserrat');
1664
+ export const Poppins = makeFont('Poppins');
1665
+ export const Raleway = makeFont('Raleway');
1666
+ export const Nunito = makeFont('Nunito');
1667
+ export const Geist = makeFont('Geist');
1668
+ export const Geist_Mono = makeFont('Geist Mono');
1669
+ export const DM_Sans = makeFont('DM Sans');
1670
+ export const Plus_Jakarta_Sans = makeFont('Plus Jakarta Sans');
1671
+ export function localFont(_opts) {
1672
+ return { className: '', style: { fontFamily: 'system-ui, sans-serif' }, variable: '--font-local' };
1673
+ }
1674
+ `.trim(),
1675
+ loader: "js"
1676
+ }));
1677
+ build2.onResolve({ filter: /^next\/dynamic$/ }, () => ({
1678
+ path: "next-dynamic-shim",
1679
+ namespace: "next-shim"
1680
+ }));
1681
+ build2.onLoad({ filter: /^next-dynamic-shim$/, namespace: "next-shim" }, () => ({
1682
+ contents: `
1683
+ import { lazy, Suspense, createElement } from 'react';
1684
+ export default function dynamic(loader, opts) {
1685
+ const Lazy = lazy(loader);
1686
+ return function DynamicComponent(props) {
1687
+ return createElement(Suspense, { fallback: opts?.loading ? createElement(opts.loading) : null },
1688
+ createElement(Lazy, props));
1689
+ };
1690
+ }
1691
+ `.trim(),
1692
+ loader: "js"
1693
+ }));
1694
+ build2.onResolve({ filter: /^next\/image$/ }, () => ({
1695
+ path: "next-image-shim",
1696
+ namespace: "next-shim"
1697
+ }));
1698
+ build2.onLoad({ filter: /^next-image-shim$/, namespace: "next-shim" }, () => ({
1699
+ contents: `
1700
+ import { createElement } from 'react';
1701
+ export default function Image({ src, alt, width, height, style, className, ...rest }) {
1702
+ return createElement('img', { src, alt, width, height, style, className, ...rest });
1703
+ }
1704
+ `.trim(),
1705
+ loader: "js"
1706
+ }));
1707
+ build2.onResolve({ filter: /^next\/link$/ }, () => ({
1708
+ path: "next-link-shim",
1709
+ namespace: "next-shim"
1710
+ }));
1711
+ build2.onLoad({ filter: /^next-link-shim$/, namespace: "next-shim" }, () => ({
1712
+ contents: `
1713
+ import { createElement } from 'react';
1714
+ export default function Link({ href, children, className, style, ...rest }) {
1715
+ return createElement('a', { href, className, style, ...rest }, children);
1716
+ }
1717
+ `.trim(),
1718
+ loader: "js"
1719
+ }));
1720
+ build2.onResolve({ filter: /^next\// }, () => ({
1721
+ path: "next-noop-shim",
1722
+ namespace: "next-shim"
1723
+ }));
1724
+ build2.onLoad({ filter: /^next-noop-shim$/, namespace: "next-shim" }, () => ({
1725
+ contents: `export default {};
1726
+ `,
1727
+ loader: "js"
1728
+ }));
1729
+ }
1730
+ };
1587
1731
  }
1588
1732
  });
1589
1733
 
@@ -1594,7 +1738,7 @@ __export(dev_server_exports, {
1594
1738
  });
1595
1739
  function createDevServer(options) {
1596
1740
  const clients = /* @__PURE__ */ new Set();
1597
- const themeDataPath = path11.join(options.distDir, "theme-data.json");
1741
+ const themeDataPath = path13.join(options.distDir, "theme-data.json");
1598
1742
  const server = http.createServer((req, res) => {
1599
1743
  res.setHeader("Access-Control-Allow-Origin", "*");
1600
1744
  res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
@@ -1620,8 +1764,8 @@ function createDevServer(options) {
1620
1764
  if (pathname.startsWith("/_assets/")) {
1621
1765
  const parts = pathname.replace(/^\/_assets\//, "").split("/");
1622
1766
  const assetSubpath = parts.slice(1).join("/");
1623
- const assetPath = path11.join(options.themePath, "assets", assetSubpath);
1624
- if (!assetPath.startsWith(path11.join(options.themePath, "assets"))) {
1767
+ const assetPath = path13.join(options.themePath, "assets", assetSubpath);
1768
+ if (!assetPath.startsWith(path13.join(options.themePath, "assets"))) {
1625
1769
  res.writeHead(403);
1626
1770
  res.end("Forbidden");
1627
1771
  return;
@@ -1632,8 +1776,8 @@ function createDevServer(options) {
1632
1776
  if (pathname.startsWith("/themes/")) {
1633
1777
  const match = pathname.match(/^\/themes\/[^/]+\/assets\/(.+)/);
1634
1778
  if (match) {
1635
- const assetPath = path11.join(options.themePath, "assets", match[1]);
1636
- if (!assetPath.startsWith(path11.join(options.themePath, "assets"))) {
1779
+ const assetPath = path13.join(options.themePath, "assets", match[1]);
1780
+ if (!assetPath.startsWith(path13.join(options.themePath, "assets"))) {
1637
1781
  res.writeHead(403);
1638
1782
  res.end("Forbidden");
1639
1783
  return;
@@ -1645,26 +1789,26 @@ function createDevServer(options) {
1645
1789
  if (pathname.startsWith("/assets/")) {
1646
1790
  const subpath = pathname.replace(/^\/assets\//, "");
1647
1791
  const segments = subpath.split("/");
1648
- const assetsBase = path11.join(options.themePath, "assets");
1792
+ const assetsBase = path13.join(options.themePath, "assets");
1649
1793
  let assetPath;
1650
1794
  if (segments[0] === options.themeName || segments[0] === options.themeName.replace(/^my-/, "")) {
1651
- assetPath = path11.join(assetsBase, segments.slice(1).join("/"));
1795
+ assetPath = path13.join(assetsBase, segments.slice(1).join("/"));
1652
1796
  } else {
1653
- assetPath = path11.join(assetsBase, subpath);
1797
+ assetPath = path13.join(assetsBase, subpath);
1654
1798
  }
1655
1799
  if (assetPath.startsWith(assetsBase) && fs3.existsSync(assetPath)) {
1656
1800
  serveFile(res, assetPath);
1657
1801
  return;
1658
1802
  }
1659
1803
  if (segments.length > 1) {
1660
- const fallbackPath = path11.join(assetsBase, segments.slice(1).join("/"));
1804
+ const fallbackPath = path13.join(assetsBase, segments.slice(1).join("/"));
1661
1805
  if (fallbackPath.startsWith(assetsBase) && fs3.existsSync(fallbackPath)) {
1662
1806
  serveFile(res, fallbackPath);
1663
1807
  return;
1664
1808
  }
1665
1809
  }
1666
1810
  }
1667
- const filePath = path11.join(options.distDir, pathname);
1811
+ const filePath = path13.join(options.distDir, pathname);
1668
1812
  if (!filePath.startsWith(options.distDir)) {
1669
1813
  res.writeHead(403);
1670
1814
  res.end("Forbidden");
@@ -1707,7 +1851,7 @@ function serveFile(res, filePath) {
1707
1851
  res.end("Not Found");
1708
1852
  return;
1709
1853
  }
1710
- const ext = path11.extname(filePath);
1854
+ const ext = path13.extname(filePath);
1711
1855
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
1712
1856
  const content = fs3.readFileSync(filePath);
1713
1857
  res.writeHead(200, { "Content-Type": contentType });
@@ -1824,26 +1968,26 @@ var init_dev_server = __esm({
1824
1968
  // src/utils/file-helpers.ts
1825
1969
  init_logger();
1826
1970
  async function renderTemplate(templatePath, data) {
1827
- const template = await fs.readFile(templatePath, "utf-8");
1971
+ const template = await fs8.readFile(templatePath, "utf-8");
1828
1972
  return ejs.render(template, data);
1829
1973
  }
1830
1974
  async function writeFile(filePath, content) {
1831
- await fs.ensureDir(path11.dirname(filePath));
1832
- await fs.writeFile(filePath, content, "utf-8");
1975
+ await fs8.ensureDir(path13.dirname(filePath));
1976
+ await fs8.writeFile(filePath, content, "utf-8");
1833
1977
  }
1834
1978
  function getTemplatesDir() {
1835
1979
  const locations = [
1836
- path11.join(__dirname, "../../templates"),
1980
+ path13.join(__dirname, "../../templates"),
1837
1981
  // Development
1838
- path11.join(__dirname, "../templates"),
1982
+ path13.join(__dirname, "../templates"),
1839
1983
  // Production (dist/)
1840
- path11.join(process.cwd(), "templates"),
1984
+ path13.join(process.cwd(), "templates"),
1841
1985
  // Fallback
1842
- path11.join(process.cwd(), "packages/cli/templates")
1986
+ path13.join(process.cwd(), "packages/cli/templates")
1843
1987
  // Monorepo
1844
1988
  ];
1845
1989
  for (const location of locations) {
1846
- if (fs.existsSync(location)) {
1990
+ if (fs8.existsSync(location)) {
1847
1991
  return location;
1848
1992
  }
1849
1993
  }
@@ -1851,18 +1995,18 @@ function getTemplatesDir() {
1851
1995
  }
1852
1996
  async function copyTemplate(templateName, targetDir, data) {
1853
1997
  const templatesDir = getTemplatesDir();
1854
- const templateDir = path11.join(templatesDir, templateName);
1855
- if (!fs.existsSync(templateDir)) {
1998
+ const templateDir = path13.join(templatesDir, templateName);
1999
+ if (!fs8.existsSync(templateDir)) {
1856
2000
  throw new Error(
1857
- `Template "${templateName}" not found at ${templateDir}. Available templates: ${fs.readdirSync(templatesDir).join(", ")}`
2001
+ `Template "${templateName}" not found at ${templateDir}. Available templates: ${fs8.readdirSync(templatesDir).join(", ")}`
1858
2002
  );
1859
2003
  }
1860
- await fs.ensureDir(targetDir);
1861
- const files = await fs.readdir(templateDir);
2004
+ await fs8.ensureDir(targetDir);
2005
+ const files = await fs8.readdir(templateDir);
1862
2006
  for (const file of files) {
1863
- const templatePath = path11.join(templateDir, file);
1864
- const targetPath = path11.join(targetDir, file);
1865
- const stat = await fs.stat(templatePath);
2007
+ const templatePath = path13.join(templateDir, file);
2008
+ const targetPath = path13.join(targetDir, file);
2009
+ const stat = await fs8.stat(templatePath);
1866
2010
  if (stat.isDirectory()) {
1867
2011
  await copyTemplateDir(templatePath, targetPath, data);
1868
2012
  } else if (file.endsWith(".ejs")) {
@@ -1870,17 +2014,17 @@ async function copyTemplate(templateName, targetDir, data) {
1870
2014
  const outputPath = targetPath.replace(/\.ejs$/, "");
1871
2015
  await writeFile(outputPath, content);
1872
2016
  } else {
1873
- await fs.copy(templatePath, targetPath);
2017
+ await fs8.copy(templatePath, targetPath);
1874
2018
  }
1875
2019
  }
1876
2020
  }
1877
2021
  async function copyTemplateDir(templateDir, targetDir, data) {
1878
- await fs.ensureDir(targetDir);
1879
- const files = await fs.readdir(templateDir);
2022
+ await fs8.ensureDir(targetDir);
2023
+ const files = await fs8.readdir(templateDir);
1880
2024
  for (const file of files) {
1881
- const templatePath = path11.join(templateDir, file);
1882
- const targetPath = path11.join(targetDir, file);
1883
- const stat = await fs.stat(templatePath);
2025
+ const templatePath = path13.join(templateDir, file);
2026
+ const targetPath = path13.join(targetDir, file);
2027
+ const stat = await fs8.stat(templatePath);
1884
2028
  if (stat.isDirectory()) {
1885
2029
  await copyTemplateDir(templatePath, targetPath, data);
1886
2030
  } else if (file.endsWith(".ejs")) {
@@ -1888,38 +2032,38 @@ async function copyTemplateDir(templateDir, targetDir, data) {
1888
2032
  const outputPath = targetPath.replace(/\.ejs$/, "");
1889
2033
  await writeFile(outputPath, content);
1890
2034
  } else {
1891
- await fs.copy(templatePath, targetPath);
2035
+ await fs8.copy(templatePath, targetPath);
1892
2036
  }
1893
2037
  }
1894
2038
  }
1895
2039
  function getProjectRoot() {
1896
2040
  let currentDir = process.cwd();
1897
- while (currentDir !== path11.parse(currentDir).root) {
1898
- const packageJsonPath = path11.join(currentDir, "package.json");
1899
- if (fs.existsSync(packageJsonPath)) {
1900
- const packageJson = fs.readJsonSync(packageJsonPath);
1901
- if (packageJson.workspaces || fs.existsSync(path11.join(currentDir, "src/themes")) || fs.existsSync(path11.join(currentDir, "themes"))) {
2041
+ while (currentDir !== path13.parse(currentDir).root) {
2042
+ const packageJsonPath = path13.join(currentDir, "package.json");
2043
+ if (fs8.existsSync(packageJsonPath)) {
2044
+ const packageJson = fs8.readJsonSync(packageJsonPath);
2045
+ if (packageJson.workspaces || fs8.existsSync(path13.join(currentDir, "src/themes")) || fs8.existsSync(path13.join(currentDir, "themes"))) {
1902
2046
  return currentDir;
1903
2047
  }
1904
2048
  }
1905
- currentDir = path11.dirname(currentDir);
2049
+ currentDir = path13.dirname(currentDir);
1906
2050
  }
1907
2051
  return process.cwd();
1908
2052
  }
1909
2053
  function getThemesDir() {
1910
2054
  const root = getProjectRoot();
1911
- if (fs.existsSync(path11.join(root, "themes")))
1912
- return path11.join(root, "themes");
1913
- if (fs.existsSync(path11.join(root, "src/themes")))
1914
- return path11.join(root, "src/themes");
1915
- return path11.dirname(root);
2055
+ if (fs8.existsSync(path13.join(root, "themes")))
2056
+ return path13.join(root, "themes");
2057
+ if (fs8.existsSync(path13.join(root, "src/themes")))
2058
+ return path13.join(root, "src/themes");
2059
+ return path13.dirname(root);
1916
2060
  }
1917
2061
  function getFeaturesDir() {
1918
- return path11.join(getProjectRoot(), "src/features");
2062
+ return path13.join(getProjectRoot(), "src/features");
1919
2063
  }
1920
2064
  function isOneXProject() {
1921
2065
  const root = getProjectRoot();
1922
- return fs.existsSync(path11.join(root, "themes")) || fs.existsSync(path11.join(root, "src/themes")) || fs.existsSync(path11.join(root, "theme.config.ts")) || fs.existsSync(path11.join(root, "bundle-entry.ts"));
2066
+ return fs8.existsSync(path13.join(root, "themes")) || fs8.existsSync(path13.join(root, "src/themes")) || fs8.existsSync(path13.join(root, "theme.config.ts")) || fs8.existsSync(path13.join(root, "bundle-entry.ts"));
1923
2067
  }
1924
2068
  function ensureOneXProject() {
1925
2069
  if (!isOneXProject()) {
@@ -1931,17 +2075,17 @@ function ensureOneXProject() {
1931
2075
  }
1932
2076
  function listThemes() {
1933
2077
  const themesDir = getThemesDir();
1934
- if (!fs.existsSync(themesDir)) {
2078
+ if (!fs8.existsSync(themesDir)) {
1935
2079
  return [];
1936
2080
  }
1937
- return fs.readdirSync(themesDir).filter((name) => {
1938
- const themePath = path11.join(themesDir, name);
1939
- return fs.statSync(themePath).isDirectory() && (fs.existsSync(path11.join(themePath, "theme.config.ts")) || fs.existsSync(path11.join(themePath, "bundle-entry.ts")) || fs.existsSync(path11.join(themePath, "manifest.ts")));
2081
+ return fs8.readdirSync(themesDir).filter((name) => {
2082
+ const themePath = path13.join(themesDir, name);
2083
+ return fs8.statSync(themePath).isDirectory() && (fs8.existsSync(path13.join(themePath, "theme.config.ts")) || fs8.existsSync(path13.join(themePath, "bundle-entry.ts")) || fs8.existsSync(path13.join(themePath, "manifest.ts")));
1940
2084
  });
1941
2085
  }
1942
2086
  function themeExists(themeName) {
1943
- const themePath = path11.join(getThemesDir(), themeName);
1944
- return fs.existsSync(themePath) && (fs.existsSync(path11.join(themePath, "theme.config.ts")) || fs.existsSync(path11.join(themePath, "bundle-entry.ts")) || fs.existsSync(path11.join(themePath, "manifest.ts")));
2087
+ const themePath = path13.join(getThemesDir(), themeName);
2088
+ return fs8.existsSync(themePath) && (fs8.existsSync(path13.join(themePath, "theme.config.ts")) || fs8.existsSync(path13.join(themePath, "bundle-entry.ts")) || fs8.existsSync(path13.join(themePath, "manifest.ts")));
1945
2089
  }
1946
2090
  function detectPackageManager() {
1947
2091
  const userAgent = process.env.npm_config_user_agent || "";
@@ -1949,9 +2093,9 @@ function detectPackageManager() {
1949
2093
  if (userAgent.includes("yarn")) return "yarn";
1950
2094
  if (userAgent.includes("bun")) return "bun";
1951
2095
  const cwd = process.cwd();
1952
- if (fs.existsSync(path11.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1953
- if (fs.existsSync(path11.join(cwd, "yarn.lock"))) return "yarn";
1954
- if (fs.existsSync(path11.join(cwd, "bun.lockb"))) return "bun";
2096
+ if (fs8.existsSync(path13.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
2097
+ if (fs8.existsSync(path13.join(cwd, "yarn.lock"))) return "yarn";
2098
+ if (fs8.existsSync(path13.join(cwd, "bun.lockb"))) return "bun";
1955
2099
  return "npm";
1956
2100
  }
1957
2101
  async function installDependencies(projectPath, packageManager = "npm") {
@@ -2000,23 +2144,23 @@ function getValidCategories() {
2000
2144
  "contact"
2001
2145
  ];
2002
2146
  }
2003
- var AUTH_DIR = path11.join(os.homedir(), ".onexthm");
2147
+ var AUTH_DIR = path13.join(os.homedir(), ".onexthm");
2004
2148
  var ENV_URLS = {
2005
2149
  dev: "https://platform-dev.onexeos.com",
2006
2150
  staging: "https://platform-staging.onexeos.com",
2007
2151
  prod: "https://platform-apis.onexeos.com"
2008
2152
  };
2009
2153
  function getAuthFile(env = "dev") {
2010
- const newFile = path11.join(AUTH_DIR, `auth-${env}.json`);
2154
+ const newFile = path13.join(AUTH_DIR, `auth-${env}.json`);
2011
2155
  if (env === "dev") {
2012
- const legacyFile = path11.join(AUTH_DIR, "auth.json");
2013
- if (fs.existsSync(legacyFile) && !fs.existsSync(newFile)) {
2156
+ const legacyFile = path13.join(AUTH_DIR, "auth.json");
2157
+ if (fs8.existsSync(legacyFile) && !fs8.existsSync(newFile)) {
2014
2158
  try {
2015
- fs.moveSync(legacyFile, newFile);
2159
+ fs8.moveSync(legacyFile, newFile);
2016
2160
  } catch {
2017
2161
  try {
2018
- fs.copySync(legacyFile, newFile);
2019
- fs.removeSync(legacyFile);
2162
+ fs8.copySync(legacyFile, newFile);
2163
+ fs8.removeSync(legacyFile);
2020
2164
  } catch {
2021
2165
  }
2022
2166
  }
@@ -2028,17 +2172,17 @@ function getApiUrl(env = "dev") {
2028
2172
  return process.env.ONEXTHM_API_URL || ENV_URLS[env];
2029
2173
  }
2030
2174
  async function saveAuthTokens(tokens, env = "dev") {
2031
- await fs.ensureDir(AUTH_DIR);
2175
+ await fs8.ensureDir(AUTH_DIR);
2032
2176
  const key = getMachineKey();
2033
2177
  const data = JSON.stringify(tokens);
2034
2178
  const encrypted = encrypt(data, key);
2035
- await fs.writeFile(getAuthFile(env), encrypted, "utf-8");
2179
+ await fs8.writeFile(getAuthFile(env), encrypted, "utf-8");
2036
2180
  }
2037
2181
  function loadAuthTokens(env = "dev") {
2038
2182
  try {
2039
2183
  const file = getAuthFile(env);
2040
- if (!fs.existsSync(file)) return null;
2041
- const encrypted = fs.readFileSync(file, "utf-8");
2184
+ if (!fs8.existsSync(file)) return null;
2185
+ const encrypted = fs8.readFileSync(file, "utf-8");
2042
2186
  const key = getMachineKey();
2043
2187
  const data = decrypt(encrypted, key);
2044
2188
  return JSON.parse(data);
@@ -2048,7 +2192,7 @@ function loadAuthTokens(env = "dev") {
2048
2192
  }
2049
2193
  async function clearAuthTokens(env = "dev") {
2050
2194
  try {
2051
- await fs.remove(getAuthFile(env));
2195
+ await fs8.remove(getAuthFile(env));
2052
2196
  } catch {
2053
2197
  }
2054
2198
  }
@@ -2107,7 +2251,7 @@ function getMachineKey() {
2107
2251
  seed = `onexthm:${os.hostname()}:${os.userInfo().username}`;
2108
2252
  } else if (process.platform === "linux") {
2109
2253
  try {
2110
- seed = `onexthm:${fs.readFileSync("/etc/machine-id", "utf-8").trim()}`;
2254
+ seed = `onexthm:${fs8.readFileSync("/etc/machine-id", "utf-8").trim()}`;
2111
2255
  } catch {
2112
2256
  seed = `onexthm:${os.hostname()}:${os.userInfo().username}`;
2113
2257
  }
@@ -2145,7 +2289,7 @@ function parseJwtClaims(idToken) {
2145
2289
  }
2146
2290
 
2147
2291
  // src/commands/init.ts
2148
- async function initCommand(projectName, options = {}) {
2292
+ async function initCommand(projectName, options) {
2149
2293
  logger.header("Create New OneX Theme Project");
2150
2294
  let name;
2151
2295
  if (!projectName) {
@@ -2160,7 +2304,7 @@ async function initCommand(projectName, options = {}) {
2160
2304
  if (!validateThemeName(kebabName)) {
2161
2305
  return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
2162
2306
  }
2163
- if (fs3.existsSync(path11.join(process.cwd(), kebabName))) {
2307
+ if (fs3.existsSync(path13.join(process.cwd(), kebabName))) {
2164
2308
  return `Directory "${kebabName}" already exists`;
2165
2309
  }
2166
2310
  return true;
@@ -2171,14 +2315,14 @@ async function initCommand(projectName, options = {}) {
2171
2315
  } else {
2172
2316
  name = toKebabCase(projectName);
2173
2317
  }
2174
- const projectPath = path11.join(process.cwd(), name);
2318
+ const projectPath = path13.join(process.cwd(), name);
2175
2319
  if (fs3.existsSync(projectPath)) {
2176
2320
  logger.error(`Directory "${name}" already exists.`);
2177
2321
  process.exit(1);
2178
2322
  }
2179
2323
  if (!options.yes) {
2180
2324
  try {
2181
- const apiUrl = getApiUrl(options.env ?? "dev");
2325
+ const apiUrl = getApiUrl(options.env);
2182
2326
  const controller = new AbortController();
2183
2327
  const timeout = setTimeout(() => controller.abort(), 3e3);
2184
2328
  const response = await fetch(
@@ -2287,7 +2431,7 @@ async function initCommand(projectName, options = {}) {
2287
2431
  description,
2288
2432
  author
2289
2433
  );
2290
- const mcpJsonPath = path11.join(projectPath, ".mcp.json");
2434
+ const mcpJsonPath = path13.join(projectPath, ".mcp.json");
2291
2435
  if (fs3.existsSync(mcpJsonPath)) {
2292
2436
  let mcpContent = fs3.readFileSync(mcpJsonPath, "utf-8");
2293
2437
  if (figmaApiKey) {
@@ -2367,7 +2511,7 @@ async function initCommand(projectName, options = {}) {
2367
2511
  }
2368
2512
  }
2369
2513
  async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
2370
- const configPath = path11.join(projectPath, "theme.config.ts");
2514
+ const configPath = path13.join(projectPath, "theme.config.ts");
2371
2515
  if (fs3.existsSync(configPath)) {
2372
2516
  let content = fs3.readFileSync(configPath, "utf-8");
2373
2517
  content = content.replace(
@@ -2380,7 +2524,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
2380
2524
  );
2381
2525
  fs3.writeFileSync(configPath, content, "utf-8");
2382
2526
  }
2383
- const pkgPath = path11.join(projectPath, "package.json");
2527
+ const pkgPath = path13.join(projectPath, "package.json");
2384
2528
  if (fs3.existsSync(pkgPath)) {
2385
2529
  let content = fs3.readFileSync(pkgPath, "utf-8");
2386
2530
  content = content.replace(
@@ -2402,10 +2546,10 @@ async function createSectionCommand(name, options) {
2402
2546
  ensureOneXProject();
2403
2547
  if (!options.theme) {
2404
2548
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
2405
- (f) => fs.existsSync(path11.join(process.cwd(), f))
2549
+ (f) => fs8.existsSync(path13.join(process.cwd(), f))
2406
2550
  );
2407
2551
  if (isStandaloneTheme) {
2408
- options.theme = path11.basename(process.cwd());
2552
+ options.theme = path13.basename(process.cwd());
2409
2553
  }
2410
2554
  }
2411
2555
  const sectionName = toKebabCase(name);
@@ -2468,35 +2612,35 @@ async function createSectionCommand(name, options) {
2468
2612
  };
2469
2613
  logger.startSpinner("Creating section files...");
2470
2614
  try {
2471
- const themePath = path11.join(getThemesDir(), themeName);
2472
- const sectionPath = path11.join(themePath, "sections", sectionName);
2615
+ const themePath = path13.join(getThemesDir(), themeName);
2616
+ const sectionPath = path13.join(themePath, "sections", sectionName);
2473
2617
  const schemaContent = generateSectionSchema(data);
2474
2618
  await writeFile(
2475
- path11.join(sectionPath, `${sectionName}.schema.ts`),
2619
+ path13.join(sectionPath, `${sectionName}.schema.ts`),
2476
2620
  schemaContent
2477
2621
  );
2478
2622
  if (createTemplate) {
2479
2623
  const templateContent = generateSectionTemplate(data);
2480
2624
  await writeFile(
2481
- path11.join(sectionPath, `${sectionName}-default.tsx`),
2625
+ path13.join(sectionPath, `${sectionName}-default.tsx`),
2482
2626
  templateContent
2483
2627
  );
2484
2628
  }
2485
2629
  const indexContent = generateSectionIndex(data, createTemplate);
2486
- await writeFile(path11.join(sectionPath, "index.ts"), indexContent);
2630
+ await writeFile(path13.join(sectionPath, "index.ts"), indexContent);
2487
2631
  logger.stopSpinner(true, "Section files created successfully!");
2488
2632
  logger.newLine();
2489
2633
  logger.section("Next steps:");
2490
2634
  logger.log(
2491
- ` 1. Edit schema: ${path11.relative(process.cwd(), path11.join(sectionPath, `${sectionName}.schema.ts`))}`
2635
+ ` 1. Edit schema: ${path13.relative(process.cwd(), path13.join(sectionPath, `${sectionName}.schema.ts`))}`
2492
2636
  );
2493
2637
  if (createTemplate) {
2494
2638
  logger.log(
2495
- ` 2. Edit template: ${path11.relative(process.cwd(), path11.join(sectionPath, `${sectionName}-default.tsx`))}`
2639
+ ` 2. Edit template: ${path13.relative(process.cwd(), path13.join(sectionPath, `${sectionName}-default.tsx`))}`
2496
2640
  );
2497
2641
  }
2498
2642
  logger.log(
2499
- ` 3. Add to theme manifest: ${path11.relative(process.cwd(), path11.join(themePath, "manifest.ts"))}`
2643
+ ` 3. Add to theme manifest: ${path13.relative(process.cwd(), path13.join(themePath, "manifest.ts"))}`
2500
2644
  );
2501
2645
  logger.newLine();
2502
2646
  logger.success("Section created successfully!");
@@ -2644,10 +2788,10 @@ async function createBlockCommand(name, options) {
2644
2788
  ensureOneXProject();
2645
2789
  if (!options.theme) {
2646
2790
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
2647
- (f) => fs.existsSync(path11.join(process.cwd(), f))
2791
+ (f) => fs8.existsSync(path13.join(process.cwd(), f))
2648
2792
  );
2649
2793
  if (isStandaloneTheme) {
2650
- options.theme = path11.basename(process.cwd());
2794
+ options.theme = path13.basename(process.cwd());
2651
2795
  }
2652
2796
  }
2653
2797
  const blockName = toKebabCase(name);
@@ -2722,24 +2866,24 @@ async function createBlockCommand(name, options) {
2722
2866
  };
2723
2867
  logger.startSpinner("Creating block files...");
2724
2868
  try {
2725
- const blockPath = scope === "shared" ? path11.join(getFeaturesDir(), "blocks", blockName) : path11.join(getThemesDir(), themeName, "blocks", blockName);
2869
+ const blockPath = scope === "shared" ? path13.join(getFeaturesDir(), "blocks", blockName) : path13.join(getThemesDir(), themeName, "blocks", blockName);
2726
2870
  const schemaContent = generateBlockSchema(data);
2727
2871
  await writeFile(
2728
- path11.join(blockPath, `${blockName}.schema.ts`),
2872
+ path13.join(blockPath, `${blockName}.schema.ts`),
2729
2873
  schemaContent
2730
2874
  );
2731
2875
  const componentContent = generateBlockComponent(data);
2732
- await writeFile(path11.join(blockPath, `${blockName}.tsx`), componentContent);
2876
+ await writeFile(path13.join(blockPath, `${blockName}.tsx`), componentContent);
2733
2877
  const indexContent = generateBlockIndex(data);
2734
- await writeFile(path11.join(blockPath, "index.ts"), indexContent);
2878
+ await writeFile(path13.join(blockPath, "index.ts"), indexContent);
2735
2879
  logger.stopSpinner(true, "Block files created successfully!");
2736
2880
  logger.newLine();
2737
2881
  logger.section("Next steps:");
2738
2882
  logger.log(
2739
- ` 1. Edit schema: ${path11.relative(process.cwd(), path11.join(blockPath, `${blockName}.schema.ts`))}`
2883
+ ` 1. Edit schema: ${path13.relative(process.cwd(), path13.join(blockPath, `${blockName}.schema.ts`))}`
2740
2884
  );
2741
2885
  logger.log(
2742
- ` 2. Edit component: ${path11.relative(process.cwd(), path11.join(blockPath, `${blockName}.tsx`))}`
2886
+ ` 2. Edit component: ${path13.relative(process.cwd(), path13.join(blockPath, `${blockName}.tsx`))}`
2743
2887
  );
2744
2888
  logger.log(
2745
2889
  ` 3. Register in block registry: src/lib/registry/block-registry.ts`
@@ -2917,31 +3061,31 @@ async function createComponentCommand(name, options) {
2917
3061
  };
2918
3062
  logger.startSpinner("Creating component files...");
2919
3063
  try {
2920
- const componentPath = path11.join(
3064
+ const componentPath = path13.join(
2921
3065
  getFeaturesDir(),
2922
3066
  "components",
2923
3067
  componentName
2924
3068
  );
2925
3069
  const schemaContent = generateComponentSchema(data);
2926
3070
  await writeFile(
2927
- path11.join(componentPath, `${componentName}.schema.ts`),
3071
+ path13.join(componentPath, `${componentName}.schema.ts`),
2928
3072
  schemaContent
2929
3073
  );
2930
3074
  const componentContent = generateComponent(data);
2931
3075
  await writeFile(
2932
- path11.join(componentPath, `${componentName}.tsx`),
3076
+ path13.join(componentPath, `${componentName}.tsx`),
2933
3077
  componentContent
2934
3078
  );
2935
3079
  const indexContent = generateComponentIndex(data);
2936
- await writeFile(path11.join(componentPath, "index.ts"), indexContent);
3080
+ await writeFile(path13.join(componentPath, "index.ts"), indexContent);
2937
3081
  logger.stopSpinner(true, "Component files created successfully!");
2938
3082
  logger.newLine();
2939
3083
  logger.section("Next steps:");
2940
3084
  logger.log(
2941
- ` 1. Edit schema: ${path11.relative(process.cwd(), path11.join(componentPath, `${componentName}.schema.ts`))}`
3085
+ ` 1. Edit schema: ${path13.relative(process.cwd(), path13.join(componentPath, `${componentName}.schema.ts`))}`
2942
3086
  );
2943
3087
  logger.log(
2944
- ` 2. Edit component: ${path11.relative(process.cwd(), path11.join(componentPath, `${componentName}.tsx`))}`
3088
+ ` 2. Edit component: ${path13.relative(process.cwd(), path13.join(componentPath, `${componentName}.tsx`))}`
2945
3089
  );
2946
3090
  logger.log(
2947
3091
  ` 3. Register in component registry: src/lib/registry/component-registry.ts`
@@ -3098,13 +3242,13 @@ async function listSections(themeFilter) {
3098
3242
  return;
3099
3243
  }
3100
3244
  for (const theme of themes) {
3101
- const sectionsDir = path11.join(getThemesDir(), theme, "sections");
3102
- if (!fs.existsSync(sectionsDir)) {
3245
+ const sectionsDir = path13.join(getThemesDir(), theme, "sections");
3246
+ if (!fs8.existsSync(sectionsDir)) {
3103
3247
  continue;
3104
3248
  }
3105
- const sections = fs.readdirSync(sectionsDir).filter((name) => {
3106
- const sectionPath = path11.join(sectionsDir, name);
3107
- return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path11.join(sectionPath, "index.ts"));
3249
+ const sections = fs8.readdirSync(sectionsDir).filter((name) => {
3250
+ const sectionPath = path13.join(sectionsDir, name);
3251
+ return fs8.statSync(sectionPath).isDirectory() && fs8.existsSync(path13.join(sectionPath, "index.ts"));
3108
3252
  });
3109
3253
  if (sections.length > 0) {
3110
3254
  logger.log(chalk4.cyan(`
@@ -3118,11 +3262,11 @@ async function listSections(themeFilter) {
3118
3262
  }
3119
3263
  async function listBlocks(themeFilter) {
3120
3264
  logger.section("\u{1F9F1} Blocks");
3121
- const sharedBlocksDir = path11.join(getFeaturesDir(), "blocks");
3122
- if (fs.existsSync(sharedBlocksDir)) {
3123
- const sharedBlocks = fs.readdirSync(sharedBlocksDir).filter((name) => {
3124
- const blockPath = path11.join(sharedBlocksDir, name);
3125
- return fs.statSync(blockPath).isDirectory() && fs.existsSync(path11.join(blockPath, "index.ts"));
3265
+ const sharedBlocksDir = path13.join(getFeaturesDir(), "blocks");
3266
+ if (fs8.existsSync(sharedBlocksDir)) {
3267
+ const sharedBlocks = fs8.readdirSync(sharedBlocksDir).filter((name) => {
3268
+ const blockPath = path13.join(sharedBlocksDir, name);
3269
+ return fs8.statSync(blockPath).isDirectory() && fs8.existsSync(path13.join(blockPath, "index.ts"));
3126
3270
  });
3127
3271
  if (sharedBlocks.length > 0) {
3128
3272
  logger.log(chalk4.cyan("\n Shared:"));
@@ -3133,13 +3277,13 @@ async function listBlocks(themeFilter) {
3133
3277
  }
3134
3278
  const themes = themeFilter ? [themeFilter] : listThemes();
3135
3279
  for (const theme of themes) {
3136
- const blocksDir = path11.join(getThemesDir(), theme, "blocks");
3137
- if (!fs.existsSync(blocksDir)) {
3280
+ const blocksDir = path13.join(getThemesDir(), theme, "blocks");
3281
+ if (!fs8.existsSync(blocksDir)) {
3138
3282
  continue;
3139
3283
  }
3140
- const blocks = fs.readdirSync(blocksDir).filter((name) => {
3141
- const blockPath = path11.join(blocksDir, name);
3142
- return fs.statSync(blockPath).isDirectory() && fs.existsSync(path11.join(blockPath, "index.ts"));
3284
+ const blocks = fs8.readdirSync(blocksDir).filter((name) => {
3285
+ const blockPath = path13.join(blocksDir, name);
3286
+ return fs8.statSync(blockPath).isDirectory() && fs8.existsSync(path13.join(blockPath, "index.ts"));
3143
3287
  });
3144
3288
  if (blocks.length > 0) {
3145
3289
  logger.log(chalk4.cyan(`
@@ -3153,14 +3297,14 @@ async function listBlocks(themeFilter) {
3153
3297
  }
3154
3298
  async function listComponents() {
3155
3299
  logger.section("\u2699\uFE0F Components");
3156
- const componentsDir = path11.join(getFeaturesDir(), "components");
3157
- if (!fs.existsSync(componentsDir)) {
3300
+ const componentsDir = path13.join(getFeaturesDir(), "components");
3301
+ if (!fs8.existsSync(componentsDir)) {
3158
3302
  logger.warning("No components directory found");
3159
3303
  return;
3160
3304
  }
3161
- const components = fs.readdirSync(componentsDir).filter((name) => {
3162
- const componentPath = path11.join(componentsDir, name);
3163
- return fs.statSync(componentPath).isDirectory() && fs.existsSync(path11.join(componentPath, "index.ts"));
3305
+ const components = fs8.readdirSync(componentsDir).filter((name) => {
3306
+ const componentPath = path13.join(componentsDir, name);
3307
+ return fs8.statSync(componentPath).isDirectory() && fs8.existsSync(path13.join(componentPath, "index.ts"));
3164
3308
  });
3165
3309
  if (components.length === 0) {
3166
3310
  logger.warning("No components found");
@@ -3181,13 +3325,13 @@ async function listThemesInfo() {
3181
3325
  }
3182
3326
  logger.log("");
3183
3327
  for (const theme of themes) {
3184
- const themeDir = path11.join(getThemesDir(), theme);
3328
+ const themeDir = path13.join(getThemesDir(), theme);
3185
3329
  const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
3186
3330
  let manifestContent = "";
3187
3331
  for (const candidate of candidates) {
3188
- const candidatePath = path11.join(themeDir, candidate);
3189
- if (fs.existsSync(candidatePath)) {
3190
- manifestContent = fs.readFileSync(candidatePath, "utf-8");
3332
+ const candidatePath = path13.join(themeDir, candidate);
3333
+ if (fs8.existsSync(candidatePath)) {
3334
+ manifestContent = fs8.readFileSync(candidatePath, "utf-8");
3191
3335
  break;
3192
3336
  }
3193
3337
  }
@@ -3207,6 +3351,7 @@ async function listThemesInfo() {
3207
3351
 
3208
3352
  // src/commands/validate.ts
3209
3353
  init_logger();
3354
+ init_detect_nextjs();
3210
3355
  async function validateCommand(options) {
3211
3356
  logger.header("Validate Theme");
3212
3357
  ensureOneXProject();
@@ -3222,10 +3367,13 @@ async function validateCommand(options) {
3222
3367
  const isThemeDir2 = [
3223
3368
  "theme.config.ts",
3224
3369
  "bundle-entry.ts",
3225
- "manifest.ts"
3226
- ].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
3370
+ "manifest.ts",
3371
+ "next.config.ts",
3372
+ "next.config.js",
3373
+ "next.config.mjs"
3374
+ ].some((f) => fs8.existsSync(path13.join(process.cwd(), f)));
3227
3375
  if (isThemeDir2) {
3228
- themeToValidate = path11.basename(process.cwd());
3376
+ themeToValidate = path13.basename(process.cwd());
3229
3377
  logger.info(`Validating current theme: ${themeToValidate}`);
3230
3378
  } else {
3231
3379
  logger.error(
@@ -3234,11 +3382,11 @@ async function validateCommand(options) {
3234
3382
  process.exit(1);
3235
3383
  }
3236
3384
  }
3237
- const themePath = path11.join(getThemesDir(), themeToValidate);
3385
+ const themePath = path13.join(getThemesDir(), themeToValidate);
3238
3386
  logger.startSpinner("Running validation checks...");
3239
3387
  const entryFiles = ["manifest.ts", "theme.config.ts", "bundle-entry.ts"];
3240
3388
  const foundEntry = entryFiles.find(
3241
- (f) => fs.existsSync(path11.join(themePath, f))
3389
+ (f) => fs8.existsSync(path13.join(themePath, f))
3242
3390
  );
3243
3391
  if (!foundEntry) {
3244
3392
  issues.push({
@@ -3247,8 +3395,8 @@ async function validateCommand(options) {
3247
3395
  message: "No theme entry file found (need at least one of: manifest.ts, theme.config.ts, bundle-entry.ts)"
3248
3396
  });
3249
3397
  } else if (foundEntry === "manifest.ts") {
3250
- const manifestContent = fs.readFileSync(
3251
- path11.join(themePath, foundEntry),
3398
+ const manifestContent = fs8.readFileSync(
3399
+ path13.join(themePath, foundEntry),
3252
3400
  "utf-8"
3253
3401
  );
3254
3402
  if (!manifestContent.includes("export const") && !manifestContent.includes("export default") && !manifestContent.includes("export interface")) {
@@ -3259,56 +3407,56 @@ async function validateCommand(options) {
3259
3407
  });
3260
3408
  }
3261
3409
  }
3262
- const configPath = path11.join(themePath, "theme.config.ts");
3263
- if (!fs.existsSync(configPath)) {
3410
+ const configPath = path13.join(themePath, "theme.config.ts");
3411
+ if (!fs8.existsSync(configPath)) {
3264
3412
  issues.push({
3265
3413
  type: "warning",
3266
3414
  file: "theme.config.ts",
3267
3415
  message: "Theme config file not found (recommended)"
3268
3416
  });
3269
3417
  }
3270
- const indexPath = path11.join(themePath, "index.ts");
3271
- if (!fs.existsSync(indexPath)) {
3418
+ const indexPath = path13.join(themePath, "index.ts");
3419
+ if (!fs8.existsSync(indexPath)) {
3272
3420
  issues.push({
3273
3421
  type: "warning",
3274
3422
  file: "index.ts",
3275
3423
  message: "Index file not found (recommended)"
3276
3424
  });
3277
3425
  }
3278
- const sectionsDir = path11.join(themePath, "sections");
3279
- if (!fs.existsSync(sectionsDir)) {
3426
+ const sectionsDir = path13.join(themePath, "sections");
3427
+ if (!fs8.existsSync(sectionsDir)) {
3280
3428
  issues.push({
3281
3429
  type: "warning",
3282
3430
  file: "sections/",
3283
3431
  message: "Sections directory not found"
3284
3432
  });
3285
3433
  } else {
3286
- const sections = fs.readdirSync(sectionsDir).filter(
3287
- (name) => fs.statSync(path11.join(sectionsDir, name)).isDirectory()
3434
+ const sections = fs8.readdirSync(sectionsDir).filter(
3435
+ (name) => fs8.statSync(path13.join(sectionsDir, name)).isDirectory()
3288
3436
  );
3289
3437
  for (const sectionName of sections) {
3290
- const sectionPath = path11.join(sectionsDir, sectionName);
3291
- const schemaFile = path11.join(sectionPath, `${sectionName}.schema.ts`);
3292
- const defaultTemplate = path11.join(
3438
+ const sectionPath = path13.join(sectionsDir, sectionName);
3439
+ const schemaFile = path13.join(sectionPath, `${sectionName}.schema.ts`);
3440
+ const defaultTemplate = path13.join(
3293
3441
  sectionPath,
3294
3442
  `${sectionName}-default.tsx`
3295
3443
  );
3296
- const indexFile = path11.join(sectionPath, "index.ts");
3297
- if (!fs.existsSync(schemaFile)) {
3444
+ const indexFile = path13.join(sectionPath, "index.ts");
3445
+ if (!fs8.existsSync(schemaFile)) {
3298
3446
  issues.push({
3299
3447
  type: "error",
3300
3448
  file: `sections/${sectionName}/${sectionName}.schema.ts`,
3301
3449
  message: "Section schema file missing"
3302
3450
  });
3303
3451
  }
3304
- if (!fs.existsSync(indexFile)) {
3452
+ if (!fs8.existsSync(indexFile)) {
3305
3453
  issues.push({
3306
3454
  type: "error",
3307
3455
  file: `sections/${sectionName}/index.ts`,
3308
3456
  message: "Section index file missing"
3309
3457
  });
3310
3458
  }
3311
- if (!fs.existsSync(defaultTemplate)) {
3459
+ if (!fs8.existsSync(defaultTemplate)) {
3312
3460
  issues.push({
3313
3461
  type: "warning",
3314
3462
  file: `sections/${sectionName}/${sectionName}-default.tsx`,
@@ -3317,29 +3465,29 @@ async function validateCommand(options) {
3317
3465
  }
3318
3466
  }
3319
3467
  }
3320
- const blocksDir = path11.join(themePath, "blocks");
3321
- if (fs.existsSync(blocksDir)) {
3322
- const blocks = fs.readdirSync(blocksDir).filter((name) => fs.statSync(path11.join(blocksDir, name)).isDirectory());
3468
+ const blocksDir = path13.join(themePath, "blocks");
3469
+ if (fs8.existsSync(blocksDir)) {
3470
+ const blocks = fs8.readdirSync(blocksDir).filter((name) => fs8.statSync(path13.join(blocksDir, name)).isDirectory());
3323
3471
  for (const blockName of blocks) {
3324
- const blockPath = path11.join(blocksDir, blockName);
3325
- const schemaFile = path11.join(blockPath, `${blockName}.schema.ts`);
3326
- const componentFile = path11.join(blockPath, `${blockName}.tsx`);
3327
- const indexFile = path11.join(blockPath, "index.ts");
3328
- if (!fs.existsSync(schemaFile)) {
3472
+ const blockPath = path13.join(blocksDir, blockName);
3473
+ const schemaFile = path13.join(blockPath, `${blockName}.schema.ts`);
3474
+ const componentFile = path13.join(blockPath, `${blockName}.tsx`);
3475
+ const indexFile = path13.join(blockPath, "index.ts");
3476
+ if (!fs8.existsSync(schemaFile)) {
3329
3477
  issues.push({
3330
3478
  type: "error",
3331
3479
  file: `blocks/${blockName}/${blockName}.schema.ts`,
3332
3480
  message: "Block schema file missing"
3333
3481
  });
3334
3482
  }
3335
- if (!fs.existsSync(componentFile)) {
3483
+ if (!fs8.existsSync(componentFile)) {
3336
3484
  issues.push({
3337
3485
  type: "error",
3338
3486
  file: `blocks/${blockName}/${blockName}.tsx`,
3339
3487
  message: "Block component file missing"
3340
3488
  });
3341
3489
  }
3342
- if (!fs.existsSync(indexFile)) {
3490
+ if (!fs8.existsSync(indexFile)) {
3343
3491
  issues.push({
3344
3492
  type: "error",
3345
3493
  file: `blocks/${blockName}/index.ts`,
@@ -3348,16 +3496,16 @@ async function validateCommand(options) {
3348
3496
  }
3349
3497
  }
3350
3498
  }
3351
- if (fs.existsSync(sectionsDir)) {
3352
- const sections = fs.readdirSync(sectionsDir).filter(
3353
- (name) => fs.statSync(path11.join(sectionsDir, name)).isDirectory()
3499
+ if (fs8.existsSync(sectionsDir)) {
3500
+ const sections = fs8.readdirSync(sectionsDir).filter(
3501
+ (name) => fs8.statSync(path13.join(sectionsDir, name)).isDirectory()
3354
3502
  );
3355
3503
  for (const sectionName of sections) {
3356
- const sectionPath = path11.join(sectionsDir, sectionName);
3357
- const tsxFiles = fs.readdirSync(sectionPath).filter((f) => f.endsWith(".tsx") && !f.endsWith(".schema.ts"));
3504
+ const sectionPath = path13.join(sectionsDir, sectionName);
3505
+ const tsxFiles = fs8.readdirSync(sectionPath).filter((f) => f.endsWith(".tsx") && !f.endsWith(".schema.ts"));
3358
3506
  for (const tsxFile of tsxFiles) {
3359
- const filePath = path11.join(sectionPath, tsxFile);
3360
- const content = fs.readFileSync(filePath, "utf-8");
3507
+ const filePath = path13.join(sectionPath, tsxFile);
3508
+ const content = fs8.readFileSync(filePath, "utf-8");
3361
3509
  const relPath = `sections/${sectionName}/${tsxFile}`;
3362
3510
  if (!content.includes('"use client"') && !content.includes("'use client'")) {
3363
3511
  issues.push({
@@ -3404,12 +3552,12 @@ async function validateCommand(options) {
3404
3552
  }
3405
3553
  }
3406
3554
  }
3407
- const registryPath = path11.join(themePath, "sections-registry.ts");
3408
- const bundleEntryPath = path11.join(themePath, "bundle-entry.ts");
3409
- const registryContent = fs.existsSync(registryPath) ? fs.readFileSync(registryPath, "utf-8") : fs.existsSync(bundleEntryPath) ? fs.readFileSync(bundleEntryPath, "utf-8") : "";
3410
- if (fs.existsSync(sectionsDir) && registryContent) {
3411
- const sections = fs.readdirSync(sectionsDir).filter(
3412
- (name) => fs.statSync(path11.join(sectionsDir, name)).isDirectory()
3555
+ const registryPath = path13.join(themePath, "sections-registry.ts");
3556
+ const bundleEntryPath = path13.join(themePath, "bundle-entry.ts");
3557
+ const registryContent = fs8.existsSync(registryPath) ? fs8.readFileSync(registryPath, "utf-8") : fs8.existsSync(bundleEntryPath) ? fs8.readFileSync(bundleEntryPath, "utf-8") : "";
3558
+ if (fs8.existsSync(sectionsDir) && registryContent) {
3559
+ const sections = fs8.readdirSync(sectionsDir).filter(
3560
+ (name) => fs8.statSync(path13.join(sectionsDir, name)).isDirectory()
3413
3561
  );
3414
3562
  for (const sectionName of sections) {
3415
3563
  if (!registryContent.includes(`sections/${sectionName}`) && !registryContent.includes(`"${sectionName}"`)) {
@@ -3421,7 +3569,7 @@ async function validateCommand(options) {
3421
3569
  }
3422
3570
  }
3423
3571
  }
3424
- if (fs.existsSync(sectionsDir)) {
3572
+ if (fs8.existsSync(sectionsDir)) {
3425
3573
  const schemaTypes = await loadSchemaTypes(themePath, sectionsDir);
3426
3574
  for (const { folderName, schemaType } of schemaTypes) {
3427
3575
  if (schemaType && schemaType !== folderName) {
@@ -3432,8 +3580,8 @@ async function validateCommand(options) {
3432
3580
  });
3433
3581
  }
3434
3582
  }
3435
- const pagesDir = path11.join(themePath, "pages");
3436
- if (fs.existsSync(pagesDir)) {
3583
+ const pagesDir = path13.join(themePath, "pages");
3584
+ if (fs8.existsSync(pagesDir)) {
3437
3585
  const allSchemaTypeSet = new Set(
3438
3586
  schemaTypes.map((s) => s.schemaType || s.folderName)
3439
3587
  );
@@ -3444,6 +3592,10 @@ async function validateCommand(options) {
3444
3592
  issues.push(...pageIssues);
3445
3593
  }
3446
3594
  }
3595
+ if (isNextjsProject(themePath)) {
3596
+ const nextjsIssues = await validateNextjsComponents(themePath);
3597
+ issues.push(...nextjsIssues);
3598
+ }
3447
3599
  logger.stopSpinner(true, "Validation complete");
3448
3600
  const errors = issues.filter((i) => i.type === "error");
3449
3601
  const warnings = issues.filter((i) => i.type === "warning");
@@ -3484,18 +3636,18 @@ async function validateCommand(options) {
3484
3636
  }
3485
3637
  async function loadSchemaTypes(themePath, sectionsDir) {
3486
3638
  const results = [];
3487
- const sections = fs.readdirSync(sectionsDir).filter((name) => fs.statSync(path11.join(sectionsDir, name)).isDirectory());
3639
+ const sections = fs8.readdirSync(sectionsDir).filter((name) => fs8.statSync(path13.join(sectionsDir, name)).isDirectory());
3488
3640
  for (const sectionName of sections) {
3489
- const schemaFile = path11.join(
3641
+ const schemaFile = path13.join(
3490
3642
  sectionsDir,
3491
3643
  sectionName,
3492
3644
  `${sectionName}.schema.ts`
3493
3645
  );
3494
- if (!fs.existsSync(schemaFile)) {
3646
+ if (!fs8.existsSync(schemaFile)) {
3495
3647
  results.push({ folderName: sectionName, schemaType: null });
3496
3648
  continue;
3497
3649
  }
3498
- const content = fs.readFileSync(schemaFile, "utf-8");
3650
+ const content = fs8.readFileSync(schemaFile, "utf-8");
3499
3651
  let schemaType = null;
3500
3652
  const schemaExportMatch = content.match(
3501
3653
  /:\s*SectionSchema\s*=\s*\{[\s\S]*?\btype:\s*["']([^"']+)["']/
@@ -3522,9 +3674,9 @@ async function loadSchemaTypes(themePath, sectionsDir) {
3522
3674
  }
3523
3675
  async function validatePageSectionTypes(pagesDir, validTypes) {
3524
3676
  const issues = [];
3525
- const files = fs.readdirSync(pagesDir).filter((f) => f.match(/\.(ts|js)$/));
3677
+ const files = fs8.readdirSync(pagesDir).filter((f) => f.match(/\.(ts|js)$/));
3526
3678
  for (const file of files) {
3527
- const content = fs.readFileSync(path11.join(pagesDir, file), "utf-8");
3679
+ const content = fs8.readFileSync(path13.join(pagesDir, file), "utf-8");
3528
3680
  const pageName = file.replace(/\.(ts|js)$/, "");
3529
3681
  const sectionsMatch = content.match(/\bsections:\s*\[/);
3530
3682
  if (!sectionsMatch || sectionsMatch.index === void 0) continue;
@@ -3654,9 +3806,70 @@ var BLOCK_TYPES = /* @__PURE__ */ new Set([
3654
3806
  "team-member",
3655
3807
  "hero-content"
3656
3808
  ]);
3809
+ var SERVER_ONLY_APIS = [
3810
+ "next/headers",
3811
+ "next/server",
3812
+ "next/cache",
3813
+ "cookies()",
3814
+ "headers()",
3815
+ "draftMode()"
3816
+ ];
3817
+ async function validateNextjsComponents(themePath) {
3818
+ const issues = [];
3819
+ const { glob: glob6 } = await import('glob');
3820
+ const componentFiles = await glob6("components/**/*.{tsx,ts}", {
3821
+ cwd: themePath,
3822
+ ignore: ["**/node_modules/**"]
3823
+ });
3824
+ for (const relFile of componentFiles) {
3825
+ const absFile = path13.join(themePath, relFile);
3826
+ const content = fs8.readFileSync(absFile, "utf-8");
3827
+ const dir = path13.dirname(absFile);
3828
+ const hasSectionJson = fs8.existsSync(path13.join(dir, "section.json"));
3829
+ if (!hasSectionJson) continue;
3830
+ for (const api of SERVER_ONLY_APIS) {
3831
+ if (content.includes(`"${api}"`) || content.includes(`'${api}'`)) {
3832
+ issues.push({
3833
+ type: "error",
3834
+ file: relFile,
3835
+ message: `"${api}" is server-only and cannot be used in a OneX theme bundle. Remove this import or move data fetching to a client-side useEffect/useQuery.`
3836
+ });
3837
+ }
3838
+ if (content.includes(api.replace("()", "") + "(")) {
3839
+ issues.push({
3840
+ type: "error",
3841
+ file: relFile,
3842
+ message: `${api} is server-only and cannot be called in a browser bundle. Use useQuery or fetch() inside useEffect instead.`
3843
+ });
3844
+ }
3845
+ }
3846
+ const isAsyncComponent = /export\s+default\s+async\s+function/.test(content) || /export\s+default\s+async\s+\(/.test(content);
3847
+ if (isAsyncComponent) {
3848
+ const hasUseClient2 = content.includes('"use client"') || content.includes("'use client'");
3849
+ if (!hasUseClient2) {
3850
+ issues.push({
3851
+ type: "error",
3852
+ file: relFile,
3853
+ message: 'Async Server Components cannot be compiled to a browser bundle. Add "use client" at the top and convert data fetching to useQuery or useEffect.'
3854
+ });
3855
+ }
3856
+ }
3857
+ const usesHooks = /\buse[A-Z]\w+\s*\(/.test(content);
3858
+ const hasUseClient = content.includes('"use client"') || content.includes("'use client'");
3859
+ if (usesHooks && !hasUseClient) {
3860
+ issues.push({
3861
+ type: "warning",
3862
+ file: relFile,
3863
+ message: 'Component uses React hooks but is missing "use client" directive. Add "use client" at the top of the file.'
3864
+ });
3865
+ }
3866
+ }
3867
+ return issues;
3868
+ }
3657
3869
 
3658
3870
  // src/commands/build.ts
3659
3871
  init_logger();
3872
+ init_detect_nextjs();
3660
3873
  async function buildCommand(options) {
3661
3874
  logger.header("Build Theme");
3662
3875
  let themePath;
@@ -3664,16 +3877,16 @@ async function buildCommand(options) {
3664
3877
  if (options.theme) {
3665
3878
  themeName = options.theme;
3666
3879
  try {
3667
- const workspaceThemePath = path11.join(getThemesDir(), themeName);
3668
- if (fs.existsSync(workspaceThemePath)) {
3880
+ const workspaceThemePath = path13.join(getThemesDir(), themeName);
3881
+ if (fs8.existsSync(workspaceThemePath)) {
3669
3882
  themePath = workspaceThemePath;
3670
3883
  } else {
3671
- themePath = path11.join(process.cwd(), themeName);
3884
+ themePath = path13.join(process.cwd(), themeName);
3672
3885
  }
3673
3886
  } catch {
3674
- themePath = path11.join(process.cwd(), themeName);
3887
+ themePath = path13.join(process.cwd(), themeName);
3675
3888
  }
3676
- if (!fs.existsSync(themePath)) {
3889
+ if (!fs8.existsSync(themePath)) {
3677
3890
  logger.error(`Theme "${themeName}" not found.`);
3678
3891
  process.exit(1);
3679
3892
  }
@@ -3681,11 +3894,14 @@ async function buildCommand(options) {
3681
3894
  const isThemeDir2 = [
3682
3895
  "theme.config.ts",
3683
3896
  "bundle-entry.ts",
3684
- "manifest.ts"
3685
- ].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
3897
+ "manifest.ts",
3898
+ "next.config.ts",
3899
+ "next.config.js",
3900
+ "next.config.mjs"
3901
+ ].some((f) => fs8.existsSync(path13.join(process.cwd(), f)));
3686
3902
  if (isThemeDir2) {
3687
3903
  themePath = process.cwd();
3688
- themeName = path11.basename(themePath);
3904
+ themeName = path13.basename(themePath);
3689
3905
  logger.info(`Building current theme: ${themeName}`);
3690
3906
  } else {
3691
3907
  logger.error(
@@ -3694,8 +3910,8 @@ async function buildCommand(options) {
3694
3910
  process.exit(1);
3695
3911
  }
3696
3912
  }
3697
- const packageJsonPath = path11.join(themePath, "package.json");
3698
- const hasPkgJson = fs.existsSync(packageJsonPath);
3913
+ const packageJsonPath = path13.join(themePath, "package.json");
3914
+ const hasPkgJson = fs8.existsSync(packageJsonPath);
3699
3915
  if (!hasPkgJson) {
3700
3916
  logger.warning(
3701
3917
  "No package.json found in theme. Skipping build (themes in monorepo are built via turbo)."
@@ -3710,30 +3926,42 @@ async function buildCommand(options) {
3710
3926
  }
3711
3927
  logger.newLine();
3712
3928
  logger.section("Build Steps");
3713
- logger.startSpinner("Running type check...");
3714
- const typeCheckSuccess = await runCommand("pnpm", ["type-check"], themePath);
3715
- if (!typeCheckSuccess) {
3716
- logger.stopSpinner(false, "Type check failed");
3717
- logger.error("Fix type errors before building.");
3718
- process.exit(1);
3719
- }
3720
- logger.stopSpinner(true, "Type check passed");
3721
- logger.startSpinner("Running linter...");
3722
- const lintSuccess = await runCommand("pnpm", ["lint"], themePath);
3723
- if (!lintSuccess) {
3724
- logger.stopSpinner(false, "Lint failed");
3725
- logger.error("Fix lint errors before building.");
3726
- process.exit(1);
3929
+ const pkgJson = fs8.readJsonSync(packageJsonPath);
3930
+ if (pkgJson.scripts?.["type-check"]) {
3931
+ logger.startSpinner("Running type check...");
3932
+ const typeCheckSuccess = await runCommand("pnpm", ["type-check"], themePath);
3933
+ if (!typeCheckSuccess) {
3934
+ logger.stopSpinner(false, "Type check failed");
3935
+ logger.error("Fix type errors before building.");
3936
+ process.exit(1);
3937
+ }
3938
+ logger.stopSpinner(true, "Type check passed");
3939
+ } else {
3940
+ logger.info("Skipping type check (no type-check script in package.json)");
3941
+ }
3942
+ const isNextjsForLint = isNextjsProject(themePath);
3943
+ if (!isNextjsForLint && pkgJson.scripts?.lint) {
3944
+ logger.startSpinner("Running linter...");
3945
+ const lintSuccess = await runCommand("pnpm", ["lint"], themePath);
3946
+ if (!lintSuccess) {
3947
+ logger.stopSpinner(false, "Lint failed");
3948
+ logger.error("Fix lint errors before building.");
3949
+ process.exit(1);
3950
+ }
3951
+ logger.stopSpinner(true, "Lint passed");
3952
+ } else if (isNextjsForLint) {
3953
+ logger.info("Skipping lint (Next.js project compiled via esbuild)");
3954
+ } else {
3955
+ logger.info("Skipping lint (no lint script in package.json)");
3727
3956
  }
3728
- logger.stopSpinner(true, "Lint passed");
3729
- const pkgJson = fs.readJsonSync(packageJsonPath);
3730
3957
  const buildScript = pkgJson.scripts?.build || "";
3731
3958
  const isRecursive = buildScript.includes("onexthm build") || buildScript.includes("onex build") || buildScript.includes("onex-cli build");
3959
+ const isNextjs = isNextjsProject(themePath);
3732
3960
  logger.startSpinner(
3733
3961
  options.watch ? "Building (watch mode)..." : "Building..."
3734
3962
  );
3735
3963
  let buildSuccess;
3736
- if (isRecursive) {
3964
+ if (isRecursive || isNextjs) {
3737
3965
  const { compileStandaloneTheme: compileStandaloneTheme2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
3738
3966
  buildSuccess = await compileStandaloneTheme2(themePath, themeName);
3739
3967
  } else {
@@ -3750,10 +3978,10 @@ async function buildCommand(options) {
3750
3978
  logger.success("\u2713 Theme built successfully!");
3751
3979
  logger.newLine();
3752
3980
  logger.info(`Theme: ${themeName}`);
3753
- const distPath = path11.join(themePath, "dist");
3754
- if (fs.existsSync(distPath)) {
3755
- logger.log(`Output: ${path11.relative(process.cwd(), distPath)}`);
3756
- const files = fs.readdirSync(distPath);
3981
+ const distPath = path13.join(themePath, "dist");
3982
+ if (fs8.existsSync(distPath)) {
3983
+ logger.log(`Output: ${path13.relative(process.cwd(), distPath)}`);
3984
+ const files = fs8.readdirSync(distPath);
3757
3985
  logger.log(`Files: ${files.length}`);
3758
3986
  }
3759
3987
  }
@@ -3808,8 +4036,8 @@ async function packageCommand(options) {
3808
4036
  let themeName;
3809
4037
  if (options.theme) {
3810
4038
  themeName = options.theme;
3811
- themePath = path11.join(getThemesDir(), themeName);
3812
- if (!fs.existsSync(themePath)) {
4039
+ themePath = path13.join(getThemesDir(), themeName);
4040
+ if (!fs8.existsSync(themePath)) {
3813
4041
  logger.error(`Theme "${themeName}" not found.`);
3814
4042
  process.exit(1);
3815
4043
  }
@@ -3817,11 +4045,14 @@ async function packageCommand(options) {
3817
4045
  const isThemeDir2 = [
3818
4046
  "theme.config.ts",
3819
4047
  "bundle-entry.ts",
3820
- "manifest.ts"
3821
- ].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
4048
+ "manifest.ts",
4049
+ "next.config.ts",
4050
+ "next.config.js",
4051
+ "next.config.mjs"
4052
+ ].some((f) => fs8.existsSync(path13.join(process.cwd(), f)));
3822
4053
  if (isThemeDir2) {
3823
4054
  themePath = process.cwd();
3824
- themeName = path11.basename(themePath);
4055
+ themeName = path13.basename(themePath);
3825
4056
  logger.info(`Packaging current theme: ${themeName}`);
3826
4057
  } else {
3827
4058
  logger.error(
@@ -3830,22 +4061,19 @@ async function packageCommand(options) {
3830
4061
  process.exit(1);
3831
4062
  }
3832
4063
  }
3833
- const packageJsonPath = path11.join(themePath, "package.json");
4064
+ const packageJsonPath = path13.join(themePath, "package.json");
3834
4065
  let version2 = "1.0.0";
3835
- if (fs.existsSync(packageJsonPath)) {
3836
- const packageJson = await fs.readJson(packageJsonPath);
4066
+ if (fs8.existsSync(packageJsonPath)) {
4067
+ const packageJson = await fs8.readJson(packageJsonPath);
3837
4068
  version2 = packageJson.version || "1.0.0";
3838
4069
  }
3839
4070
  logger.newLine();
3840
4071
  logger.info(`Theme: ${themeName}`);
3841
4072
  logger.info(`Version: ${version2}`);
3842
4073
  logger.newLine();
3843
- const compiledThemePath = path11.join(
3844
- process.cwd(),
3845
- "themes",
3846
- themeName,
3847
- "dist"
3848
- );
4074
+ const standaloneDistPath = path13.join(themePath, "dist");
4075
+ const monorepoDistPath = path13.join(process.cwd(), "themes", themeName, "dist");
4076
+ const compiledThemePath = fs8.existsSync(standaloneDistPath) ? standaloneDistPath : monorepoDistPath;
3849
4077
  if (!options.skipBuild) {
3850
4078
  logger.section("Step 1: Compile Theme");
3851
4079
  logger.startSpinner("Compiling theme with esbuild...");
@@ -3866,7 +4094,7 @@ async function packageCommand(options) {
3866
4094
  } else {
3867
4095
  logger.info("Skipping build (--skip-build flag)");
3868
4096
  }
3869
- if (!fs.existsSync(compiledThemePath)) {
4097
+ if (!fs8.existsSync(compiledThemePath)) {
3870
4098
  logger.error(`Compiled theme not found at: ${compiledThemePath}`);
3871
4099
  logger.info("Run without --skip-build to compile first.");
3872
4100
  process.exit(1);
@@ -3874,25 +4102,25 @@ async function packageCommand(options) {
3874
4102
  logger.newLine();
3875
4103
  logger.section("Step 2: Create Package");
3876
4104
  const packageName = options.name || `${themeName}-${version2}`;
3877
- const outputDir = options.output || path11.join(process.cwd(), "dist");
3878
- const outputPath = path11.join(outputDir, `${packageName}.zip`);
3879
- await fs.ensureDir(outputDir);
4105
+ const outputDir = options.output || path13.join(process.cwd(), "dist");
4106
+ const outputPath = path13.join(outputDir, `${packageName}.zip`);
4107
+ await fs8.ensureDir(outputDir);
3880
4108
  logger.startSpinner("Creating zip archive...");
3881
4109
  try {
3882
4110
  await createZipArchive(compiledThemePath, outputPath);
3883
4111
  logger.stopSpinner(true, "Package created");
3884
- const stats = await fs.stat(outputPath);
4112
+ const stats = await fs8.stat(outputPath);
3885
4113
  const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
3886
4114
  logger.newLine();
3887
4115
  logger.success("\u2713 Theme packaged successfully!");
3888
4116
  logger.newLine();
3889
4117
  logger.info(`Package: ${packageName}.zip`);
3890
4118
  logger.log(`Size: ${sizeMB} MB`);
3891
- logger.log(`Location: ${path11.relative(process.cwd(), outputPath)}`);
4119
+ logger.log(`Location: ${path13.relative(process.cwd(), outputPath)}`);
3892
4120
  logger.newLine();
3893
4121
  logger.section("Next steps:");
3894
4122
  logger.log(
3895
- ` onexthm deploy --package ${path11.relative(process.cwd(), outputPath)}`
4123
+ ` onexthm deploy --package ${path13.relative(process.cwd(), outputPath)}`
3896
4124
  );
3897
4125
  } catch (error) {
3898
4126
  logger.stopSpinner(false, "Failed to create package");
@@ -3926,7 +4154,7 @@ function runCommand2(command, args) {
3926
4154
  }
3927
4155
  async function createZipArchive(compiledThemePath, outputPath) {
3928
4156
  return new Promise((resolve, reject) => {
3929
- const output = fs.createWriteStream(outputPath);
4157
+ const output = fs8.createWriteStream(outputPath);
3930
4158
  const archive = archiver("zip", {
3931
4159
  zlib: { level: 9 }
3932
4160
  // Maximum compression
@@ -3950,14 +4178,14 @@ async function deployCommand(options) {
3950
4178
  ensureOneXProject();
3951
4179
  let packagePath;
3952
4180
  if (options.package) {
3953
- packagePath = path11.resolve(options.package);
4181
+ packagePath = path13.resolve(options.package);
3954
4182
  } else if (options.theme) {
3955
- const distDir = path11.join(process.cwd(), "dist");
3956
- if (!fs.existsSync(distDir)) {
4183
+ const distDir = path13.join(process.cwd(), "dist");
4184
+ if (!fs8.existsSync(distDir)) {
3957
4185
  logger.error("No dist/ directory found. Run 'onexthm package' first.");
3958
4186
  process.exit(1);
3959
4187
  }
3960
- const files = fs.readdirSync(distDir);
4188
+ const files = fs8.readdirSync(distDir);
3961
4189
  const packageFiles = files.filter(
3962
4190
  (f) => f.startsWith(options.theme) && f.endsWith(".zip")
3963
4191
  );
@@ -3967,7 +4195,7 @@ async function deployCommand(options) {
3967
4195
  process.exit(1);
3968
4196
  }
3969
4197
  packageFiles.sort().reverse();
3970
- packagePath = path11.join(distDir, packageFiles[0]);
4198
+ packagePath = path13.join(distDir, packageFiles[0]);
3971
4199
  } else {
3972
4200
  logger.error("Either --package or --theme must be specified.");
3973
4201
  logger.info("Examples:");
@@ -3975,17 +4203,17 @@ async function deployCommand(options) {
3975
4203
  logger.log(" onexthm deploy --theme tinan");
3976
4204
  process.exit(1);
3977
4205
  }
3978
- if (!fs.existsSync(packagePath)) {
4206
+ if (!fs8.existsSync(packagePath)) {
3979
4207
  logger.error(`Package not found: ${packagePath}`);
3980
4208
  process.exit(1);
3981
4209
  }
3982
- const stats = await fs.stat(packagePath);
4210
+ const stats = await fs8.stat(packagePath);
3983
4211
  const sizeMB = (stats.size / 1024 / 1024).toFixed(2);
3984
- const fileName = path11.basename(packagePath);
4212
+ const fileName = path13.basename(packagePath);
3985
4213
  logger.newLine();
3986
4214
  logger.info(`Package: ${fileName}`);
3987
4215
  logger.log(`Size: ${sizeMB} MB`);
3988
- logger.log(`Path: ${path11.relative(process.cwd(), packagePath)}`);
4216
+ logger.log(`Path: ${path13.relative(process.cwd(), packagePath)}`);
3989
4217
  logger.newLine();
3990
4218
  const apiUrl = options.apiUrl || process.env.ONEX_API_URL || "http://localhost:3001";
3991
4219
  const uploadEndpoint = `${apiUrl}/website-api/themes/upload`;
@@ -3995,7 +4223,7 @@ async function deployCommand(options) {
3995
4223
  logger.startSpinner("Uploading theme package...");
3996
4224
  try {
3997
4225
  const formData = new FormData();
3998
- formData.append("theme", fs.createReadStream(packagePath), {
4226
+ formData.append("theme", fs8.createReadStream(packagePath), {
3999
4227
  filename: fileName,
4000
4228
  contentType: "application/zip"
4001
4229
  });
@@ -4142,24 +4370,24 @@ async function downloadBundleZip(apiUrl, themeId, version2) {
4142
4370
  async function createCompatibilityFiles(outputDir, manifest) {
4143
4371
  const entryFile = manifest.output?.entry || "bundle-entry.js";
4144
4372
  if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
4145
- const hashedPath = path11.join(outputDir, entryFile);
4146
- const stablePath = path11.join(outputDir, "bundle-entry.js");
4147
- if (await fs.pathExists(hashedPath)) {
4148
- await fs.copy(hashedPath, stablePath);
4373
+ const hashedPath = path13.join(outputDir, entryFile);
4374
+ const stablePath = path13.join(outputDir, "bundle-entry.js");
4375
+ if (await fs8.pathExists(hashedPath)) {
4376
+ await fs8.copy(hashedPath, stablePath);
4149
4377
  const mapPath = hashedPath + ".map";
4150
- if (await fs.pathExists(mapPath)) {
4151
- await fs.copy(mapPath, stablePath + ".map");
4378
+ if (await fs8.pathExists(mapPath)) {
4379
+ await fs8.copy(mapPath, stablePath + ".map");
4152
4380
  }
4153
4381
  }
4154
4382
  }
4155
- const sectionsRegistryPath = path11.join(outputDir, "sections-registry.js");
4383
+ const sectionsRegistryPath = path13.join(outputDir, "sections-registry.js");
4156
4384
  const content = `// Re-export all sections from bundle-entry
4157
4385
  // This file exists to maintain compatibility with the import path
4158
4386
  export * from './bundle-entry.js';
4159
4387
  `;
4160
- await fs.writeFile(sectionsRegistryPath, content, "utf-8");
4161
- const pkgJsonPath = path11.join(outputDir, "package.json");
4162
- await fs.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
4388
+ await fs8.writeFile(sectionsRegistryPath, content, "utf-8");
4389
+ const pkgJsonPath = path13.join(outputDir, "package.json");
4390
+ await fs8.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
4163
4391
  }
4164
4392
  function showDownloadFailureHelp(themeId, apiUrl) {
4165
4393
  console.log();
@@ -4199,7 +4427,7 @@ function showDownloadFailureHelp(themeId, apiUrl) {
4199
4427
  }
4200
4428
  async function downloadCommand(options) {
4201
4429
  logger.header("Download Theme");
4202
- const env = options.env ?? "dev";
4430
+ const env = options.env;
4203
4431
  const apiUrl = getApiUrl(env);
4204
4432
  logger.info(`Environment: ${env} (${apiUrl})`);
4205
4433
  const spinner = ora("Initializing download...").start();
@@ -4251,14 +4479,14 @@ async function downloadCommand(options) {
4251
4479
  const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
4252
4480
  spinner.succeed(`Downloaded bundle.zip (${sizeMB} MB)`);
4253
4481
  spinner.start("Extracting bundle...");
4254
- await fs.remove(outputDir);
4255
- await fs.ensureDir(outputDir);
4482
+ await fs8.remove(outputDir);
4483
+ await fs8.ensureDir(outputDir);
4256
4484
  const zip = new AdmZip(zipBuffer);
4257
4485
  zip.extractAllTo(outputDir, true);
4258
4486
  const entries = zip.getEntries().filter((e) => !e.isDirectory);
4259
4487
  spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
4260
- const manifestPath = path11.join(outputDir, "manifest.json");
4261
- const manifest = await fs.readJson(manifestPath);
4488
+ const manifestPath = path13.join(outputDir, "manifest.json");
4489
+ const manifest = await fs8.readJson(manifestPath);
4262
4490
  await createCompatibilityFiles(outputDir, manifest);
4263
4491
  console.log();
4264
4492
  logger.success(chalk4.green.bold("Theme downloaded successfully!"));
@@ -4378,9 +4606,9 @@ async function renameTheme(themeDir, oldName, newName) {
4378
4606
  const oldPrefix = `${oldName}-`;
4379
4607
  const newPrefix = `${newName}-`;
4380
4608
  const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
4381
- const pkgPath = path11.join(themeDir, "package.json");
4382
- if (await fs.pathExists(pkgPath)) {
4383
- const pkg = await fs.readJson(pkgPath);
4609
+ const pkgPath = path13.join(themeDir, "package.json");
4610
+ if (await fs8.pathExists(pkgPath)) {
4611
+ const pkg = await fs8.readJson(pkgPath);
4384
4612
  pkg.name = `@onex-themes/${newName}`;
4385
4613
  if (pkg.description) {
4386
4614
  pkg.description = pkg.description.replace(
@@ -4392,33 +4620,33 @@ async function renameTheme(themeDir, oldName, newName) {
4392
4620
  if (pkg.devDependencies?.["@onexapis/cli"]) {
4393
4621
  delete pkg.devDependencies["@onexapis/cli"];
4394
4622
  }
4395
- await fs.writeJson(pkgPath, pkg, { spaces: 2 });
4623
+ await fs8.writeJson(pkgPath, pkg, { spaces: 2 });
4396
4624
  }
4397
- const configPath = path11.join(themeDir, "theme.config.ts");
4398
- if (await fs.pathExists(configPath)) {
4399
- let content = await fs.readFile(configPath, "utf-8");
4625
+ const configPath = path13.join(themeDir, "theme.config.ts");
4626
+ if (await fs8.pathExists(configPath)) {
4627
+ let content = await fs8.readFile(configPath, "utf-8");
4400
4628
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
4401
4629
  content = content.replace(
4402
4630
  /name:\s*"[^"]*Theme"/,
4403
4631
  `name: "${newDisplayName} Theme"`
4404
4632
  );
4405
- await fs.writeFile(configPath, content);
4633
+ await fs8.writeFile(configPath, content);
4406
4634
  }
4407
- const layoutPath = path11.join(themeDir, "theme.layout.ts");
4408
- if (await fs.pathExists(layoutPath)) {
4409
- let content = await fs.readFile(layoutPath, "utf-8");
4635
+ const layoutPath = path13.join(themeDir, "theme.layout.ts");
4636
+ if (await fs8.pathExists(layoutPath)) {
4637
+ let content = await fs8.readFile(layoutPath, "utf-8");
4410
4638
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
4411
4639
  content = content.replace(
4412
4640
  /name:\s*"[^"]*Theme"/,
4413
4641
  `name: "${newDisplayName} Theme"`
4414
4642
  );
4415
- await fs.writeFile(layoutPath, content);
4643
+ await fs8.writeFile(layoutPath, content);
4416
4644
  }
4417
4645
  const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
4418
4646
  const tsFiles = await glob("**/*.ts", { cwd: themeDir, nodir: true });
4419
4647
  for (const file of tsFiles) {
4420
- const filePath = path11.join(themeDir, file);
4421
- let content = await fs.readFile(filePath, "utf-8");
4648
+ const filePath = path13.join(themeDir, file);
4649
+ let content = await fs8.readFile(filePath, "utf-8");
4422
4650
  const original = content;
4423
4651
  content = content.replace(
4424
4652
  new RegExp(`"${oldPrefix}`, "g"),
@@ -4433,13 +4661,13 @@ async function renameTheme(themeDir, oldName, newName) {
4433
4661
  `${newDisplayName} Theme`
4434
4662
  );
4435
4663
  if (content !== original) {
4436
- await fs.writeFile(filePath, content);
4664
+ await fs8.writeFile(filePath, content);
4437
4665
  }
4438
4666
  }
4439
4667
  }
4440
4668
  async function cloneCommand(themeName, options) {
4441
4669
  logger.header("Clone Theme Source");
4442
- const env = options.env ?? "dev";
4670
+ const env = options.env;
4443
4671
  const apiUrl = getApiUrl(env);
4444
4672
  logger.info(`Environment: ${env} (${apiUrl})`);
4445
4673
  if (options.bucket) {
@@ -4460,8 +4688,8 @@ async function cloneCommand(themeName, options) {
4460
4688
  }
4461
4689
  const spinner = ora("Initializing clone...").start();
4462
4690
  try {
4463
- const outputDir = options.output || path11.resolve(process.cwd(), newName);
4464
- if (await fs.pathExists(outputDir)) {
4691
+ const outputDir = options.output || path13.resolve(process.cwd(), newName);
4692
+ if (await fs8.pathExists(outputDir)) {
4465
4693
  spinner.fail(chalk4.red(`Directory already exists: ${outputDir}`));
4466
4694
  logger.info(
4467
4695
  chalk4.gray(
@@ -4494,7 +4722,7 @@ async function cloneCommand(themeName, options) {
4494
4722
  const sizeMB = (zipBuffer.length / 1024 / 1024).toFixed(2);
4495
4723
  spinner.succeed(`Downloaded source.zip (${sizeMB} MB)`);
4496
4724
  spinner.start(`Extracting to ${outputDir}...`);
4497
- await fs.ensureDir(outputDir);
4725
+ await fs8.ensureDir(outputDir);
4498
4726
  const zip = new AdmZip(zipBuffer);
4499
4727
  zip.extractAllTo(outputDir, true);
4500
4728
  const entries = zip.getEntries().filter((e) => !e.isDirectory);
@@ -4506,9 +4734,9 @@ async function cloneCommand(themeName, options) {
4506
4734
  spinner.succeed(
4507
4735
  `Renamed theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}`
4508
4736
  );
4509
- const envExamplePath = path11.join(outputDir, ".env.example");
4510
- if (!await fs.pathExists(envExamplePath)) {
4511
- await fs.writeFile(
4737
+ const envExamplePath = path13.join(outputDir, ".env.example");
4738
+ if (!await fs8.pathExists(envExamplePath)) {
4739
+ await fs8.writeFile(
4512
4740
  envExamplePath,
4513
4741
  [
4514
4742
  "# API Configuration (enables real data in preview)",
@@ -4519,8 +4747,8 @@ async function cloneCommand(themeName, options) {
4519
4747
  ].join("\n")
4520
4748
  );
4521
4749
  }
4522
- const mcpJsonPath = path11.join(outputDir, ".mcp.json");
4523
- if (await fs.pathExists(mcpJsonPath)) {
4750
+ const mcpJsonPath = path13.join(outputDir, ".mcp.json");
4751
+ if (await fs8.pathExists(mcpJsonPath)) {
4524
4752
  const { default: inquirerMod } = await import('inquirer');
4525
4753
  const { figmaApiKey } = await inquirerMod.prompt([
4526
4754
  {
@@ -4529,7 +4757,7 @@ async function cloneCommand(themeName, options) {
4529
4757
  message: "Figma API Key (optional, for Figma-to-code MCP \u2014 press Enter to skip):"
4530
4758
  }
4531
4759
  ]);
4532
- let mcpContent = await fs.readFile(mcpJsonPath, "utf-8");
4760
+ let mcpContent = await fs8.readFile(mcpJsonPath, "utf-8");
4533
4761
  if (figmaApiKey) {
4534
4762
  mcpContent = mcpContent.replace("__FIGMA_API_KEY__", figmaApiKey);
4535
4763
  } else {
@@ -4540,11 +4768,11 @@ async function cloneCommand(themeName, options) {
4540
4768
  } catch {
4541
4769
  }
4542
4770
  }
4543
- await fs.writeFile(mcpJsonPath, mcpContent, "utf-8");
4771
+ await fs8.writeFile(mcpJsonPath, mcpContent, "utf-8");
4544
4772
  }
4545
4773
  if (options.install !== false) {
4546
- const hasPkgJson = await fs.pathExists(
4547
- path11.join(outputDir, "package.json")
4774
+ const hasPkgJson = await fs8.pathExists(
4775
+ path13.join(outputDir, "package.json")
4548
4776
  );
4549
4777
  if (hasPkgJson) {
4550
4778
  spinner.start("Installing dependencies...");
@@ -4572,7 +4800,7 @@ async function cloneCommand(themeName, options) {
4572
4800
  console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
4573
4801
  console.log();
4574
4802
  console.log(chalk4.cyan("Next steps:"));
4575
- console.log(chalk4.gray(` cd ${path11.relative(process.cwd(), outputDir)}`));
4803
+ console.log(chalk4.gray(` cd ${path13.relative(process.cwd(), outputDir)}`));
4576
4804
  console.log(
4577
4805
  chalk4.gray(" cp .env.example .env # then add your Company ID")
4578
4806
  );
@@ -4599,16 +4827,16 @@ async function devCommand(options) {
4599
4827
  if (options.theme) {
4600
4828
  themeName = options.theme;
4601
4829
  try {
4602
- const workspaceThemePath = path11.join(getThemesDir(), themeName);
4603
- if (fs.existsSync(workspaceThemePath)) {
4830
+ const workspaceThemePath = path13.join(getThemesDir(), themeName);
4831
+ if (fs8.existsSync(workspaceThemePath)) {
4604
4832
  themePath = workspaceThemePath;
4605
4833
  } else {
4606
- themePath = path11.join(process.cwd(), themeName);
4834
+ themePath = path13.join(process.cwd(), themeName);
4607
4835
  }
4608
4836
  } catch {
4609
- themePath = path11.join(process.cwd(), themeName);
4837
+ themePath = path13.join(process.cwd(), themeName);
4610
4838
  }
4611
- if (!fs.existsSync(themePath)) {
4839
+ if (!fs8.existsSync(themePath)) {
4612
4840
  logger.error(`Theme "${themeName}" not found.`);
4613
4841
  process.exit(1);
4614
4842
  }
@@ -4616,11 +4844,14 @@ async function devCommand(options) {
4616
4844
  const isThemeDir2 = [
4617
4845
  "theme.config.ts",
4618
4846
  "bundle-entry.ts",
4619
- "manifest.ts"
4620
- ].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
4847
+ "manifest.ts",
4848
+ "next.config.ts",
4849
+ "next.config.js",
4850
+ "next.config.mjs"
4851
+ ].some((f) => fs8.existsSync(path13.join(process.cwd(), f)));
4621
4852
  if (isThemeDir2) {
4622
4853
  themePath = process.cwd();
4623
- themeName = path11.basename(themePath);
4854
+ themeName = path13.basename(themePath);
4624
4855
  } else {
4625
4856
  logger.error(
4626
4857
  "Not in a theme directory and no --theme specified. Run from theme root or use --theme flag."
@@ -4689,9 +4920,9 @@ async function devCommand(options) {
4689
4920
  watcher.close();
4690
4921
  await context2.dispose();
4691
4922
  server.close();
4692
- const shimPath = path11.join(outputDir, ".process-shim.js");
4923
+ const shimPath = path13.join(outputDir, ".process-shim.js");
4693
4924
  try {
4694
- await fs9.unlink(shimPath);
4925
+ await fs11.unlink(shimPath);
4695
4926
  } catch {
4696
4927
  }
4697
4928
  process.exit(0);
@@ -4700,8 +4931,8 @@ async function devCommand(options) {
4700
4931
 
4701
4932
  // src/commands/config.ts
4702
4933
  init_logger();
4703
- var CONFIG_DIR = path11.join(os.homedir(), ".onexthm");
4704
- var CONFIG_FILE = path11.join(CONFIG_DIR, ".env");
4934
+ var CONFIG_DIR = path13.join(os.homedir(), ".onexthm");
4935
+ var CONFIG_FILE = path13.join(CONFIG_DIR, ".env");
4705
4936
  var CONFIG_ENTRIES = [
4706
4937
  {
4707
4938
  key: "AWS_ACCESS_KEY_ID",
@@ -4787,7 +5018,7 @@ async function configCommand() {
4787
5018
  logger.header("OneX CLI Configuration");
4788
5019
  let existing = {};
4789
5020
  try {
4790
- const content = await fs.readFile(CONFIG_FILE, "utf-8");
5021
+ const content = await fs8.readFile(CONFIG_FILE, "utf-8");
4791
5022
  existing = parseEnvFile(content);
4792
5023
  logger.info(`Existing config found at: ${CONFIG_FILE}`);
4793
5024
  logger.newLine();
@@ -4823,8 +5054,8 @@ async function configCommand() {
4823
5054
  for (const key of Object.keys(merged)) {
4824
5055
  if (!merged[key]) delete merged[key];
4825
5056
  }
4826
- await fs.ensureDir(CONFIG_DIR);
4827
- await fs.writeFile(CONFIG_FILE, serializeEnv(merged));
5057
+ await fs8.ensureDir(CONFIG_DIR);
5058
+ await fs8.writeFile(CONFIG_FILE, serializeEnv(merged));
4828
5059
  logger.newLine();
4829
5060
  logger.success(`Config saved to: ${CONFIG_FILE}`);
4830
5061
  logger.newLine();
@@ -4843,8 +5074,8 @@ async function configCommand() {
4843
5074
 
4844
5075
  // src/commands/login.ts
4845
5076
  init_logger();
4846
- async function loginCommand(options = {}) {
4847
- const env = options.env ?? "dev";
5077
+ async function loginCommand(options) {
5078
+ const env = options.env;
4848
5079
  const apiUrl = getApiUrl(env);
4849
5080
  logger.header("OneX Theme Developer Login");
4850
5081
  logger.info(`Environment: ${env} (${apiUrl})`);
@@ -4933,8 +5164,8 @@ async function loginCommand(options = {}) {
4933
5164
 
4934
5165
  // src/commands/logout.ts
4935
5166
  init_logger();
4936
- async function logoutCommand(options = {}) {
4937
- const env = options.env ?? "dev";
5167
+ async function logoutCommand(options) {
5168
+ const env = options.env;
4938
5169
  const tokens = loadAuthTokens(env);
4939
5170
  if (!tokens) {
4940
5171
  logger.info(`Not logged in to ${env} environment.`);
@@ -4946,8 +5177,8 @@ async function logoutCommand(options = {}) {
4946
5177
 
4947
5178
  // src/commands/whoami.ts
4948
5179
  init_logger();
4949
- async function whoamiCommand(options = {}) {
4950
- const env = options.env ?? "dev";
5180
+ async function whoamiCommand(options) {
5181
+ const env = options.env;
4951
5182
  const tokens = loadAuthTokens(env);
4952
5183
  if (!tokens) {
4953
5184
  logger.error(
@@ -5200,11 +5431,11 @@ function diffFieldList(prior, current, pathPrefix, out) {
5200
5431
  }
5201
5432
  }
5202
5433
  }
5203
- function diffFieldPair(p, c, path23, out) {
5434
+ function diffFieldPair(p, c, path25, out) {
5204
5435
  if (p.type !== c.type) {
5205
5436
  out.push({
5206
5437
  kind: "breaking",
5207
- path: path23,
5438
+ path: path25,
5208
5439
  detail: `Type changed (${p.type} \u2192 ${c.type}). Saved values may misrender.`
5209
5440
  });
5210
5441
  return;
@@ -5212,7 +5443,7 @@ function diffFieldPair(p, c, path23, out) {
5212
5443
  if (p.required !== true && c.required === true) {
5213
5444
  out.push({
5214
5445
  kind: "breaking",
5215
- path: path23,
5446
+ path: path25,
5216
5447
  detail: "Field became required. Existing empty instances now invalid."
5217
5448
  });
5218
5449
  }
@@ -5220,7 +5451,7 @@ function diffFieldPair(p, c, path23, out) {
5220
5451
  if ((c.maxLength ?? Infinity) < (p.maxLength ?? Infinity)) {
5221
5452
  out.push({
5222
5453
  kind: "breaking",
5223
- path: path23,
5454
+ path: path25,
5224
5455
  detail: `maxLength tightened (${p.maxLength ?? "\u221E"} \u2192 ${c.maxLength}).`
5225
5456
  });
5226
5457
  }
@@ -5229,7 +5460,7 @@ function diffFieldPair(p, c, path23, out) {
5229
5460
  if ((c.min ?? -Infinity) > (p.min ?? -Infinity)) {
5230
5461
  out.push({
5231
5462
  kind: "breaking",
5232
- path: path23,
5463
+ path: path25,
5233
5464
  detail: `min raised (${p.min ?? "-\u221E"} \u2192 ${c.min}).`
5234
5465
  });
5235
5466
  }
@@ -5238,7 +5469,7 @@ function diffFieldPair(p, c, path23, out) {
5238
5469
  if ((c.max ?? Infinity) < (p.max ?? Infinity)) {
5239
5470
  out.push({
5240
5471
  kind: "breaking",
5241
- path: path23,
5472
+ path: path25,
5242
5473
  detail: `max lowered (${p.max ?? "\u221E"} \u2192 ${c.max}).`
5243
5474
  });
5244
5475
  }
@@ -5251,14 +5482,14 @@ function diffFieldPair(p, c, path23, out) {
5251
5482
  if (removed.length > 0) {
5252
5483
  out.push({
5253
5484
  kind: "breaking",
5254
- path: path23,
5485
+ path: path25,
5255
5486
  detail: `Option(s) removed: ${removed.join(", ")}. Existing saved values may be orphaned.`
5256
5487
  });
5257
5488
  }
5258
5489
  if (added.length > 0) {
5259
5490
  out.push({
5260
5491
  kind: "additive",
5261
- path: path23,
5492
+ path: path25,
5262
5493
  detail: `Option(s) added: ${added.join(", ")}.`
5263
5494
  });
5264
5495
  }
@@ -5266,7 +5497,7 @@ function diffFieldPair(p, c, path23, out) {
5266
5497
  if (!deepEqual(p.default, c.default)) {
5267
5498
  out.push({
5268
5499
  kind: "defaults-only",
5269
- path: path23,
5500
+ path: path25,
5270
5501
  detail: `Default changed: ${JSON.stringify(p.default)} \u2192 ${JSON.stringify(c.default)}.`
5271
5502
  });
5272
5503
  }
@@ -5324,7 +5555,7 @@ function deepEqual(a, b) {
5324
5555
 
5325
5556
  // src/commands/publish.ts
5326
5557
  async function publishCommand(options) {
5327
- const env = options.env ?? "dev";
5558
+ const env = options.env;
5328
5559
  logger.header("OneX Theme Publish");
5329
5560
  logger.info(`Environment: ${env} (${getApiUrl(env)})`);
5330
5561
  logger.newLine();
@@ -5338,13 +5569,13 @@ async function publishCommand(options) {
5338
5569
  logger.info(`Logged in as: ${tokens.user.email}`);
5339
5570
  let themePath;
5340
5571
  if (options.theme) {
5341
- themePath = path11.resolve(options.theme);
5572
+ themePath = path13.resolve(options.theme);
5342
5573
  } else {
5343
5574
  const isThemeDir2 = [
5344
5575
  "theme.config.ts",
5345
5576
  "bundle-entry.ts",
5346
5577
  "manifest.ts"
5347
- ].some((f) => fs.existsSync(path11.join(process.cwd(), f)));
5578
+ ].some((f) => fs8.existsSync(path13.join(process.cwd(), f)));
5348
5579
  if (isThemeDir2) {
5349
5580
  themePath = process.cwd();
5350
5581
  } else {
@@ -5354,13 +5585,13 @@ async function publishCommand(options) {
5354
5585
  process.exit(1);
5355
5586
  }
5356
5587
  }
5357
- const pkgPath = path11.join(themePath, "package.json");
5358
- if (!fs.existsSync(pkgPath)) {
5588
+ const pkgPath = path13.join(themePath, "package.json");
5589
+ if (!fs8.existsSync(pkgPath)) {
5359
5590
  logger.error("No package.json found in theme directory");
5360
5591
  process.exit(1);
5361
5592
  }
5362
- const pkg = fs.readJsonSync(pkgPath);
5363
- const themeId = pkg.name?.replace("@onex-themes/", "") || path11.basename(themePath);
5593
+ const pkg = fs8.readJsonSync(pkgPath);
5594
+ const themeId = pkg.name?.replace("@onex-themes/", "") || path13.basename(themePath);
5364
5595
  if (options.bump) {
5365
5596
  const currentVersion = pkg.version || "1.0.0";
5366
5597
  const newVersion = semver.inc(currentVersion, options.bump);
@@ -5369,7 +5600,7 @@ async function publishCommand(options) {
5369
5600
  process.exit(1);
5370
5601
  }
5371
5602
  pkg.version = newVersion;
5372
- fs.writeJsonSync(pkgPath, pkg, { spaces: 2 });
5603
+ fs8.writeJsonSync(pkgPath, pkg, { spaces: 2 });
5373
5604
  logger.info(`Bumped version: ${currentVersion} -> ${newVersion}`);
5374
5605
  }
5375
5606
  const version2 = pkg.version || "1.0.0";
@@ -5476,7 +5707,7 @@ Or use the --bump flag:
5476
5707
  logger.error(error instanceof Error ? error.message : "Build error");
5477
5708
  process.exit(1);
5478
5709
  }
5479
- const distDir = path11.join(themePath, "dist");
5710
+ const distDir = path13.join(themePath, "dist");
5480
5711
  const classification = await runSchemaDiffGate(
5481
5712
  themeId,
5482
5713
  distDir,
@@ -5525,8 +5756,8 @@ Or use the --bump flag:
5525
5756
  for (const [originalPath, url] of Object.entries(videoUrls)) {
5526
5757
  assetMap[originalPath] = url;
5527
5758
  }
5528
- const assetMapPath = path11.join(distDir, "asset-map.json");
5529
- await fs.writeFile(assetMapPath, JSON.stringify(assetMap, null, 2));
5759
+ const assetMapPath = path13.join(distDir, "asset-map.json");
5760
+ await fs8.writeFile(assetMapPath, JSON.stringify(assetMap, null, 2));
5530
5761
  } catch (error) {
5531
5762
  logger.error(
5532
5763
  `Failed to write asset-map.json: ${error instanceof Error ? error.message : "unknown"}`
@@ -5601,7 +5832,7 @@ Or use the --bump flag:
5601
5832
  continue;
5602
5833
  }
5603
5834
  try {
5604
- const buf = await fs.promises.readFile(entry.absPath);
5835
+ const buf = await fs8.promises.readFile(entry.absPath);
5605
5836
  const res = await fetch(item.upload_url, {
5606
5837
  method: "PUT",
5607
5838
  headers: {
@@ -5643,12 +5874,12 @@ Or use the --bump flag:
5643
5874
  }
5644
5875
  logger.startSpinner("Uploading bundle...");
5645
5876
  try {
5646
- if (!fs.existsSync(distDir)) {
5877
+ if (!fs8.existsSync(distDir)) {
5647
5878
  logger.stopSpinner(false, "No dist/ directory");
5648
5879
  logger.error("Build the theme first: onexthm build");
5649
5880
  process.exit(1);
5650
5881
  }
5651
- const bundleZipPath = path11.join(themePath, "dist", "bundle.zip");
5882
+ const bundleZipPath = path13.join(themePath, "dist", "bundle.zip");
5652
5883
  await createZip(distDir, bundleZipPath, [
5653
5884
  "bundle.zip",
5654
5885
  "source.zip",
@@ -5657,7 +5888,7 @@ Or use the --bump flag:
5657
5888
  "theme-assets",
5658
5889
  "theme-assets/**"
5659
5890
  ]);
5660
- const bundleBuffer = fs.readFileSync(bundleZipPath);
5891
+ const bundleBuffer = fs8.readFileSync(bundleZipPath);
5661
5892
  const bundleRes = await fetch(bundleUploadUrl, {
5662
5893
  method: "PUT",
5663
5894
  headers: { "Content-Type": "application/zip" },
@@ -5675,7 +5906,7 @@ Or use the --bump flag:
5675
5906
  }
5676
5907
  logger.startSpinner("Uploading source...");
5677
5908
  try {
5678
- const sourceZipPath = path11.join(themePath, "dist", "source.zip");
5909
+ const sourceZipPath = path13.join(themePath, "dist", "source.zip");
5679
5910
  await createZip(themePath, sourceZipPath, [
5680
5911
  "node_modules",
5681
5912
  "dist",
@@ -5683,7 +5914,7 @@ Or use the --bump flag:
5683
5914
  ".env",
5684
5915
  ".env.local"
5685
5916
  ]);
5686
- const sourceBuffer = fs.readFileSync(sourceZipPath);
5917
+ const sourceBuffer = fs8.readFileSync(sourceZipPath);
5687
5918
  const sourceRes = await fetch(sourceUploadUrl, {
5688
5919
  method: "PUT",
5689
5920
  headers: { "Content-Type": "application/zip" },
@@ -5761,9 +5992,9 @@ async function uploadThumbnail(apiUrl, themeId, themePath, distDir, env = "dev")
5761
5992
  let imageBase64 = null;
5762
5993
  let mimeType = "image/png";
5763
5994
  for (const { file, mime } of THUMBNAIL_CANDIDATES) {
5764
- const candidate = path11.join(themePath, file);
5765
- if (fs.existsSync(candidate)) {
5766
- const buf = fs.readFileSync(candidate);
5995
+ const candidate = path13.join(themePath, file);
5996
+ if (fs8.existsSync(candidate)) {
5997
+ const buf = fs8.readFileSync(candidate);
5767
5998
  imageBase64 = `data:${mime};base64,${buf.toString("base64")}`;
5768
5999
  mimeType = mime;
5769
6000
  logger.info(`Using local thumbnail: ${file}`);
@@ -5863,7 +6094,7 @@ async function screenshotHomePage(themePath, distDir) {
5863
6094
  const { compilePreviewRuntime: compilePreviewRuntime2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
5864
6095
  const { createDevServer: createDevServer2 } = await Promise.resolve().then(() => (init_dev_server(), dev_server_exports));
5865
6096
  const previewRuntimePath = await compilePreviewRuntime2(themePath);
5866
- const themeName = path11.basename(themePath);
6097
+ const themeName = path13.basename(themePath);
5867
6098
  const port = await findFreePort(4500);
5868
6099
  const server = createDevServer2({
5869
6100
  port,
@@ -5920,7 +6151,7 @@ async function findFreePort(start) {
5920
6151
  });
5921
6152
  }
5922
6153
  async function uploadVideoMultipart(apiUrl, themeId, video, env = "dev") {
5923
- const fileName = path11.basename(video.originalPath);
6154
+ const fileName = path13.basename(video.originalPath);
5924
6155
  const videoInitUrl = `${apiUrl}/media/videos/multipart/init`;
5925
6156
  const videoInitBody = {
5926
6157
  file_name: fileName,
@@ -5956,7 +6187,7 @@ async function uploadVideoMultipart(apiUrl, themeId, video, env = "dev") {
5956
6187
  );
5957
6188
  }
5958
6189
  const { upload_id, file_key, chunk_size, chunk_urls } = initBody;
5959
- const fileBuffer = await fs.promises.readFile(video.absPath);
6190
+ const fileBuffer = await fs8.promises.readFile(video.absPath);
5960
6191
  const CHUNK_CONCURRENCY = 4;
5961
6192
  const queue = [...chunk_urls];
5962
6193
  const parts = [];
@@ -6065,7 +6296,7 @@ async function runSchemaDiffGate(themeId, distDir, env, options) {
6065
6296
  let currentAssets;
6066
6297
  try {
6067
6298
  currentSchemas = JSON.parse(
6068
- await fs.readFile(path11.join(distDir, "schemas.json"), "utf-8")
6299
+ await fs8.readFile(path13.join(distDir, "schemas.json"), "utf-8")
6069
6300
  );
6070
6301
  } catch (err) {
6071
6302
  logger.warning(
@@ -6075,7 +6306,7 @@ async function runSchemaDiffGate(themeId, distDir, env, options) {
6075
6306
  }
6076
6307
  try {
6077
6308
  currentAssets = JSON.parse(
6078
- await fs.readFile(path11.join(distDir, "asset-manifest.json"), "utf-8")
6309
+ await fs8.readFile(path13.join(distDir, "asset-manifest.json"), "utf-8")
6079
6310
  );
6080
6311
  } catch {
6081
6312
  currentAssets = { manifestVersion: 1, assets: [] };
@@ -6145,24 +6376,24 @@ var AI_CONTEXT_FILES = [
6145
6376
  ".mcp.json"
6146
6377
  ];
6147
6378
  function resolveTargetDir(opts) {
6148
- return path11.resolve(opts.cwd ?? process.cwd());
6379
+ return path13.resolve(opts.cwd ?? process.cwd());
6149
6380
  }
6150
6381
  function resolveDefaultTemplateDir() {
6151
- return path11.join(getTemplatesDir(), "default");
6382
+ return path13.join(getTemplatesDir(), "default");
6152
6383
  }
6153
6384
  function isThemeDir(dir) {
6154
- return fs.existsSync(path11.join(dir, "theme.config.ts")) || fs.existsSync(path11.join(dir, "theme.config.js"));
6385
+ return fs8.existsSync(path13.join(dir, "theme.config.ts")) || fs8.existsSync(path13.join(dir, "theme.config.js"));
6155
6386
  }
6156
6387
  function inspectFiles(templateDir, targetDir) {
6157
6388
  return AI_CONTEXT_FILES.map((name) => {
6158
- const templatePath = path11.join(templateDir, name);
6159
- const targetPath = path11.join(targetDir, name);
6160
- const exists = fs.existsSync(targetPath);
6389
+ const templatePath = path13.join(templateDir, name);
6390
+ const targetPath = path13.join(targetDir, name);
6391
+ const exists = fs8.existsSync(targetPath);
6161
6392
  let identical = false;
6162
- if (exists && fs.existsSync(templatePath)) {
6393
+ if (exists && fs8.existsSync(templatePath)) {
6163
6394
  try {
6164
- const a = fs.readFileSync(templatePath, "utf-8");
6165
- const b = fs.readFileSync(targetPath, "utf-8");
6395
+ const a = fs8.readFileSync(templatePath, "utf-8");
6396
+ const b = fs8.readFileSync(targetPath, "utf-8");
6166
6397
  identical = a.replace(/\r\n/g, "\n") === b.replace(/\r\n/g, "\n");
6167
6398
  } catch {
6168
6399
  identical = false;
@@ -6212,11 +6443,11 @@ async function mcpSetupCommand(options = {}) {
6212
6443
  }
6213
6444
  }
6214
6445
  for (const s of missing) {
6215
- if (!fs.existsSync(s.templatePath)) {
6446
+ if (!fs8.existsSync(s.templatePath)) {
6216
6447
  logger.warning(` ! ${s.name} not in template \u2014 skipped`);
6217
6448
  continue;
6218
6449
  }
6219
- await fs.copy(s.templatePath, s.targetPath);
6450
+ await fs8.copy(s.templatePath, s.targetPath);
6220
6451
  logger.success(` \u2713 ${s.name}`);
6221
6452
  }
6222
6453
  logger.log("");
@@ -6277,11 +6508,11 @@ async function mcpUpgradeCommand(options = {}) {
6277
6508
  }
6278
6509
  }
6279
6510
  for (const s of toUpgrade) {
6280
- if (!fs.existsSync(s.templatePath)) {
6511
+ if (!fs8.existsSync(s.templatePath)) {
6281
6512
  logger.warning(` ! ${s.name} not in template \u2014 skipped`);
6282
6513
  continue;
6283
6514
  }
6284
- await fs.copy(s.templatePath, s.targetPath, { overwrite: true });
6515
+ await fs8.copy(s.templatePath, s.targetPath, { overwrite: true });
6285
6516
  logger.success(` \u2713 ${s.name}`);
6286
6517
  }
6287
6518
  logger.log("");
@@ -6299,12 +6530,12 @@ async function mcpDoctorCommand(options = {}) {
6299
6530
  return;
6300
6531
  }
6301
6532
  logger.success("theme.config.ts present");
6302
- const mcpJsonPath = path11.join(targetDir, ".mcp.json");
6303
- if (!fs.existsSync(mcpJsonPath)) {
6533
+ const mcpJsonPath = path13.join(targetDir, ".mcp.json");
6534
+ if (!fs8.existsSync(mcpJsonPath)) {
6304
6535
  logger.error(".mcp.json missing \u2014 run `onexthm mcp setup`");
6305
6536
  } else {
6306
6537
  try {
6307
- const mcpJson = JSON.parse(fs.readFileSync(mcpJsonPath, "utf-8"));
6538
+ const mcpJson = JSON.parse(fs8.readFileSync(mcpJsonPath, "utf-8"));
6308
6539
  const servers = mcpJson?.mcpServers ?? {};
6309
6540
  if (servers.onexthm) {
6310
6541
  logger.success(".mcp.json registers `onexthm`");
@@ -6337,8 +6568,8 @@ async function mcpDoctorCommand(options = {}) {
6337
6568
  logger.success(`${s.name} up to date`);
6338
6569
  }
6339
6570
  }
6340
- const registryPath = path11.join(targetDir, "sections-registry.ts");
6341
- if (fs.existsSync(registryPath)) {
6571
+ const registryPath = path13.join(targetDir, "sections-registry.ts");
6572
+ if (fs8.existsSync(registryPath)) {
6342
6573
  logger.success("sections-registry.ts present");
6343
6574
  } else {
6344
6575
  logger.warning(
@@ -6349,24 +6580,27 @@ async function mcpDoctorCommand(options = {}) {
6349
6580
 
6350
6581
  // src/cli.ts
6351
6582
  dotenv.config({
6352
- path: path11.join(process.cwd(), ".env.local"),
6583
+ path: path13.join(process.cwd(), ".env.local"),
6353
6584
  override: true
6354
6585
  });
6355
- dotenv.config({ path: path11.join(process.cwd(), ".env") });
6586
+ dotenv.config({ path: path13.join(process.cwd(), ".env") });
6356
6587
  try {
6357
6588
  const projectRoot = getProjectRoot();
6358
- if (path11.resolve(projectRoot) !== path11.resolve(process.cwd())) {
6589
+ if (path13.resolve(projectRoot) !== path13.resolve(process.cwd())) {
6359
6590
  dotenv.config({
6360
- path: path11.join(projectRoot, ".env.local")
6591
+ path: path13.join(projectRoot, ".env.local")
6361
6592
  });
6362
- dotenv.config({ path: path11.join(projectRoot, ".env") });
6593
+ dotenv.config({ path: path13.join(projectRoot, ".env") });
6363
6594
  }
6364
6595
  } catch {
6365
6596
  }
6366
6597
  dotenv.config({
6367
- path: path11.join(os.homedir(), ".onexthm", ".env"),
6598
+ path: path13.join(os.homedir(), ".onexthm", ".env"),
6368
6599
  quiet: true
6369
6600
  });
6601
+ function envOpt() {
6602
+ return new Option("--env <env>", "Target environment: dev, staging, or prod").choices(["dev", "staging", "prod"]).makeOptionMandatory();
6603
+ }
6370
6604
  var require2 = createRequire(import.meta.url);
6371
6605
  var { version } = require2("../package.json");
6372
6606
  var program = new Command();
@@ -6375,11 +6609,7 @@ program.command("init").description("Create a new OneX theme project").argument(
6375
6609
  "-t, --template <template>",
6376
6610
  "Template to use (default, minimal)",
6377
6611
  "default"
6378
- ).option("--no-install", "Skip installing dependencies").option("--git", "Initialize git repository").option("-y, --yes", "Skip prompts and use defaults").option(
6379
- "--env <env>",
6380
- "Target environment: dev, staging, or prod (default: dev)",
6381
- "dev"
6382
- ).action(initCommand);
6612
+ ).option("--no-install", "Skip installing dependencies").option("--git", "Initialize git repository").option("-y, --yes", "Skip prompts and use defaults").addOption(envOpt()).action(initCommand);
6383
6613
  program.command("create:section").alias("cs").description("Create a new section").argument("<name>", "Name of the section (e.g., hero, features)").option("-t, --theme <theme>", "Theme to create section in").option(
6384
6614
  "-c, --category <category>",
6385
6615
  "Section category (headers, content, footers)"
@@ -6406,36 +6636,16 @@ program.command("download").description("Download a published theme via the webs
6406
6636
  "-v, --version <version>",
6407
6637
  "Theme version (default: latest)",
6408
6638
  "latest"
6409
- ).option(
6410
- "--env <env>",
6411
- "Target environment: dev, staging, or prod (default: dev)",
6412
- "dev"
6413
- ).option("-b, --bucket <name>", "[deprecated] ignored").option("-o, --output <dir>", "Output directory", "./active-theme").action(downloadCommand);
6639
+ ).addOption(envOpt()).option("-b, --bucket <name>", "[deprecated] ignored").option("-o, --output <dir>", "Output directory", "./active-theme").action(downloadCommand);
6414
6640
  program.command("clone").description("Clone theme source code via the website-api").argument("<theme-name>", "Theme to clone").option(
6415
6641
  "-v, --version <version>",
6416
6642
  "Theme version (default: latest)",
6417
6643
  "latest"
6418
- ).option("-n, --name <name>", "New theme name (skips interactive prompt)").option("-o, --output <dir>", "Output directory").option(
6419
- "--env <env>",
6420
- "Target environment: dev, staging, or prod (default: dev)",
6421
- "dev"
6422
- ).option("-b, --bucket <name>", "[deprecated] ignored").option("--no-install", "Skip running pnpm install after clone").action(cloneCommand);
6644
+ ).option("-n, --name <name>", "New theme name (skips interactive prompt)").option("-o, --output <dir>", "Output directory").addOption(envOpt()).option("-b, --bucket <name>", "[deprecated] ignored").option("--no-install", "Skip running pnpm install after clone").action(cloneCommand);
6423
6645
  program.command("config").description("Configure OneX CLI credentials (AWS, API keys)").action(configCommand);
6424
- program.command("login").description("Login to OneX platform").option(
6425
- "--env <env>",
6426
- "Target environment: dev, staging, or prod (default: dev)",
6427
- "dev"
6428
- ).action(loginCommand);
6429
- program.command("logout").description("Logout from OneX platform").option(
6430
- "--env <env>",
6431
- "Target environment: dev, staging, or prod (default: dev)",
6432
- "dev"
6433
- ).action(logoutCommand);
6434
- program.command("whoami").description("Show current logged-in developer").option(
6435
- "--env <env>",
6436
- "Target environment: dev, staging, or prod (default: dev)",
6437
- "dev"
6438
- ).action(whoamiCommand);
6646
+ program.command("login").description("Login to OneX platform").addOption(envOpt()).action(loginCommand);
6647
+ program.command("logout").description("Logout from OneX platform").addOption(envOpt()).action(logoutCommand);
6648
+ program.command("whoami").description("Show current logged-in developer").addOption(envOpt()).action(whoamiCommand);
6439
6649
  var mcpCmd = program.command("mcp").description("Manage MCP server registration and AI-context files");
6440
6650
  mcpCmd.command("setup").description(
6441
6651
  "Install .mcp.json + CLAUDE.md + AGENTS.md + .cursorrules into the current theme"
@@ -6447,11 +6657,7 @@ mcpCmd.command("doctor").description("Diagnose MCP setup in the current theme di
6447
6657
  program.command("publish").description("Build, scan, and publish theme to marketplace (requires login)").option("-t, --theme <path>", "Theme directory path").option(
6448
6658
  "--bump <type>",
6449
6659
  "Auto-bump version before publish (patch|minor|major)"
6450
- ).option(
6451
- "--env <env>",
6452
- "Target environment: dev, staging, or prod (default: dev)",
6453
- "dev"
6454
- ).option(
6660
+ ).addOption(envOpt()).option(
6455
6661
  "--dry-run",
6456
6662
  "Build locally and print the schema-diff classification without publishing"
6457
6663
  ).option(