@onexapis/cli 1.1.64 → 1.1.66

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/index.mjs CHANGED
@@ -1,15 +1,15 @@
1
1
  import chalk4 from 'chalk';
2
2
  import ora from 'ora';
3
- import * as esbuild from 'esbuild';
4
- import path8 from 'path';
5
- import fs7 from 'fs/promises';
6
- import crypto from 'crypto';
3
+ import path10 from 'path';
7
4
  import { glob } from 'glob';
5
+ import fs from 'fs-extra';
6
+ import crypto from 'crypto';
7
+ import * as esbuild from 'esbuild';
8
+ import fs8 from 'fs/promises';
8
9
  import { createRequire } from 'module';
9
10
  import fs3 from 'fs';
10
11
  import { execSync, spawn } from 'child_process';
11
12
  import inquirer from 'inquirer';
12
- import fs from 'fs-extra';
13
13
  import ejs from 'ejs';
14
14
  import os from 'os';
15
15
  import AdmZip from 'adm-zip';
@@ -85,6 +85,187 @@ var init_logger = __esm({
85
85
  logger = new Logger();
86
86
  }
87
87
  });
88
+ function sortedCopy(value) {
89
+ if (Array.isArray(value)) {
90
+ return value.map((v) => sortedCopy(v));
91
+ }
92
+ if (value && typeof value === "object") {
93
+ const sorted = {};
94
+ for (const key of Object.keys(value).sort()) {
95
+ sorted[key] = sortedCopy(value[key]);
96
+ }
97
+ return sorted;
98
+ }
99
+ return value;
100
+ }
101
+ function normalizeField(raw) {
102
+ const out = {
103
+ id: String(raw.id),
104
+ type: String(raw.type)
105
+ };
106
+ if (raw.required === true) out.required = true;
107
+ if (raw.default !== void 0) out.default = raw.default;
108
+ if (Array.isArray(raw.aliases) && raw.aliases.length > 0) {
109
+ out.aliases = [...raw.aliases].map(String).sort();
110
+ }
111
+ if (typeof raw.maxLength === "number") out.maxLength = raw.maxLength;
112
+ if (typeof raw.min === "number") out.min = raw.min;
113
+ if (typeof raw.max === "number") out.max = raw.max;
114
+ if (typeof raw.step === "number") out.step = raw.step;
115
+ if (Array.isArray(raw.accept)) {
116
+ out.accept = [...raw.accept].map(String).sort();
117
+ }
118
+ if (Array.isArray(raw.options)) {
119
+ out.options = raw.options.map((o) => String(o?.value ?? o)).sort();
120
+ }
121
+ return out;
122
+ }
123
+ function normalizeBlock(raw) {
124
+ return {
125
+ type: String(raw.type),
126
+ settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
127
+ defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
128
+ ...typeof raw.limit === "number" ? { limit: raw.limit } : {},
129
+ ...typeof raw.min === "number" ? { min: raw.min } : {},
130
+ ...raw.sortable === true ? { sortable: true } : {},
131
+ ...raw.baseType ? { baseType: String(raw.baseType) } : {}
132
+ };
133
+ }
134
+ function normalizeTemplate(raw) {
135
+ const out = { id: String(raw.id) };
136
+ if (raw.isDefault === true) out.isDefault = true;
137
+ if (Array.isArray(raw.settings)) {
138
+ out.settings = raw.settings.map(normalizeField).sort(sortFieldsById);
139
+ }
140
+ if (raw.defaults && typeof raw.defaults === "object") {
141
+ out.defaults = sortedCopy(raw.defaults);
142
+ }
143
+ return out;
144
+ }
145
+ function sortFieldsById(a, b) {
146
+ return a.id.localeCompare(b.id);
147
+ }
148
+ function sortByType(a, b) {
149
+ return a.type.localeCompare(b.type);
150
+ }
151
+ function normalizeSection(raw) {
152
+ return {
153
+ type: String(raw.type),
154
+ settings: Array.isArray(raw.settings) ? raw.settings.map(normalizeField).sort(sortFieldsById) : [],
155
+ defaults: raw.defaults && typeof raw.defaults === "object" ? sortedCopy(raw.defaults) : {},
156
+ blocks: Array.isArray(raw.blocks) ? raw.blocks.map(normalizeBlock).sort(sortByType) : [],
157
+ templates: Array.isArray(raw.templates) ? raw.templates.map(normalizeTemplate).sort(sortFieldsById) : [],
158
+ dataRequirements: raw.dataRequirements && typeof raw.dataRequirements === "object" ? sortedCopy(raw.dataRequirements) : null,
159
+ ...raw.global === true ? { global: true } : {},
160
+ ...typeof raw.maxBlocks === "number" ? { maxBlocks: raw.maxBlocks } : {}
161
+ };
162
+ }
163
+ async function extractSchemas(themePath) {
164
+ const { createJiti } = await import('jiti');
165
+ const jiti = createJiti(import.meta.url);
166
+ const schemaFiles = await glob("sections/**/*.schema.ts", { cwd: themePath });
167
+ const sections = {};
168
+ for (const file of schemaFiles) {
169
+ try {
170
+ const mod = await jiti.import(path10.join(themePath, file));
171
+ const exports$1 = mod;
172
+ for (const value of Object.values(exports$1)) {
173
+ if (value && typeof value === "object" && typeof value.type === "string" && Array.isArray(value.settings)) {
174
+ const section = normalizeSection(value);
175
+ sections[section.type] = section;
176
+ }
177
+ }
178
+ } catch {
179
+ }
180
+ }
181
+ const manifest = {
182
+ manifestVersion: 1,
183
+ sections: {}
184
+ };
185
+ for (const type of Object.keys(sections).sort()) {
186
+ manifest.sections[type] = sections[type];
187
+ }
188
+ return manifest;
189
+ }
190
+ function serializeManifest(manifest) {
191
+ return JSON.stringify(sortedCopy(manifest), null, 2);
192
+ }
193
+ var init_extract_schemas = __esm({
194
+ "src/utils/extract-schemas.ts"() {
195
+ }
196
+ });
197
+ function mimeFor(filename) {
198
+ const ext = path10.extname(filename).toLowerCase();
199
+ return MIME_MAP[ext] || "application/octet-stream";
200
+ }
201
+ async function sha256Prefix(absPath, len) {
202
+ const buf = await fs.readFile(absPath);
203
+ return crypto.createHash("sha256").update(buf).digest("hex").slice(0, len);
204
+ }
205
+ function insertHashIntoName(relPath, hash) {
206
+ const dir = path10.posix.dirname(relPath);
207
+ const base = path10.posix.basename(relPath);
208
+ const ext = path10.posix.extname(base);
209
+ const stem = ext ? base.slice(0, -ext.length) : base;
210
+ const hashed = `${stem}-${hash}${ext}`;
211
+ return dir === "." ? hashed : `${dir}/${hashed}`;
212
+ }
213
+ async function scanThemeAssets(distDir) {
214
+ const assetsDir = path10.join(distDir, "theme-assets");
215
+ if (!await fs.pathExists(assetsDir)) return [];
216
+ const files = await glob("**/*", {
217
+ cwd: assetsDir,
218
+ nodir: true,
219
+ dot: false
220
+ });
221
+ const results = [];
222
+ for (const rel of files) {
223
+ const absPath = path10.join(assetsDir, rel);
224
+ const stat = await fs.stat(absPath);
225
+ if (!stat.isFile()) continue;
226
+ const originalPath = rel.split(path10.sep).join("/");
227
+ const hash = await sha256Prefix(absPath, HASH_LEN);
228
+ const hashedPath = insertHashIntoName(originalPath, hash);
229
+ const contentType = mimeFor(rel);
230
+ results.push({
231
+ originalPath,
232
+ hashedPath,
233
+ hash,
234
+ size: stat.size,
235
+ contentType,
236
+ absPath
237
+ });
238
+ }
239
+ results.sort((a, b) => a.originalPath.localeCompare(b.originalPath));
240
+ return results;
241
+ }
242
+ var MIME_MAP, HASH_LEN;
243
+ var init_scan_theme_assets = __esm({
244
+ "src/utils/scan-theme-assets.ts"() {
245
+ MIME_MAP = {
246
+ ".png": "image/png",
247
+ ".jpg": "image/jpeg",
248
+ ".jpeg": "image/jpeg",
249
+ ".gif": "image/gif",
250
+ ".webp": "image/webp",
251
+ ".avif": "image/avif",
252
+ ".svg": "image/svg+xml",
253
+ ".ico": "image/x-icon",
254
+ ".bmp": "image/bmp",
255
+ ".woff": "font/woff",
256
+ ".woff2": "font/woff2",
257
+ ".ttf": "font/ttf",
258
+ ".otf": "font/otf",
259
+ ".eot": "application/vnd.ms-fontobject",
260
+ ".mp4": "video/mp4",
261
+ ".webm": "video/webm",
262
+ ".mov": "video/quicktime",
263
+ ".ogg": "video/ogg",
264
+ ".json": "application/json"
265
+ };
266
+ HASH_LEN = 8;
267
+ }
268
+ });
88
269
 
89
270
  // src/utils/compile-theme.ts
90
271
  var compile_theme_exports = {};
@@ -100,8 +281,8 @@ async function generateThemeCSS(themePath, outDir) {
100
281
  const tailwindcss = (await import('tailwindcss')).default;
101
282
  const tailwindConfig = {
102
283
  content: [
103
- path8.join(themePath, "sections/**/*.{ts,tsx}"),
104
- path8.join(themePath, "components/**/*.{ts,tsx}")
284
+ path10.join(themePath, "sections/**/*.{ts,tsx}"),
285
+ path10.join(themePath, "components/**/*.{ts,tsx}")
105
286
  ],
106
287
  theme: { extend: {} },
107
288
  plugins: []
@@ -111,7 +292,7 @@ async function generateThemeCSS(themePath, outDir) {
111
292
  inputCSS,
112
293
  { from: void 0 }
113
294
  );
114
- await fs7.writeFile(path8.join(outDir, "bundle.css"), result.css);
295
+ await fs8.writeFile(path10.join(outDir, "bundle.css"), result.css);
115
296
  logger.info("Generated bundle.css");
116
297
  } catch (err) {
117
298
  logger.warning(
@@ -122,12 +303,12 @@ async function generateThemeCSS(themePath, outDir) {
122
303
  async function resolveNodeModulesFile(startDir, relativePath) {
123
304
  let dir = startDir;
124
305
  while (true) {
125
- const candidate = path8.join(dir, "node_modules", relativePath);
306
+ const candidate = path10.join(dir, "node_modules", relativePath);
126
307
  try {
127
- await fs7.access(candidate);
308
+ await fs8.access(candidate);
128
309
  return candidate;
129
310
  } catch {
130
- const parent = path8.dirname(dir);
311
+ const parent = path10.dirname(dir);
131
312
  if (parent === dir) break;
132
313
  dir = parent;
133
314
  }
@@ -151,7 +332,7 @@ async function scanImportsFromPackage(sourceDir, packageName) {
151
332
  });
152
333
  for (const file of sourceFiles) {
153
334
  try {
154
- const content = await fs7.readFile(path8.join(sourceDir, file), "utf-8");
335
+ const content = await fs8.readFile(path10.join(sourceDir, file), "utf-8");
155
336
  for (const match of content.matchAll(namespaceImportRegex)) {
156
337
  const subpath = match[1] ? match[1].slice(1) : "";
157
338
  if (!result[subpath]) result[subpath] = /* @__PURE__ */ new Set();
@@ -205,17 +386,17 @@ function createCoreGlobalPlugin(themePath) {
205
386
  const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
206
387
  let distPath = await resolveNodeModulesFile(
207
388
  themePath,
208
- path8.join("@onexapis", "core", "dist", distFileName)
389
+ path10.join("@onexapis", "core", "dist", distFileName)
209
390
  );
210
391
  if (!distPath) {
211
392
  distPath = await resolveNodeModulesFile(
212
393
  __dirname,
213
- path8.join("@onexapis", "core", "dist", distFileName)
394
+ path10.join("@onexapis", "core", "dist", distFileName)
214
395
  );
215
396
  }
216
397
  try {
217
398
  if (!distPath) throw new Error("not found");
218
- const distContent = await fs7.readFile(distPath, "utf-8");
399
+ const distContent = await fs8.readFile(distPath, "utf-8");
219
400
  const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
220
401
  for (const m of exportMatches) {
221
402
  const names = m[1].split(",").map((n) => {
@@ -444,7 +625,7 @@ async function generateThemeData(themePath, outputDir, themeId) {
444
625
  const pages = {};
445
626
  for (const ext of [".ts", ".js"]) {
446
627
  try {
447
- const mod = await jiti.import(path8.join(themePath, `theme.config${ext}`));
628
+ const mod = await jiti.import(path10.join(themePath, `theme.config${ext}`));
448
629
  themeConfig = mod.default || mod;
449
630
  break;
450
631
  } catch {
@@ -452,20 +633,20 @@ async function generateThemeData(themePath, outputDir, themeId) {
452
633
  }
453
634
  for (const ext of [".ts", ".js"]) {
454
635
  try {
455
- const mod = await jiti.import(path8.join(themePath, `theme.layout${ext}`));
636
+ const mod = await jiti.import(path10.join(themePath, `theme.layout${ext}`));
456
637
  layoutConfig = mod.default || mod;
457
638
  break;
458
639
  } catch {
459
640
  }
460
641
  }
461
642
  const schemas = {};
462
- const sectionsDir = path8.join(themePath, "sections");
643
+ const sectionsDir = path10.join(themePath, "sections");
463
644
  try {
464
- const sectionDirs = await fs7.readdir(sectionsDir);
645
+ const sectionDirs = await fs8.readdir(sectionsDir);
465
646
  for (const dir of sectionDirs) {
466
- const schemaFile = path8.join(sectionsDir, dir, `${dir}.schema.ts`);
647
+ const schemaFile = path10.join(sectionsDir, dir, `${dir}.schema.ts`);
467
648
  try {
468
- await fs7.access(schemaFile);
649
+ await fs8.access(schemaFile);
469
650
  const mod = await jiti.import(schemaFile);
470
651
  for (const [key, value] of Object.entries(mod)) {
471
652
  if (key.endsWith("Schema") && value && typeof value === "object" && value.type) {
@@ -477,14 +658,14 @@ async function generateThemeData(themePath, outputDir, themeId) {
477
658
  }
478
659
  } catch {
479
660
  }
480
- const pagesDir = path8.join(themePath, "pages");
661
+ const pagesDir = path10.join(themePath, "pages");
481
662
  try {
482
- const files = await fs7.readdir(pagesDir);
663
+ const files = await fs8.readdir(pagesDir);
483
664
  for (const file of files) {
484
665
  if (!file.match(/\.(ts|js)$/)) continue;
485
666
  const name = file.replace(/\.(ts|js)$/, "");
486
667
  try {
487
- const mod = await jiti.import(path8.join(pagesDir, file));
668
+ const mod = await jiti.import(path10.join(pagesDir, file));
488
669
  const config = mod.default || mod;
489
670
  const sections = (config.sections || []).map((section) => {
490
671
  const schema = schemas[section.type];
@@ -512,8 +693,8 @@ async function generateThemeData(themePath, outputDir, themeId) {
512
693
  }
513
694
  } catch {
514
695
  }
515
- await fs7.writeFile(
516
- path8.join(outputDir, "theme-data.json"),
696
+ await fs8.writeFile(
697
+ path10.join(outputDir, "theme-data.json"),
517
698
  JSON.stringify(
518
699
  {
519
700
  themeId,
@@ -536,22 +717,22 @@ async function generateThemeData(themePath, outputDir, themeId) {
536
717
  logger.info(`Generated theme-data.json (${Object.keys(pages).length} pages)`);
537
718
  }
538
719
  async function contentHashEntry(outputDir) {
539
- const entryPath = path8.join(outputDir, "bundle-entry.js");
540
- const mapPath = path8.join(outputDir, "bundle-entry.js.map");
720
+ const entryPath = path10.join(outputDir, "bundle-entry.js");
721
+ const mapPath = path10.join(outputDir, "bundle-entry.js.map");
541
722
  let entryContent;
542
723
  try {
543
- entryContent = await fs7.readFile(entryPath, "utf-8");
724
+ entryContent = await fs8.readFile(entryPath, "utf-8");
544
725
  } catch {
545
- const indexPath = path8.join(outputDir, "index.js");
726
+ const indexPath = path10.join(outputDir, "index.js");
546
727
  try {
547
- entryContent = await fs7.readFile(indexPath, "utf-8");
728
+ entryContent = await fs8.readFile(indexPath, "utf-8");
548
729
  } catch {
549
730
  logger.warning("No entry file found in output, skipping content hash");
550
731
  return;
551
732
  }
552
733
  const hash2 = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
553
734
  const hashedName2 = `bundle-entry-${hash2}.js`;
554
- const indexMapPath = path8.join(outputDir, "index.js.map");
735
+ const indexMapPath = path10.join(outputDir, "index.js.map");
555
736
  const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
556
737
  entryContent = entryContent.replace(
557
738
  /\/\/# sourceMappingURL=index\.js\.map/,
@@ -559,18 +740,18 @@ async function contentHashEntry(outputDir) {
559
740
  );
560
741
  const oldFiles2 = await glob("bundle-entry-*.js*", { cwd: outputDir });
561
742
  for (const f of oldFiles2) {
562
- await fs7.unlink(path8.join(outputDir, f));
743
+ await fs8.unlink(path10.join(outputDir, f));
563
744
  }
564
- await fs7.writeFile(path8.join(outputDir, hashedName2), entryContent);
565
- await fs7.unlink(indexPath);
745
+ await fs8.writeFile(path10.join(outputDir, hashedName2), entryContent);
746
+ await fs8.unlink(indexPath);
566
747
  try {
567
- await fs7.unlink(entryPath);
748
+ await fs8.unlink(entryPath);
568
749
  } catch {
569
750
  }
570
- await fs7.writeFile(entryPath, entryContent);
751
+ await fs8.writeFile(entryPath, entryContent);
571
752
  try {
572
- await fs7.access(indexMapPath);
573
- await fs7.rename(indexMapPath, path8.join(outputDir, hashedMapName2));
753
+ await fs8.access(indexMapPath);
754
+ await fs8.rename(indexMapPath, path10.join(outputDir, hashedMapName2));
574
755
  } catch {
575
756
  }
576
757
  logger.info(`Entry hashed: ${hashedName2}`);
@@ -585,17 +766,17 @@ async function contentHashEntry(outputDir) {
585
766
  );
586
767
  const oldFiles = await glob("bundle-entry-*.js*", { cwd: outputDir });
587
768
  for (const f of oldFiles) {
588
- await fs7.unlink(path8.join(outputDir, f));
769
+ await fs8.unlink(path10.join(outputDir, f));
589
770
  }
590
- await fs7.writeFile(path8.join(outputDir, hashedName), entryContent);
771
+ await fs8.writeFile(path10.join(outputDir, hashedName), entryContent);
591
772
  try {
592
- await fs7.unlink(entryPath);
773
+ await fs8.unlink(entryPath);
593
774
  } catch {
594
775
  }
595
- await fs7.writeFile(entryPath, entryContent);
776
+ await fs8.writeFile(entryPath, entryContent);
596
777
  try {
597
- await fs7.access(mapPath);
598
- await fs7.rename(mapPath, path8.join(outputDir, hashedMapName));
778
+ await fs8.access(mapPath);
779
+ await fs8.rename(mapPath, path10.join(outputDir, hashedMapName));
599
780
  } catch {
600
781
  }
601
782
  logger.info(`Entry hashed: ${hashedName}`);
@@ -607,7 +788,7 @@ async function extractDataRequirements(themePath) {
607
788
  const requirements = {};
608
789
  for (const file of schemaFiles) {
609
790
  try {
610
- const mod = await jiti.import(path8.join(themePath, file));
791
+ const mod = await jiti.import(path10.join(themePath, file));
611
792
  const exports$1 = mod;
612
793
  for (const value of Object.values(exports$1)) {
613
794
  if (value && typeof value === "object" && typeof value.type === "string" && value.dataRequirements && typeof value.dataRequirements === "object") {
@@ -622,12 +803,46 @@ async function extractDataRequirements(themePath) {
622
803
  }
623
804
  return requirements;
624
805
  }
806
+ async function writeGateManifests(themePath, outputDir) {
807
+ try {
808
+ const schemas = await extractSchemas(themePath);
809
+ await fs8.writeFile(
810
+ path10.join(outputDir, "schemas.json"),
811
+ serializeManifest(schemas)
812
+ );
813
+ logger.info(
814
+ `Generated schemas.json (${Object.keys(schemas.sections).length} sections)`
815
+ );
816
+ } catch (err) {
817
+ logger.warning(
818
+ `schemas.json not written: ${err instanceof Error ? err.message : String(err)}`
819
+ );
820
+ }
821
+ try {
822
+ const entries = await scanThemeAssets(outputDir);
823
+ const assets = entries.map((e) => ({
824
+ path: e.originalPath,
825
+ hash: e.hash,
826
+ size: e.size,
827
+ contentType: e.contentType
828
+ }));
829
+ await fs8.writeFile(
830
+ path10.join(outputDir, "asset-manifest.json"),
831
+ JSON.stringify({ manifestVersion: 1, assets }, null, 2)
832
+ );
833
+ logger.info(`Generated asset-manifest.json (${assets.length} assets)`);
834
+ } catch (err) {
835
+ logger.warning(
836
+ `asset-manifest.json not written: ${err instanceof Error ? err.message : String(err)}`
837
+ );
838
+ }
839
+ }
625
840
  async function generateManifest(themeName, themePath, outputDir) {
626
841
  let version = "1.0.0";
627
842
  let themeId = themeName;
628
843
  try {
629
- const pkgContent = await fs7.readFile(
630
- path8.join(themePath, "package.json"),
844
+ const pkgContent = await fs8.readFile(
845
+ path10.join(themePath, "package.json"),
631
846
  "utf-8"
632
847
  );
633
848
  const pkg = JSON.parse(pkgContent);
@@ -645,7 +860,7 @@ async function generateManifest(themeName, themePath, outputDir) {
645
860
  const dataRequirements = await extractDataRequirements(themePath);
646
861
  let hasThemeConfig = false;
647
862
  try {
648
- await fs7.access(path8.join(themePath, "theme.config.ts"));
863
+ await fs8.access(path10.join(themePath, "theme.config.ts"));
649
864
  hasThemeConfig = true;
650
865
  } catch {
651
866
  }
@@ -686,24 +901,24 @@ async function generateManifest(themeName, themePath, outputDir) {
686
901
  // Section data requirements for server-side prefetching (keyed by section type)
687
902
  dataRequirements
688
903
  };
689
- await fs7.writeFile(
690
- path8.join(outputDir, "manifest.json"),
904
+ await fs8.writeFile(
905
+ path10.join(outputDir, "manifest.json"),
691
906
  JSON.stringify(manifest, null, 2)
692
907
  );
693
908
  }
694
909
  async function compileStandaloneTheme(themePath, themeName) {
695
- const outputDir = path8.join(themePath, "dist");
696
- const bundleEntry = path8.join(themePath, "bundle-entry.ts");
697
- const indexEntry = path8.join(themePath, "index.ts");
910
+ const outputDir = path10.join(themePath, "dist");
911
+ const bundleEntry = path10.join(themePath, "bundle-entry.ts");
912
+ const indexEntry = path10.join(themePath, "index.ts");
698
913
  let entryPoint = indexEntry;
699
914
  try {
700
- await fs7.access(bundleEntry);
915
+ await fs8.access(bundleEntry);
701
916
  entryPoint = bundleEntry;
702
917
  } catch {
703
918
  }
704
- const shimPath = path8.join(outputDir, ".process-shim.js");
705
- await fs7.mkdir(outputDir, { recursive: true });
706
- await fs7.writeFile(shimPath, PROCESS_SHIM);
919
+ const shimPath = path10.join(outputDir, ".process-shim.js");
920
+ await fs8.mkdir(outputDir, { recursive: true });
921
+ await fs8.writeFile(shimPath, PROCESS_SHIM);
707
922
  const buildOptions = {
708
923
  entryPoints: [entryPoint],
709
924
  bundle: true,
@@ -754,19 +969,20 @@ async function compileStandaloneTheme(themePath, themeName) {
754
969
  try {
755
970
  const result = await esbuild.build(buildOptions);
756
971
  try {
757
- await fs7.unlink(shimPath);
972
+ await fs8.unlink(shimPath);
758
973
  } catch {
759
974
  }
760
975
  await contentHashEntry(outputDir);
761
- const themeAssetsDir = path8.join(themePath, "assets");
762
- const distThemeAssets = path8.join(outputDir, "theme-assets");
976
+ const themeAssetsDir = path10.join(themePath, "assets");
977
+ const distThemeAssets = path10.join(outputDir, "theme-assets");
763
978
  try {
764
- await fs7.access(themeAssetsDir);
765
- await fs7.cp(themeAssetsDir, distThemeAssets, { recursive: true });
979
+ await fs8.access(themeAssetsDir);
980
+ await fs8.cp(themeAssetsDir, distThemeAssets, { recursive: true });
766
981
  logger.info("Copied static assets to dist/theme-assets/");
767
982
  } catch {
768
983
  }
769
984
  await generateManifest(themeName, themePath, outputDir);
985
+ await writeGateManifests(themePath, outputDir);
770
986
  await generateThemeData(themePath, outputDir, themeName);
771
987
  await generateThemeCSS(themePath, outputDir);
772
988
  if (result.metafile) {
@@ -781,7 +997,7 @@ async function compileStandaloneTheme(themePath, themeName) {
781
997
  return true;
782
998
  } catch (error) {
783
999
  try {
784
- await fs7.unlink(shimPath);
1000
+ await fs8.unlink(shimPath);
785
1001
  } catch {
786
1002
  }
787
1003
  logger.error(`esbuild compilation failed: ${error}`);
@@ -789,18 +1005,18 @@ async function compileStandaloneTheme(themePath, themeName) {
789
1005
  }
790
1006
  }
791
1007
  async function compileStandaloneThemeDev(themePath, themeName) {
792
- const outputDir = path8.join(themePath, "dist");
793
- const bundleEntry = path8.join(themePath, "bundle-entry.ts");
794
- const indexEntry = path8.join(themePath, "index.ts");
1008
+ const outputDir = path10.join(themePath, "dist");
1009
+ const bundleEntry = path10.join(themePath, "bundle-entry.ts");
1010
+ const indexEntry = path10.join(themePath, "index.ts");
795
1011
  let entryPoint = indexEntry;
796
1012
  try {
797
- await fs7.access(bundleEntry);
1013
+ await fs8.access(bundleEntry);
798
1014
  entryPoint = bundleEntry;
799
1015
  } catch {
800
1016
  }
801
- const shimPath = path8.join(outputDir, ".process-shim.js");
802
- await fs7.mkdir(outputDir, { recursive: true });
803
- await fs7.writeFile(shimPath, PROCESS_SHIM);
1017
+ const shimPath = path10.join(outputDir, ".process-shim.js");
1018
+ await fs8.mkdir(outputDir, { recursive: true });
1019
+ await fs8.writeFile(shimPath, PROCESS_SHIM);
804
1020
  const buildOptions = {
805
1021
  entryPoints: [entryPoint],
806
1022
  bundle: true,
@@ -854,18 +1070,18 @@ async function compileStandaloneThemeDev(themePath, themeName) {
854
1070
  return { context: context2, outputDir };
855
1071
  }
856
1072
  async function compilePreviewRuntime(themePath) {
857
- const outputDir = path8.join(themePath, "dist");
858
- await fs7.mkdir(outputDir, { recursive: true });
859
- const outputPath = path8.join(outputDir, "preview-runtime.js");
1073
+ const outputDir = path10.join(themePath, "dist");
1074
+ await fs8.mkdir(outputDir, { recursive: true });
1075
+ const outputPath = path10.join(outputDir, "preview-runtime.js");
860
1076
  const locations = [
861
- path8.join(__dirname, "..", "preview", "preview-app.tsx"),
862
- path8.join(__dirname, "preview", "preview-app.tsx"),
863
- path8.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
1077
+ path10.join(__dirname, "..", "preview", "preview-app.tsx"),
1078
+ path10.join(__dirname, "preview", "preview-app.tsx"),
1079
+ path10.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
864
1080
  ];
865
1081
  let previewEntryPath = null;
866
1082
  for (const loc of locations) {
867
1083
  try {
868
- await fs7.access(loc);
1084
+ await fs8.access(loc);
869
1085
  previewEntryPath = loc;
870
1086
  break;
871
1087
  } catch {
@@ -948,10 +1164,10 @@ ${locations.join("\n")}`
948
1164
  if (!lucideScanned) {
949
1165
  lucideScanned = true;
950
1166
  const coreSrcCandidates = [
951
- path8.join(themePath, "node_modules", "@onexapis", "core", "src"),
952
- path8.join(themePath, "..", "..", "packages", "core", "src"),
1167
+ path10.join(themePath, "node_modules", "@onexapis", "core", "src"),
1168
+ path10.join(themePath, "..", "..", "packages", "core", "src"),
953
1169
  // monorepo sibling
954
- path8.join(
1170
+ path10.join(
955
1171
  __dirname,
956
1172
  "..",
957
1173
  "..",
@@ -966,7 +1182,7 @@ ${locations.join("\n")}`
966
1182
  let coreSourceDir = null;
967
1183
  for (const candidate of coreSrcCandidates) {
968
1184
  try {
969
- await fs7.access(candidate);
1185
+ await fs8.access(candidate);
970
1186
  coreSourceDir = candidate;
971
1187
  break;
972
1188
  } catch {
@@ -985,21 +1201,21 @@ ${locations.join("\n")}`
985
1201
  }
986
1202
  } else {
987
1203
  const coreDistCandidates = [
988
- path8.join(themePath, "node_modules", "@onexapis", "core", "dist")
1204
+ path10.join(themePath, "node_modules", "@onexapis", "core", "dist")
989
1205
  ];
990
1206
  const resolvedDist = await resolveNodeModulesFile(
991
1207
  __dirname,
992
- path8.join("@onexapis", "core", "dist")
1208
+ path10.join("@onexapis", "core", "dist")
993
1209
  );
994
1210
  if (resolvedDist) coreDistCandidates.push(resolvedDist);
995
1211
  for (const candidate of coreDistCandidates) {
996
1212
  try {
997
- await fs7.access(candidate);
1213
+ await fs8.access(candidate);
998
1214
  const mjsFiles = await glob("*.mjs", { cwd: candidate });
999
1215
  const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']lucide-react["']/g;
1000
1216
  for (const file of mjsFiles) {
1001
- const content = await fs7.readFile(
1002
- path8.join(candidate, file),
1217
+ const content = await fs8.readFile(
1218
+ path10.join(candidate, file),
1003
1219
  "utf-8"
1004
1220
  );
1005
1221
  for (const match of content.matchAll(importRegex)) {
@@ -1054,7 +1270,7 @@ export default new Proxy({}, { get: (_, name) => name === '__esModule' ? true :
1054
1270
  const req = createRequire(import.meta.url || __filename);
1055
1271
  const cjsPath = req.resolve("framer-motion");
1056
1272
  const pkgDir = cjsPath.replace(/[/\\]dist[/\\].*$/, "");
1057
- const esmEntry = path8.join(pkgDir, "dist", "es", "index.mjs");
1273
+ const esmEntry = path10.join(pkgDir, "dist", "es", "index.mjs");
1058
1274
  const { existsSync } = await import('fs');
1059
1275
  if (existsSync(esmEntry)) {
1060
1276
  return { path: esmEntry, namespace: "file" };
@@ -1153,8 +1369,8 @@ export function headers() { return new Headers(); }
1153
1369
  });
1154
1370
  }
1155
1371
  };
1156
- const shimPath = path8.join(outputDir, ".process-shim-preview.js");
1157
- await fs7.writeFile(shimPath, PROCESS_SHIM);
1372
+ const shimPath = path10.join(outputDir, ".process-shim-preview.js");
1373
+ await fs8.writeFile(shimPath, PROCESS_SHIM);
1158
1374
  await esbuild.build({
1159
1375
  entryPoints: [previewEntryPath],
1160
1376
  bundle: true,
@@ -1189,7 +1405,7 @@ export function headers() { return new Headers(); }
1189
1405
  }
1190
1406
  });
1191
1407
  try {
1192
- await fs7.unlink(shimPath);
1408
+ await fs8.unlink(shimPath);
1193
1409
  } catch {
1194
1410
  }
1195
1411
  return outputPath;
@@ -1198,6 +1414,8 @@ var PROCESS_SHIM, reactGlobalPlugin, reactQueryGlobalPlugin;
1198
1414
  var init_compile_theme = __esm({
1199
1415
  "src/utils/compile-theme.ts"() {
1200
1416
  init_logger();
1417
+ init_extract_schemas();
1418
+ init_scan_theme_assets();
1201
1419
  PROCESS_SHIM = `
1202
1420
  if (typeof process === "undefined") {
1203
1421
  globalThis.process = {
@@ -1367,8 +1585,8 @@ function validateThemeName(name) {
1367
1585
  return /^[a-z][a-z0-9-]*$/.test(name);
1368
1586
  }
1369
1587
  function pathExists(filePath) {
1370
- const fs11 = __require("fs-extra");
1371
- return fs11.existsSync(filePath);
1588
+ const fs12 = __require("fs-extra");
1589
+ return fs12.existsSync(filePath);
1372
1590
  }
1373
1591
  function validateCategory(category) {
1374
1592
  const validCategories = [
@@ -1409,18 +1627,18 @@ async function renderTemplate(templatePath, data) {
1409
1627
  return ejs.render(template, data);
1410
1628
  }
1411
1629
  async function writeFile(filePath, content) {
1412
- await fs.ensureDir(path8.dirname(filePath));
1630
+ await fs.ensureDir(path10.dirname(filePath));
1413
1631
  await fs.writeFile(filePath, content, "utf-8");
1414
1632
  }
1415
1633
  function getTemplatesDir() {
1416
1634
  const locations = [
1417
- path8.join(__dirname, "../../templates"),
1635
+ path10.join(__dirname, "../../templates"),
1418
1636
  // Development
1419
- path8.join(__dirname, "../templates"),
1637
+ path10.join(__dirname, "../templates"),
1420
1638
  // Production (dist/)
1421
- path8.join(process.cwd(), "templates"),
1639
+ path10.join(process.cwd(), "templates"),
1422
1640
  // Fallback
1423
- path8.join(process.cwd(), "packages/cli/templates")
1641
+ path10.join(process.cwd(), "packages/cli/templates")
1424
1642
  // Monorepo
1425
1643
  ];
1426
1644
  for (const location of locations) {
@@ -1432,7 +1650,7 @@ function getTemplatesDir() {
1432
1650
  }
1433
1651
  async function copyTemplate(templateName, targetDir, data) {
1434
1652
  const templatesDir = getTemplatesDir();
1435
- const templateDir = path8.join(templatesDir, templateName);
1653
+ const templateDir = path10.join(templatesDir, templateName);
1436
1654
  if (!fs.existsSync(templateDir)) {
1437
1655
  throw new Error(
1438
1656
  `Template "${templateName}" not found at ${templateDir}. Available templates: ${fs.readdirSync(templatesDir).join(", ")}`
@@ -1441,8 +1659,8 @@ async function copyTemplate(templateName, targetDir, data) {
1441
1659
  await fs.ensureDir(targetDir);
1442
1660
  const files = await fs.readdir(templateDir);
1443
1661
  for (const file of files) {
1444
- const templatePath = path8.join(templateDir, file);
1445
- const targetPath = path8.join(targetDir, file);
1662
+ const templatePath = path10.join(templateDir, file);
1663
+ const targetPath = path10.join(targetDir, file);
1446
1664
  const stat = await fs.stat(templatePath);
1447
1665
  if (stat.isDirectory()) {
1448
1666
  await copyTemplateDir(templatePath, targetPath, data);
@@ -1459,8 +1677,8 @@ async function copyTemplateDir(templateDir, targetDir, data) {
1459
1677
  await fs.ensureDir(targetDir);
1460
1678
  const files = await fs.readdir(templateDir);
1461
1679
  for (const file of files) {
1462
- const templatePath = path8.join(templateDir, file);
1463
- const targetPath = path8.join(targetDir, file);
1680
+ const templatePath = path10.join(templateDir, file);
1681
+ const targetPath = path10.join(targetDir, file);
1464
1682
  const stat = await fs.stat(templatePath);
1465
1683
  if (stat.isDirectory()) {
1466
1684
  await copyTemplateDir(templatePath, targetPath, data);
@@ -1475,32 +1693,32 @@ async function copyTemplateDir(templateDir, targetDir, data) {
1475
1693
  }
1476
1694
  function getProjectRoot() {
1477
1695
  let currentDir = process.cwd();
1478
- while (currentDir !== path8.parse(currentDir).root) {
1479
- const packageJsonPath = path8.join(currentDir, "package.json");
1696
+ while (currentDir !== path10.parse(currentDir).root) {
1697
+ const packageJsonPath = path10.join(currentDir, "package.json");
1480
1698
  if (fs.existsSync(packageJsonPath)) {
1481
1699
  const packageJson = fs.readJsonSync(packageJsonPath);
1482
- if (packageJson.workspaces || fs.existsSync(path8.join(currentDir, "src/themes")) || fs.existsSync(path8.join(currentDir, "themes"))) {
1700
+ if (packageJson.workspaces || fs.existsSync(path10.join(currentDir, "src/themes")) || fs.existsSync(path10.join(currentDir, "themes"))) {
1483
1701
  return currentDir;
1484
1702
  }
1485
1703
  }
1486
- currentDir = path8.dirname(currentDir);
1704
+ currentDir = path10.dirname(currentDir);
1487
1705
  }
1488
1706
  return process.cwd();
1489
1707
  }
1490
1708
  function getThemesDir() {
1491
1709
  const root = getProjectRoot();
1492
- if (fs.existsSync(path8.join(root, "themes")))
1493
- return path8.join(root, "themes");
1494
- if (fs.existsSync(path8.join(root, "src/themes")))
1495
- return path8.join(root, "src/themes");
1496
- return path8.dirname(root);
1710
+ if (fs.existsSync(path10.join(root, "themes")))
1711
+ return path10.join(root, "themes");
1712
+ if (fs.existsSync(path10.join(root, "src/themes")))
1713
+ return path10.join(root, "src/themes");
1714
+ return path10.dirname(root);
1497
1715
  }
1498
1716
  function getFeaturesDir() {
1499
- return path8.join(getProjectRoot(), "src/features");
1717
+ return path10.join(getProjectRoot(), "src/features");
1500
1718
  }
1501
1719
  function isOneXProject() {
1502
1720
  const root = getProjectRoot();
1503
- return fs.existsSync(path8.join(root, "themes")) || fs.existsSync(path8.join(root, "src/themes")) || fs.existsSync(path8.join(root, "theme.config.ts")) || fs.existsSync(path8.join(root, "bundle-entry.ts"));
1721
+ return fs.existsSync(path10.join(root, "themes")) || fs.existsSync(path10.join(root, "src/themes")) || fs.existsSync(path10.join(root, "theme.config.ts")) || fs.existsSync(path10.join(root, "bundle-entry.ts"));
1504
1722
  }
1505
1723
  function ensureOneXProject() {
1506
1724
  if (!isOneXProject()) {
@@ -1516,13 +1734,13 @@ function listThemes() {
1516
1734
  return [];
1517
1735
  }
1518
1736
  return fs.readdirSync(themesDir).filter((name) => {
1519
- const themePath = path8.join(themesDir, name);
1520
- return fs.statSync(themePath).isDirectory() && (fs.existsSync(path8.join(themePath, "theme.config.ts")) || fs.existsSync(path8.join(themePath, "bundle-entry.ts")) || fs.existsSync(path8.join(themePath, "manifest.ts")));
1737
+ const themePath = path10.join(themesDir, name);
1738
+ return fs.statSync(themePath).isDirectory() && (fs.existsSync(path10.join(themePath, "theme.config.ts")) || fs.existsSync(path10.join(themePath, "bundle-entry.ts")) || fs.existsSync(path10.join(themePath, "manifest.ts")));
1521
1739
  });
1522
1740
  }
1523
1741
  function themeExists(themeName) {
1524
- const themePath = path8.join(getThemesDir(), themeName);
1525
- return fs.existsSync(themePath) && (fs.existsSync(path8.join(themePath, "theme.config.ts")) || fs.existsSync(path8.join(themePath, "bundle-entry.ts")) || fs.existsSync(path8.join(themePath, "manifest.ts")));
1742
+ const themePath = path10.join(getThemesDir(), themeName);
1743
+ return fs.existsSync(themePath) && (fs.existsSync(path10.join(themePath, "theme.config.ts")) || fs.existsSync(path10.join(themePath, "bundle-entry.ts")) || fs.existsSync(path10.join(themePath, "manifest.ts")));
1526
1744
  }
1527
1745
  function detectPackageManager() {
1528
1746
  const userAgent = process.env.npm_config_user_agent || "";
@@ -1530,9 +1748,9 @@ function detectPackageManager() {
1530
1748
  if (userAgent.includes("yarn")) return "yarn";
1531
1749
  if (userAgent.includes("bun")) return "bun";
1532
1750
  const cwd = process.cwd();
1533
- if (fs.existsSync(path8.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1534
- if (fs.existsSync(path8.join(cwd, "yarn.lock"))) return "yarn";
1535
- if (fs.existsSync(path8.join(cwd, "bun.lockb"))) return "bun";
1751
+ if (fs.existsSync(path10.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1752
+ if (fs.existsSync(path10.join(cwd, "yarn.lock"))) return "yarn";
1753
+ if (fs.existsSync(path10.join(cwd, "bun.lockb"))) return "bun";
1536
1754
  return "npm";
1537
1755
  }
1538
1756
  async function installDependencies(projectPath, packageManager = "npm") {
@@ -1549,22 +1767,45 @@ async function installDependencies(projectPath, packageManager = "npm") {
1549
1767
  }
1550
1768
  });
1551
1769
  }
1552
- var AUTH_DIR = path8.join(os.homedir(), ".onexthm");
1553
- var AUTH_FILE = path8.join(AUTH_DIR, "auth.json");
1554
- function getApiUrl() {
1555
- return process.env.ONEXTHM_API_URL || "https://platform-dev.onexeos.com";
1770
+ var AUTH_DIR = path10.join(os.homedir(), ".onexthm");
1771
+ var ENV_URLS = {
1772
+ dev: "https://platform-dev.onexeos.com",
1773
+ staging: "https://platform-staging.onexeos.com",
1774
+ prod: "https://platform-apis.onexeos.com"
1775
+ };
1776
+ function getAuthFile(env = "dev") {
1777
+ const newFile = path10.join(AUTH_DIR, `auth-${env}.json`);
1778
+ if (env === "dev") {
1779
+ const legacyFile = path10.join(AUTH_DIR, "auth.json");
1780
+ if (fs.existsSync(legacyFile) && !fs.existsSync(newFile)) {
1781
+ try {
1782
+ fs.moveSync(legacyFile, newFile);
1783
+ } catch {
1784
+ try {
1785
+ fs.copySync(legacyFile, newFile);
1786
+ fs.removeSync(legacyFile);
1787
+ } catch {
1788
+ }
1789
+ }
1790
+ }
1791
+ }
1792
+ return newFile;
1793
+ }
1794
+ function getApiUrl(env = "dev") {
1795
+ return process.env.ONEXTHM_API_URL || ENV_URLS[env];
1556
1796
  }
1557
- async function saveAuthTokens(tokens) {
1797
+ async function saveAuthTokens(tokens, env = "dev") {
1558
1798
  await fs.ensureDir(AUTH_DIR);
1559
1799
  const key = getMachineKey();
1560
1800
  const data = JSON.stringify(tokens);
1561
1801
  const encrypted = encrypt(data, key);
1562
- await fs.writeFile(AUTH_FILE, encrypted, "utf-8");
1802
+ await fs.writeFile(getAuthFile(env), encrypted, "utf-8");
1563
1803
  }
1564
- function loadAuthTokens() {
1804
+ function loadAuthTokens(env = "dev") {
1565
1805
  try {
1566
- if (!fs.existsSync(AUTH_FILE)) return null;
1567
- const encrypted = fs.readFileSync(AUTH_FILE, "utf-8");
1806
+ const file = getAuthFile(env);
1807
+ if (!fs.existsSync(file)) return null;
1808
+ const encrypted = fs.readFileSync(file, "utf-8");
1568
1809
  const key = getMachineKey();
1569
1810
  const data = decrypt(encrypted, key);
1570
1811
  return JSON.parse(data);
@@ -1572,34 +1813,34 @@ function loadAuthTokens() {
1572
1813
  return null;
1573
1814
  }
1574
1815
  }
1575
- async function clearAuthTokens() {
1816
+ async function clearAuthTokens(env = "dev") {
1576
1817
  try {
1577
- await fs.remove(AUTH_FILE);
1818
+ await fs.remove(getAuthFile(env));
1578
1819
  } catch {
1579
1820
  }
1580
1821
  }
1581
1822
  function isTokenExpired(tokens) {
1582
1823
  return Date.now() / 1e3 > tokens.expiresAt - 300;
1583
1824
  }
1584
- async function getValidTokens() {
1585
- const tokens = loadAuthTokens();
1825
+ async function getValidTokens(env = "dev") {
1826
+ const tokens = loadAuthTokens(env);
1586
1827
  if (!tokens) return null;
1587
1828
  if (!isTokenExpired(tokens)) return tokens;
1588
1829
  try {
1589
- const apiUrl = getApiUrl();
1830
+ const apiUrl = getApiUrl(env);
1590
1831
  const response = await fetch(`${apiUrl}/auth/refresh`, {
1591
1832
  method: "POST",
1592
1833
  headers: { "Content-Type": "application/json" },
1593
1834
  body: JSON.stringify({ refresh_token: tokens.refreshToken })
1594
1835
  });
1595
1836
  if (!response.ok) {
1596
- await clearAuthTokens();
1837
+ await clearAuthTokens(env);
1597
1838
  return null;
1598
1839
  }
1599
1840
  const data = await response.json();
1600
1841
  const body = data.statusCode ? data.body : data;
1601
1842
  if (!body.IdToken) {
1602
- await clearAuthTokens();
1843
+ await clearAuthTokens(env);
1603
1844
  return null;
1604
1845
  }
1605
1846
  const refreshed = {
@@ -1608,17 +1849,19 @@ async function getValidTokens() {
1608
1849
  idToken: body.IdToken,
1609
1850
  expiresAt: Math.floor(Date.now() / 1e3) + (body.ExpiresIn || 3600)
1610
1851
  };
1611
- await saveAuthTokens(refreshed);
1852
+ await saveAuthTokens(refreshed, env);
1612
1853
  return refreshed;
1613
1854
  } catch {
1614
- await clearAuthTokens();
1855
+ await clearAuthTokens(env);
1615
1856
  return null;
1616
1857
  }
1617
1858
  }
1618
- async function authenticatedFetch(url, init) {
1619
- const tokens = await getValidTokens();
1859
+ async function authenticatedFetch(url, init, env = "dev") {
1860
+ const tokens = await getValidTokens(env);
1620
1861
  if (!tokens) {
1621
- throw new Error("Not logged in. Run: onexthm login");
1862
+ throw new Error(
1863
+ `Not logged in to ${env} environment. Run: onexthm login --env ${env}`
1864
+ );
1622
1865
  }
1623
1866
  const headers = new Headers(init?.headers);
1624
1867
  headers.set("Authorization", `Bearer ${tokens.idToken}`);
@@ -1675,7 +1918,7 @@ async function initCommand(projectName, options = {}) {
1675
1918
  if (!validateThemeName(kebabName)) {
1676
1919
  return "Invalid project name. Use lowercase letters, numbers, and hyphens only.";
1677
1920
  }
1678
- if (fs3.existsSync(path8.join(process.cwd(), kebabName))) {
1921
+ if (fs3.existsSync(path10.join(process.cwd(), kebabName))) {
1679
1922
  return `Directory "${kebabName}" already exists`;
1680
1923
  }
1681
1924
  return true;
@@ -1686,14 +1929,14 @@ async function initCommand(projectName, options = {}) {
1686
1929
  } else {
1687
1930
  name = toKebabCase(projectName);
1688
1931
  }
1689
- const projectPath = path8.join(process.cwd(), name);
1932
+ const projectPath = path10.join(process.cwd(), name);
1690
1933
  if (fs3.existsSync(projectPath)) {
1691
1934
  logger.error(`Directory "${name}" already exists.`);
1692
1935
  process.exit(1);
1693
1936
  }
1694
1937
  if (!options.yes) {
1695
1938
  try {
1696
- const apiUrl = getApiUrl();
1939
+ const apiUrl = getApiUrl(options.env ?? "dev");
1697
1940
  const controller = new AbortController();
1698
1941
  const timeout = setTimeout(() => controller.abort(), 3e3);
1699
1942
  const response = await fetch(
@@ -1802,7 +2045,7 @@ async function initCommand(projectName, options = {}) {
1802
2045
  description,
1803
2046
  author
1804
2047
  );
1805
- const mcpJsonPath = path8.join(projectPath, ".mcp.json");
2048
+ const mcpJsonPath = path10.join(projectPath, ".mcp.json");
1806
2049
  if (fs3.existsSync(mcpJsonPath)) {
1807
2050
  let mcpContent = fs3.readFileSync(mcpJsonPath, "utf-8");
1808
2051
  if (figmaApiKey) {
@@ -1882,7 +2125,7 @@ async function initCommand(projectName, options = {}) {
1882
2125
  }
1883
2126
  }
1884
2127
  async function renameThemeInFiles(projectPath, themeName, displayName, description, author) {
1885
- const configPath = path8.join(projectPath, "theme.config.ts");
2128
+ const configPath = path10.join(projectPath, "theme.config.ts");
1886
2129
  if (fs3.existsSync(configPath)) {
1887
2130
  let content = fs3.readFileSync(configPath, "utf-8");
1888
2131
  content = content.replace(
@@ -1895,7 +2138,7 @@ async function renameThemeInFiles(projectPath, themeName, displayName, descripti
1895
2138
  );
1896
2139
  fs3.writeFileSync(configPath, content, "utf-8");
1897
2140
  }
1898
- const pkgPath = path8.join(projectPath, "package.json");
2141
+ const pkgPath = path10.join(projectPath, "package.json");
1899
2142
  if (fs3.existsSync(pkgPath)) {
1900
2143
  let content = fs3.readFileSync(pkgPath, "utf-8");
1901
2144
  content = content.replace(
@@ -1917,10 +2160,10 @@ async function createSectionCommand(name, options) {
1917
2160
  ensureOneXProject();
1918
2161
  if (!options.theme) {
1919
2162
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
1920
- (f) => fs.existsSync(path8.join(process.cwd(), f))
2163
+ (f) => fs.existsSync(path10.join(process.cwd(), f))
1921
2164
  );
1922
2165
  if (isStandaloneTheme) {
1923
- options.theme = path8.basename(process.cwd());
2166
+ options.theme = path10.basename(process.cwd());
1924
2167
  }
1925
2168
  }
1926
2169
  const sectionName = toKebabCase(name);
@@ -1983,35 +2226,35 @@ async function createSectionCommand(name, options) {
1983
2226
  };
1984
2227
  logger.startSpinner("Creating section files...");
1985
2228
  try {
1986
- const themePath = path8.join(getThemesDir(), themeName);
1987
- const sectionPath = path8.join(themePath, "sections", sectionName);
2229
+ const themePath = path10.join(getThemesDir(), themeName);
2230
+ const sectionPath = path10.join(themePath, "sections", sectionName);
1988
2231
  const schemaContent = generateSectionSchema(data);
1989
2232
  await writeFile(
1990
- path8.join(sectionPath, `${sectionName}.schema.ts`),
2233
+ path10.join(sectionPath, `${sectionName}.schema.ts`),
1991
2234
  schemaContent
1992
2235
  );
1993
2236
  if (createTemplate) {
1994
2237
  const templateContent = generateSectionTemplate(data);
1995
2238
  await writeFile(
1996
- path8.join(sectionPath, `${sectionName}-default.tsx`),
2239
+ path10.join(sectionPath, `${sectionName}-default.tsx`),
1997
2240
  templateContent
1998
2241
  );
1999
2242
  }
2000
2243
  const indexContent = generateSectionIndex(data, createTemplate);
2001
- await writeFile(path8.join(sectionPath, "index.ts"), indexContent);
2244
+ await writeFile(path10.join(sectionPath, "index.ts"), indexContent);
2002
2245
  logger.stopSpinner(true, "Section files created successfully!");
2003
2246
  logger.newLine();
2004
2247
  logger.section("Next steps:");
2005
2248
  logger.log(
2006
- ` 1. Edit schema: ${path8.relative(process.cwd(), path8.join(sectionPath, `${sectionName}.schema.ts`))}`
2249
+ ` 1. Edit schema: ${path10.relative(process.cwd(), path10.join(sectionPath, `${sectionName}.schema.ts`))}`
2007
2250
  );
2008
2251
  if (createTemplate) {
2009
2252
  logger.log(
2010
- ` 2. Edit template: ${path8.relative(process.cwd(), path8.join(sectionPath, `${sectionName}-default.tsx`))}`
2253
+ ` 2. Edit template: ${path10.relative(process.cwd(), path10.join(sectionPath, `${sectionName}-default.tsx`))}`
2011
2254
  );
2012
2255
  }
2013
2256
  logger.log(
2014
- ` 3. Add to theme manifest: ${path8.relative(process.cwd(), path8.join(themePath, "manifest.ts"))}`
2257
+ ` 3. Add to theme manifest: ${path10.relative(process.cwd(), path10.join(themePath, "manifest.ts"))}`
2015
2258
  );
2016
2259
  logger.newLine();
2017
2260
  logger.success("Section created successfully!");
@@ -2159,10 +2402,10 @@ async function createBlockCommand(name, options) {
2159
2402
  ensureOneXProject();
2160
2403
  if (!options.theme) {
2161
2404
  const isStandaloneTheme = ["theme.config.ts", "bundle-entry.ts"].some(
2162
- (f) => fs.existsSync(path8.join(process.cwd(), f))
2405
+ (f) => fs.existsSync(path10.join(process.cwd(), f))
2163
2406
  );
2164
2407
  if (isStandaloneTheme) {
2165
- options.theme = path8.basename(process.cwd());
2408
+ options.theme = path10.basename(process.cwd());
2166
2409
  }
2167
2410
  }
2168
2411
  const blockName = toKebabCase(name);
@@ -2237,24 +2480,24 @@ async function createBlockCommand(name, options) {
2237
2480
  };
2238
2481
  logger.startSpinner("Creating block files...");
2239
2482
  try {
2240
- const blockPath = scope === "shared" ? path8.join(getFeaturesDir(), "blocks", blockName) : path8.join(getThemesDir(), themeName, "blocks", blockName);
2483
+ const blockPath = scope === "shared" ? path10.join(getFeaturesDir(), "blocks", blockName) : path10.join(getThemesDir(), themeName, "blocks", blockName);
2241
2484
  const schemaContent = generateBlockSchema(data);
2242
2485
  await writeFile(
2243
- path8.join(blockPath, `${blockName}.schema.ts`),
2486
+ path10.join(blockPath, `${blockName}.schema.ts`),
2244
2487
  schemaContent
2245
2488
  );
2246
2489
  const componentContent = generateBlockComponent(data);
2247
- await writeFile(path8.join(blockPath, `${blockName}.tsx`), componentContent);
2490
+ await writeFile(path10.join(blockPath, `${blockName}.tsx`), componentContent);
2248
2491
  const indexContent = generateBlockIndex(data);
2249
- await writeFile(path8.join(blockPath, "index.ts"), indexContent);
2492
+ await writeFile(path10.join(blockPath, "index.ts"), indexContent);
2250
2493
  logger.stopSpinner(true, "Block files created successfully!");
2251
2494
  logger.newLine();
2252
2495
  logger.section("Next steps:");
2253
2496
  logger.log(
2254
- ` 1. Edit schema: ${path8.relative(process.cwd(), path8.join(blockPath, `${blockName}.schema.ts`))}`
2497
+ ` 1. Edit schema: ${path10.relative(process.cwd(), path10.join(blockPath, `${blockName}.schema.ts`))}`
2255
2498
  );
2256
2499
  logger.log(
2257
- ` 2. Edit component: ${path8.relative(process.cwd(), path8.join(blockPath, `${blockName}.tsx`))}`
2500
+ ` 2. Edit component: ${path10.relative(process.cwd(), path10.join(blockPath, `${blockName}.tsx`))}`
2258
2501
  );
2259
2502
  logger.log(
2260
2503
  ` 3. Register in block registry: src/lib/registry/block-registry.ts`
@@ -2432,31 +2675,31 @@ async function createComponentCommand(name, options) {
2432
2675
  };
2433
2676
  logger.startSpinner("Creating component files...");
2434
2677
  try {
2435
- const componentPath = path8.join(
2678
+ const componentPath = path10.join(
2436
2679
  getFeaturesDir(),
2437
2680
  "components",
2438
2681
  componentName
2439
2682
  );
2440
2683
  const schemaContent = generateComponentSchema(data);
2441
2684
  await writeFile(
2442
- path8.join(componentPath, `${componentName}.schema.ts`),
2685
+ path10.join(componentPath, `${componentName}.schema.ts`),
2443
2686
  schemaContent
2444
2687
  );
2445
2688
  const componentContent = generateComponent(data);
2446
2689
  await writeFile(
2447
- path8.join(componentPath, `${componentName}.tsx`),
2690
+ path10.join(componentPath, `${componentName}.tsx`),
2448
2691
  componentContent
2449
2692
  );
2450
2693
  const indexContent = generateComponentIndex(data);
2451
- await writeFile(path8.join(componentPath, "index.ts"), indexContent);
2694
+ await writeFile(path10.join(componentPath, "index.ts"), indexContent);
2452
2695
  logger.stopSpinner(true, "Component files created successfully!");
2453
2696
  logger.newLine();
2454
2697
  logger.section("Next steps:");
2455
2698
  logger.log(
2456
- ` 1. Edit schema: ${path8.relative(process.cwd(), path8.join(componentPath, `${componentName}.schema.ts`))}`
2699
+ ` 1. Edit schema: ${path10.relative(process.cwd(), path10.join(componentPath, `${componentName}.schema.ts`))}`
2457
2700
  );
2458
2701
  logger.log(
2459
- ` 2. Edit component: ${path8.relative(process.cwd(), path8.join(componentPath, `${componentName}.tsx`))}`
2702
+ ` 2. Edit component: ${path10.relative(process.cwd(), path10.join(componentPath, `${componentName}.tsx`))}`
2460
2703
  );
2461
2704
  logger.log(
2462
2705
  ` 3. Register in component registry: src/lib/registry/component-registry.ts`
@@ -2613,13 +2856,13 @@ async function listSections(themeFilter) {
2613
2856
  return;
2614
2857
  }
2615
2858
  for (const theme of themes) {
2616
- const sectionsDir = path8.join(getThemesDir(), theme, "sections");
2859
+ const sectionsDir = path10.join(getThemesDir(), theme, "sections");
2617
2860
  if (!fs.existsSync(sectionsDir)) {
2618
2861
  continue;
2619
2862
  }
2620
2863
  const sections = fs.readdirSync(sectionsDir).filter((name) => {
2621
- const sectionPath = path8.join(sectionsDir, name);
2622
- return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path8.join(sectionPath, "index.ts"));
2864
+ const sectionPath = path10.join(sectionsDir, name);
2865
+ return fs.statSync(sectionPath).isDirectory() && fs.existsSync(path10.join(sectionPath, "index.ts"));
2623
2866
  });
2624
2867
  if (sections.length > 0) {
2625
2868
  logger.log(chalk4.cyan(`
@@ -2633,11 +2876,11 @@ async function listSections(themeFilter) {
2633
2876
  }
2634
2877
  async function listBlocks(themeFilter) {
2635
2878
  logger.section("\u{1F9F1} Blocks");
2636
- const sharedBlocksDir = path8.join(getFeaturesDir(), "blocks");
2879
+ const sharedBlocksDir = path10.join(getFeaturesDir(), "blocks");
2637
2880
  if (fs.existsSync(sharedBlocksDir)) {
2638
2881
  const sharedBlocks = fs.readdirSync(sharedBlocksDir).filter((name) => {
2639
- const blockPath = path8.join(sharedBlocksDir, name);
2640
- return fs.statSync(blockPath).isDirectory() && fs.existsSync(path8.join(blockPath, "index.ts"));
2882
+ const blockPath = path10.join(sharedBlocksDir, name);
2883
+ return fs.statSync(blockPath).isDirectory() && fs.existsSync(path10.join(blockPath, "index.ts"));
2641
2884
  });
2642
2885
  if (sharedBlocks.length > 0) {
2643
2886
  logger.log(chalk4.cyan("\n Shared:"));
@@ -2648,13 +2891,13 @@ async function listBlocks(themeFilter) {
2648
2891
  }
2649
2892
  const themes = themeFilter ? [themeFilter] : listThemes();
2650
2893
  for (const theme of themes) {
2651
- const blocksDir = path8.join(getThemesDir(), theme, "blocks");
2894
+ const blocksDir = path10.join(getThemesDir(), theme, "blocks");
2652
2895
  if (!fs.existsSync(blocksDir)) {
2653
2896
  continue;
2654
2897
  }
2655
2898
  const blocks = fs.readdirSync(blocksDir).filter((name) => {
2656
- const blockPath = path8.join(blocksDir, name);
2657
- return fs.statSync(blockPath).isDirectory() && fs.existsSync(path8.join(blockPath, "index.ts"));
2899
+ const blockPath = path10.join(blocksDir, name);
2900
+ return fs.statSync(blockPath).isDirectory() && fs.existsSync(path10.join(blockPath, "index.ts"));
2658
2901
  });
2659
2902
  if (blocks.length > 0) {
2660
2903
  logger.log(chalk4.cyan(`
@@ -2668,14 +2911,14 @@ async function listBlocks(themeFilter) {
2668
2911
  }
2669
2912
  async function listComponents() {
2670
2913
  logger.section("\u2699\uFE0F Components");
2671
- const componentsDir = path8.join(getFeaturesDir(), "components");
2914
+ const componentsDir = path10.join(getFeaturesDir(), "components");
2672
2915
  if (!fs.existsSync(componentsDir)) {
2673
2916
  logger.warning("No components directory found");
2674
2917
  return;
2675
2918
  }
2676
2919
  const components = fs.readdirSync(componentsDir).filter((name) => {
2677
- const componentPath = path8.join(componentsDir, name);
2678
- return fs.statSync(componentPath).isDirectory() && fs.existsSync(path8.join(componentPath, "index.ts"));
2920
+ const componentPath = path10.join(componentsDir, name);
2921
+ return fs.statSync(componentPath).isDirectory() && fs.existsSync(path10.join(componentPath, "index.ts"));
2679
2922
  });
2680
2923
  if (components.length === 0) {
2681
2924
  logger.warning("No components found");
@@ -2696,11 +2939,11 @@ async function listThemesInfo() {
2696
2939
  }
2697
2940
  logger.log("");
2698
2941
  for (const theme of themes) {
2699
- const themeDir = path8.join(getThemesDir(), theme);
2942
+ const themeDir = path10.join(getThemesDir(), theme);
2700
2943
  const candidates = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"];
2701
2944
  let manifestContent = "";
2702
2945
  for (const candidate of candidates) {
2703
- const candidatePath = path8.join(themeDir, candidate);
2946
+ const candidatePath = path10.join(themeDir, candidate);
2704
2947
  if (fs.existsSync(candidatePath)) {
2705
2948
  manifestContent = fs.readFileSync(candidatePath, "utf-8");
2706
2949
  break;
@@ -2729,14 +2972,14 @@ async function buildCommand(options) {
2729
2972
  if (options.theme) {
2730
2973
  themeName = options.theme;
2731
2974
  try {
2732
- const workspaceThemePath = path8.join(getThemesDir(), themeName);
2975
+ const workspaceThemePath = path10.join(getThemesDir(), themeName);
2733
2976
  if (fs.existsSync(workspaceThemePath)) {
2734
2977
  themePath = workspaceThemePath;
2735
2978
  } else {
2736
- themePath = path8.join(process.cwd(), themeName);
2979
+ themePath = path10.join(process.cwd(), themeName);
2737
2980
  }
2738
2981
  } catch {
2739
- themePath = path8.join(process.cwd(), themeName);
2982
+ themePath = path10.join(process.cwd(), themeName);
2740
2983
  }
2741
2984
  if (!fs.existsSync(themePath)) {
2742
2985
  logger.error(`Theme "${themeName}" not found.`);
@@ -2747,10 +2990,10 @@ async function buildCommand(options) {
2747
2990
  "theme.config.ts",
2748
2991
  "bundle-entry.ts",
2749
2992
  "manifest.ts"
2750
- ].some((f) => fs.existsSync(path8.join(process.cwd(), f)));
2993
+ ].some((f) => fs.existsSync(path10.join(process.cwd(), f)));
2751
2994
  if (isThemeDir) {
2752
2995
  themePath = process.cwd();
2753
- themeName = path8.basename(themePath);
2996
+ themeName = path10.basename(themePath);
2754
2997
  logger.info(`Building current theme: ${themeName}`);
2755
2998
  } else {
2756
2999
  logger.error(
@@ -2759,7 +3002,7 @@ async function buildCommand(options) {
2759
3002
  process.exit(1);
2760
3003
  }
2761
3004
  }
2762
- const packageJsonPath = path8.join(themePath, "package.json");
3005
+ const packageJsonPath = path10.join(themePath, "package.json");
2763
3006
  const hasPkgJson = fs.existsSync(packageJsonPath);
2764
3007
  if (!hasPkgJson) {
2765
3008
  logger.warning(
@@ -2815,9 +3058,9 @@ async function buildCommand(options) {
2815
3058
  logger.success("\u2713 Theme built successfully!");
2816
3059
  logger.newLine();
2817
3060
  logger.info(`Theme: ${themeName}`);
2818
- const distPath = path8.join(themePath, "dist");
3061
+ const distPath = path10.join(themePath, "dist");
2819
3062
  if (fs.existsSync(distPath)) {
2820
- logger.log(`Output: ${path8.relative(process.cwd(), distPath)}`);
3063
+ logger.log(`Output: ${path10.relative(process.cwd(), distPath)}`);
2821
3064
  const files = fs.readdirSync(distPath);
2822
3065
  logger.log(`Files: ${files.length}`);
2823
3066
  }
@@ -2958,8 +3201,8 @@ async function downloadBundleZip(apiUrl, themeId, version) {
2958
3201
  async function createCompatibilityFiles(outputDir, manifest) {
2959
3202
  const entryFile = manifest.output?.entry || "bundle-entry.js";
2960
3203
  if (entryFile !== "bundle-entry.js" && entryFile.startsWith("bundle-entry-")) {
2961
- const hashedPath = path8.join(outputDir, entryFile);
2962
- const stablePath = path8.join(outputDir, "bundle-entry.js");
3204
+ const hashedPath = path10.join(outputDir, entryFile);
3205
+ const stablePath = path10.join(outputDir, "bundle-entry.js");
2963
3206
  if (await fs.pathExists(hashedPath)) {
2964
3207
  await fs.copy(hashedPath, stablePath);
2965
3208
  const mapPath = hashedPath + ".map";
@@ -2968,13 +3211,13 @@ async function createCompatibilityFiles(outputDir, manifest) {
2968
3211
  }
2969
3212
  }
2970
3213
  }
2971
- const sectionsRegistryPath = path8.join(outputDir, "sections-registry.js");
3214
+ const sectionsRegistryPath = path10.join(outputDir, "sections-registry.js");
2972
3215
  const content = `// Re-export all sections from bundle-entry
2973
3216
  // This file exists to maintain compatibility with the import path
2974
3217
  export * from './bundle-entry.js';
2975
3218
  `;
2976
3219
  await fs.writeFile(sectionsRegistryPath, content, "utf-8");
2977
- const pkgJsonPath = path8.join(outputDir, "package.json");
3220
+ const pkgJsonPath = path10.join(outputDir, "package.json");
2978
3221
  await fs.writeFile(pkgJsonPath, '{\n "type": "module"\n}\n', "utf-8");
2979
3222
  }
2980
3223
  function showDownloadFailureHelp(themeId, apiUrl) {
@@ -3005,9 +3248,7 @@ function showDownloadFailureHelp(themeId, apiUrl) {
3005
3248
  console.log();
3006
3249
  console.log(chalk4.white("2. Check API URL configuration:"));
3007
3250
  console.log(chalk4.gray(` Current API URL: ${apiUrl}`));
3008
- console.log(
3009
- chalk4.gray(" Override with NEXT_PUBLIC_API_URL or ONEXTHM_API_URL")
3010
- );
3251
+ console.log(chalk4.gray(" Override with ONEXTHM_API_URL env var if needed"));
3011
3252
  console.log();
3012
3253
  console.log(chalk4.white("3. Pin a specific version (CI/production):"));
3013
3254
  console.log(
@@ -3017,15 +3258,17 @@ function showDownloadFailureHelp(themeId, apiUrl) {
3017
3258
  }
3018
3259
  async function downloadCommand(options) {
3019
3260
  logger.header("Download Theme");
3261
+ const env = options.env ?? "dev";
3262
+ const apiUrl = getApiUrl(env);
3263
+ logger.info(`Environment: ${env} (${apiUrl})`);
3020
3264
  const spinner = ora("Initializing download...").start();
3021
- if (options.bucket || options.environment) {
3265
+ if (options.bucket) {
3022
3266
  spinner.stop();
3023
3267
  logger.warning(
3024
- "--bucket and --environment are deprecated and ignored. Themes are now served via HTTP from the website-api Lambda."
3268
+ "--bucket is deprecated and ignored. Themes are now served via HTTP from the website-api Lambda."
3025
3269
  );
3026
3270
  spinner.start();
3027
3271
  }
3028
- const apiUrl = getApiUrl();
3029
3272
  try {
3030
3273
  const themeId = options.themeId || process.env.NEXT_PUBLIC_THEME_ID || process.env.THEME_ID;
3031
3274
  const requestedVersion = options.version || process.env.THEME_VERSION || "latest";
@@ -3073,7 +3316,7 @@ async function downloadCommand(options) {
3073
3316
  zip.extractAllTo(outputDir, true);
3074
3317
  const entries = zip.getEntries().filter((e) => !e.isDirectory);
3075
3318
  spinner.succeed(`Extracted ${entries.length} files to ${outputDir}`);
3076
- const manifestPath = path8.join(outputDir, "manifest.json");
3319
+ const manifestPath = path10.join(outputDir, "manifest.json");
3077
3320
  const manifest = await fs.readJson(manifestPath);
3078
3321
  await createCompatibilityFiles(outputDir, manifest);
3079
3322
  console.log();
@@ -3082,6 +3325,7 @@ async function downloadCommand(options) {
3082
3325
  console.log(
3083
3326
  chalk4.cyan(" Theme: ") + chalk4.white(`${themeId}@${resolvedVersion}`)
3084
3327
  );
3328
+ console.log(chalk4.cyan(" Env: ") + chalk4.white(env));
3085
3329
  console.log(chalk4.cyan(" Source: ") + chalk4.white(apiUrl));
3086
3330
  console.log(chalk4.cyan(" Output: ") + chalk4.white(outputDir));
3087
3331
  console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
@@ -3124,11 +3368,9 @@ async function resolveLatestVersion2(apiUrl, themeId) {
3124
3368
  }
3125
3369
  return latest;
3126
3370
  }
3127
- async function fetchSourceZip(apiUrl, themeId, version) {
3371
+ async function fetchSourceZip(apiUrl, themeId, version, env) {
3128
3372
  const url = `${apiUrl}/website-api/themes/${encodeURIComponent(themeId)}/source?version=${encodeURIComponent(version)}`;
3129
- const response = await authenticatedFetch(url, {
3130
- method: "GET"
3131
- });
3373
+ const response = await authenticatedFetch(url, { method: "GET" }, env);
3132
3374
  if (!response.ok) {
3133
3375
  if (response.status === 404) {
3134
3376
  throw new Error(
@@ -3137,7 +3379,7 @@ async function fetchSourceZip(apiUrl, themeId, version) {
3137
3379
  }
3138
3380
  if (response.status === 401 || response.status === 403) {
3139
3381
  throw new Error(
3140
- `Not authorized to download source for "${themeId}". Run \`onexthm login\` first.`
3382
+ `Not authorized to download source for "${themeId}". Run \`onexthm login --env ${env}\` first.`
3141
3383
  );
3142
3384
  }
3143
3385
  throw new Error(
@@ -3195,7 +3437,7 @@ async function renameTheme(themeDir, oldName, newName) {
3195
3437
  const oldPrefix = `${oldName}-`;
3196
3438
  const newPrefix = `${newName}-`;
3197
3439
  const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3198
- const pkgPath = path8.join(themeDir, "package.json");
3440
+ const pkgPath = path10.join(themeDir, "package.json");
3199
3441
  if (await fs.pathExists(pkgPath)) {
3200
3442
  const pkg = await fs.readJson(pkgPath);
3201
3443
  pkg.name = `@onex-themes/${newName}`;
@@ -3211,7 +3453,7 @@ async function renameTheme(themeDir, oldName, newName) {
3211
3453
  }
3212
3454
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3213
3455
  }
3214
- const configPath = path8.join(themeDir, "theme.config.ts");
3456
+ const configPath = path10.join(themeDir, "theme.config.ts");
3215
3457
  if (await fs.pathExists(configPath)) {
3216
3458
  let content = await fs.readFile(configPath, "utf-8");
3217
3459
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
@@ -3221,7 +3463,7 @@ async function renameTheme(themeDir, oldName, newName) {
3221
3463
  );
3222
3464
  await fs.writeFile(configPath, content);
3223
3465
  }
3224
- const layoutPath = path8.join(themeDir, "theme.layout.ts");
3466
+ const layoutPath = path10.join(themeDir, "theme.layout.ts");
3225
3467
  if (await fs.pathExists(layoutPath)) {
3226
3468
  let content = await fs.readFile(layoutPath, "utf-8");
3227
3469
  content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
@@ -3234,7 +3476,7 @@ async function renameTheme(themeDir, oldName, newName) {
3234
3476
  const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3235
3477
  const tsFiles = await glob("**/*.ts", { cwd: themeDir, nodir: true });
3236
3478
  for (const file of tsFiles) {
3237
- const filePath = path8.join(themeDir, file);
3479
+ const filePath = path10.join(themeDir, file);
3238
3480
  let content = await fs.readFile(filePath, "utf-8");
3239
3481
  const original = content;
3240
3482
  content = content.replace(
@@ -3256,14 +3498,19 @@ async function renameTheme(themeDir, oldName, newName) {
3256
3498
  }
3257
3499
  async function cloneCommand(themeName, options) {
3258
3500
  logger.header("Clone Theme Source");
3259
- if (options.bucket || options.environment) {
3501
+ const env = options.env ?? "dev";
3502
+ const apiUrl = getApiUrl(env);
3503
+ logger.info(`Environment: ${env} (${apiUrl})`);
3504
+ if (options.bucket) {
3260
3505
  logger.warning(
3261
- "--bucket and --environment are deprecated and ignored. Source is now fetched via HTTP from the website-api Lambda."
3506
+ "--bucket is deprecated and ignored. Source is now fetched via HTTP from the website-api Lambda."
3262
3507
  );
3263
3508
  }
3264
- const tokens = await getValidTokens();
3509
+ const tokens = await getValidTokens(env);
3265
3510
  if (!tokens) {
3266
- logger.error("Not logged in. Run: onexthm login");
3511
+ logger.error(
3512
+ `Not logged in to ${env} environment. Run: onexthm login --env ${env}`
3513
+ );
3267
3514
  process.exit(1);
3268
3515
  }
3269
3516
  let newName = options.name;
@@ -3272,8 +3519,7 @@ async function cloneCommand(themeName, options) {
3272
3519
  }
3273
3520
  const spinner = ora("Initializing clone...").start();
3274
3521
  try {
3275
- const apiUrl = getApiUrl();
3276
- const outputDir = options.output || path8.resolve(process.cwd(), newName);
3522
+ const outputDir = options.output || path10.resolve(process.cwd(), newName);
3277
3523
  if (await fs.pathExists(outputDir)) {
3278
3524
  spinner.fail(chalk4.red(`Directory already exists: ${outputDir}`));
3279
3525
  logger.info(
@@ -3292,7 +3538,7 @@ async function cloneCommand(themeName, options) {
3292
3538
  spinner.start(`Downloading source.zip for ${themeName}@${version}...`);
3293
3539
  let zipBuffer;
3294
3540
  try {
3295
- zipBuffer = await fetchSourceZip(apiUrl, themeName, version);
3541
+ zipBuffer = await fetchSourceZip(apiUrl, themeName, version, env);
3296
3542
  } catch (error) {
3297
3543
  spinner.fail(chalk4.red(error.message));
3298
3544
  console.log();
@@ -3319,20 +3565,20 @@ async function cloneCommand(themeName, options) {
3319
3565
  spinner.succeed(
3320
3566
  `Renamed theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}`
3321
3567
  );
3322
- const envExamplePath = path8.join(outputDir, ".env.example");
3568
+ const envExamplePath = path10.join(outputDir, ".env.example");
3323
3569
  if (!await fs.pathExists(envExamplePath)) {
3324
3570
  await fs.writeFile(
3325
3571
  envExamplePath,
3326
3572
  [
3327
3573
  "# API Configuration (enables real data in preview)",
3328
3574
  "# Get your Company ID from the OneX dashboard",
3329
- "NEXT_PUBLIC_API_URL=https://platform-dev.onexeos.com",
3575
+ `NEXT_PUBLIC_API_URL=${apiUrl}`,
3330
3576
  "NEXT_PUBLIC_COMPANY_ID=",
3331
3577
  ""
3332
3578
  ].join("\n")
3333
3579
  );
3334
3580
  }
3335
- const mcpJsonPath = path8.join(outputDir, ".mcp.json");
3581
+ const mcpJsonPath = path10.join(outputDir, ".mcp.json");
3336
3582
  if (await fs.pathExists(mcpJsonPath)) {
3337
3583
  const { default: inquirerMod } = await import('inquirer');
3338
3584
  const { figmaApiKey } = await inquirerMod.prompt([
@@ -3357,7 +3603,7 @@ async function cloneCommand(themeName, options) {
3357
3603
  }
3358
3604
  if (options.install !== false) {
3359
3605
  const hasPkgJson = await fs.pathExists(
3360
- path8.join(outputDir, "package.json")
3606
+ path10.join(outputDir, "package.json")
3361
3607
  );
3362
3608
  if (hasPkgJson) {
3363
3609
  spinner.start("Installing dependencies...");
@@ -3379,12 +3625,13 @@ async function cloneCommand(themeName, options) {
3379
3625
  console.log(
3380
3626
  chalk4.cyan(" Source: ") + chalk4.gray(`${themeName}@${version}`)
3381
3627
  );
3628
+ console.log(chalk4.cyan(" Env: ") + chalk4.white(env));
3382
3629
  console.log(chalk4.cyan(" Theme: ") + chalk4.white(newName));
3383
3630
  console.log(chalk4.cyan(" Location: ") + chalk4.white(outputDir));
3384
3631
  console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
3385
3632
  console.log();
3386
3633
  console.log(chalk4.cyan("Next steps:"));
3387
- console.log(chalk4.gray(` cd ${path8.relative(process.cwd(), outputDir)}`));
3634
+ console.log(chalk4.gray(` cd ${path10.relative(process.cwd(), outputDir)}`));
3388
3635
  console.log(
3389
3636
  chalk4.gray(" cp .env.example .env # then add your Company ID")
3390
3637
  );