@onexapis/cli 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,9 +1,13 @@
1
+ import chalk4 from 'chalk';
2
+ import ora from 'ora';
3
+ import * as esbuild from 'esbuild';
1
4
  import path from 'path';
5
+ import fs6 from 'fs/promises';
6
+ import crypto from 'crypto';
7
+ import { glob } from 'glob';
2
8
  import fs2 from 'fs';
3
9
  import { execSync, spawn } from 'child_process';
4
10
  import inquirer from 'inquirer';
5
- import chalk4 from 'chalk';
6
- import ora from 'ora';
7
11
  import fs from 'fs-extra';
8
12
  import ejs from 'ejs';
9
13
  import { PutObjectCommand, GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
@@ -11,6 +15,8 @@ import os from 'os';
11
15
  import archiver from 'archiver';
12
16
  import AdmZip from 'adm-zip';
13
17
 
18
+ var __defProp = Object.defineProperty;
19
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
20
  var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
15
21
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
16
22
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -18,58 +24,644 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
18
24
  if (typeof require !== "undefined") return require.apply(this, arguments);
19
25
  throw Error('Dynamic require of "' + x + '" is not supported');
20
26
  });
27
+ var __esm = (fn, res) => function __init() {
28
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
29
+ };
30
+ var __export = (target, all) => {
31
+ for (var name in all)
32
+ __defProp(target, name, { get: all[name], enumerable: true });
33
+ };
21
34
  var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
22
- var Logger = class {
23
- constructor() {
24
- this.spinner = null;
25
- }
26
- success(message) {
27
- console.log(chalk4.green("\u2713"), message);
28
- }
29
- error(message) {
30
- console.log(chalk4.red("\u2717"), message);
35
+ var Logger, logger;
36
+ var init_logger = __esm({
37
+ "src/utils/logger.ts"() {
38
+ Logger = class {
39
+ constructor() {
40
+ this.spinner = null;
41
+ }
42
+ success(message) {
43
+ console.log(chalk4.green("\u2713"), message);
44
+ }
45
+ error(message) {
46
+ console.log(chalk4.red("\u2717"), message);
47
+ }
48
+ warning(message) {
49
+ console.log(chalk4.yellow("\u26A0"), message);
50
+ }
51
+ info(message) {
52
+ console.log(chalk4.blue("\u2139"), message);
53
+ }
54
+ log(message) {
55
+ console.log(message);
56
+ }
57
+ startSpinner(message) {
58
+ this.spinner = ora(message).start();
59
+ }
60
+ stopSpinner(success = true, message) {
61
+ if (!this.spinner) return;
62
+ if (success) {
63
+ this.spinner.succeed(message);
64
+ } else {
65
+ this.spinner.fail(message);
66
+ }
67
+ this.spinner = null;
68
+ }
69
+ updateSpinner(message) {
70
+ if (this.spinner) {
71
+ this.spinner.text = message;
72
+ }
73
+ }
74
+ newLine() {
75
+ console.log();
76
+ }
77
+ header(message) {
78
+ console.log();
79
+ console.log(chalk4.bold.cyan(message));
80
+ console.log(chalk4.cyan("=".repeat(message.length)));
81
+ console.log();
82
+ }
83
+ section(message) {
84
+ console.log();
85
+ console.log(chalk4.bold(message));
86
+ }
87
+ };
88
+ logger = new Logger();
31
89
  }
32
- warning(message) {
33
- console.log(chalk4.yellow("\u26A0"), message);
90
+ });
91
+
92
+ // src/utils/compile-theme.ts
93
+ var compile_theme_exports = {};
94
+ __export(compile_theme_exports, {
95
+ compilePreviewRuntime: () => compilePreviewRuntime,
96
+ compileStandaloneTheme: () => compileStandaloneTheme,
97
+ compileStandaloneThemeDev: () => compileStandaloneThemeDev,
98
+ generateManifest: () => generateManifest2
99
+ });
100
+ async function resolveNodeModulesFile(startDir, relativePath) {
101
+ let dir = startDir;
102
+ while (true) {
103
+ const candidate = path.join(dir, "node_modules", relativePath);
104
+ try {
105
+ await fs6.access(candidate);
106
+ return candidate;
107
+ } catch (e) {
108
+ const parent = path.dirname(dir);
109
+ if (parent === dir) break;
110
+ dir = parent;
111
+ }
34
112
  }
35
- info(message) {
36
- console.log(chalk4.blue("\u2139"), message);
113
+ return null;
114
+ }
115
+ function createCoreGlobalPlugin(themePath) {
116
+ const exportsBySubpath = {};
117
+ return {
118
+ name: "core-global",
119
+ setup(build2) {
120
+ build2.onResolve({ filter: /^@onexapis\/core(\/.*)?$/ }, (args) => ({
121
+ path: args.path,
122
+ namespace: "core-global"
123
+ }));
124
+ build2.onLoad({ filter: /.*/, namespace: "core-global" }, async (args) => {
125
+ const match = args.path.match(/^@onexapis\/core(\/(.+))?$/);
126
+ const subpath = (match == null ? void 0 : match[2]) || "";
127
+ const moduleAccess = subpath ? `['${subpath}']` : "";
128
+ let namedExports = [];
129
+ const cacheKey = subpath || "__root__";
130
+ if (exportsBySubpath[cacheKey]) {
131
+ namedExports = exportsBySubpath[cacheKey];
132
+ } else {
133
+ const distFileName = subpath ? `${subpath}.mjs` : "index.mjs";
134
+ const distPath = await resolveNodeModulesFile(
135
+ themePath,
136
+ path.join("@onexapis", "core", "dist", distFileName)
137
+ );
138
+ try {
139
+ if (!distPath) throw new Error("not found");
140
+ const distContent = await fs6.readFile(distPath, "utf-8");
141
+ const exportMatches = distContent.matchAll(/export\s*\{([^}]+)\}/g);
142
+ for (const m of exportMatches) {
143
+ const names = m[1].split(",").map((n) => {
144
+ const parts = n.trim().split(/\s+as\s+/);
145
+ return (parts[1] || parts[0]).trim();
146
+ }).filter((n) => n.length > 0);
147
+ namedExports.push(...names);
148
+ }
149
+ namedExports = [...new Set(namedExports)];
150
+ } catch (e) {
151
+ }
152
+ exportsBySubpath[cacheKey] = namedExports;
153
+ }
154
+ const namedExportLines = namedExports.length > 0 ? `
155
+ export const {
156
+ ${namedExports.join(",\n ")}
157
+ } = _module;
158
+ ` : "";
159
+ return {
160
+ contents: `
161
+ if (!globalThis.__ONEX_CORE__) {
162
+ throw new Error('[Theme Bundle] @onexapis/core not initialized. Ensure globalThis.__ONEX_CORE__ is set before loading theme.');
163
+ }
164
+
165
+ const _module = globalThis.__ONEX_CORE__${moduleAccess};
166
+ if (!_module) {
167
+ const subpath = ${subpath ? `'${subpath}'` : "null"};
168
+ const modulePath = subpath ? '/' + subpath : '';
169
+ const moduleKey = subpath ? '["' + subpath + '"]' : '';
170
+ throw new Error('[Theme Bundle] @onexapis/core' + modulePath + ' not available in globalThis.__ONEX_CORE__' + moduleKey);
171
+ }
172
+
173
+ export default _module;
174
+ ${namedExportLines}
175
+ `.trim(),
176
+ loader: "js"
177
+ };
178
+ });
179
+ }
180
+ };
181
+ }
182
+ async function contentHashEntry(outputDir) {
183
+ const entryPath = path.join(outputDir, "bundle-entry.js");
184
+ const mapPath = path.join(outputDir, "bundle-entry.js.map");
185
+ const oldFiles = await glob("bundle-entry-*.js*", { cwd: outputDir });
186
+ for (const f of oldFiles) {
187
+ await fs6.unlink(path.join(outputDir, f));
37
188
  }
38
- log(message) {
39
- console.log(message);
189
+ let entryContent;
190
+ try {
191
+ entryContent = await fs6.readFile(entryPath, "utf-8");
192
+ } catch (e) {
193
+ const indexPath = path.join(outputDir, "index.js");
194
+ try {
195
+ entryContent = await fs6.readFile(indexPath, "utf-8");
196
+ } catch (e2) {
197
+ logger.warning("No entry file found in output, skipping content hash");
198
+ return;
199
+ }
200
+ const hash2 = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
201
+ const hashedName2 = `bundle-entry-${hash2}.js`;
202
+ const indexMapPath = path.join(outputDir, "index.js.map");
203
+ const hashedMapName2 = `bundle-entry-${hash2}.js.map`;
204
+ entryContent = entryContent.replace(
205
+ /\/\/# sourceMappingURL=index\.js\.map/,
206
+ `//# sourceMappingURL=${hashedMapName2}`
207
+ );
208
+ await fs6.writeFile(path.join(outputDir, hashedName2), entryContent);
209
+ await fs6.unlink(indexPath);
210
+ try {
211
+ await fs6.access(indexMapPath);
212
+ await fs6.rename(indexMapPath, path.join(outputDir, hashedMapName2));
213
+ } catch (e2) {
214
+ }
215
+ logger.info(`Entry hashed: ${hashedName2}`);
216
+ return;
40
217
  }
41
- startSpinner(message) {
42
- this.spinner = ora(message).start();
218
+ const hash = crypto.createHash("sha256").update(entryContent).digest("hex").slice(0, 8);
219
+ const hashedName = `bundle-entry-${hash}.js`;
220
+ const hashedMapName = `bundle-entry-${hash}.js.map`;
221
+ entryContent = entryContent.replace(
222
+ /\/\/# sourceMappingURL=bundle-entry\.js\.map/,
223
+ `//# sourceMappingURL=${hashedMapName}`
224
+ );
225
+ await fs6.writeFile(path.join(outputDir, hashedName), entryContent);
226
+ await fs6.unlink(entryPath);
227
+ try {
228
+ await fs6.access(mapPath);
229
+ await fs6.rename(mapPath, path.join(outputDir, hashedMapName));
230
+ } catch (e) {
43
231
  }
44
- stopSpinner(success = true, message) {
45
- if (!this.spinner) return;
46
- if (success) {
47
- this.spinner.succeed(message);
48
- } else {
49
- this.spinner.fail(message);
232
+ logger.info(`Entry hashed: ${hashedName}`);
233
+ }
234
+ async function generateManifest2(themeName, themePath, outputDir) {
235
+ let version = "1.0.0";
236
+ let themeId = themeName;
237
+ try {
238
+ const pkgContent = await fs6.readFile(
239
+ path.join(themePath, "package.json"),
240
+ "utf-8"
241
+ );
242
+ const pkg = JSON.parse(pkgContent);
243
+ version = pkg.version || version;
244
+ if (pkg.name) {
245
+ themeId = pkg.name.replace(/^@onex-themes\//, "");
50
246
  }
51
- this.spinner = null;
247
+ } catch (e) {
52
248
  }
53
- updateSpinner(message) {
54
- if (this.spinner) {
55
- this.spinner.text = message;
249
+ const [sectionFiles, blockFiles, schemaFiles] = await Promise.all([
250
+ glob("sections/**/index.ts", { cwd: themePath }),
251
+ glob("blocks/**/index.ts", { cwd: themePath }),
252
+ glob("**/*.schema.ts", { cwd: themePath })
253
+ ]);
254
+ let hasThemeConfig = false;
255
+ try {
256
+ await fs6.access(path.join(themePath, "theme.config.ts"));
257
+ hasThemeConfig = true;
258
+ } catch (e) {
259
+ }
260
+ const allFiles = await glob("**/*", { cwd: outputDir, nodir: true });
261
+ const jsFiles = allFiles.filter((f) => f.endsWith(".js"));
262
+ const cssFiles = allFiles.filter((f) => f.endsWith(".css"));
263
+ const entryFile = jsFiles.find((f) => f.includes("bundle-entry")) || "bundle-entry.js";
264
+ const manifest = {
265
+ themeId,
266
+ version,
267
+ name: themeId.charAt(0).toUpperCase() + themeId.slice(1),
268
+ compiledAt: (/* @__PURE__ */ new Date()).toISOString(),
269
+ format: "esm",
270
+ platform: "browser",
271
+ target: "es2020",
272
+ counts: {
273
+ sections: sectionFiles.length,
274
+ blocks: blockFiles.length,
275
+ schemas: schemaFiles.length
276
+ },
277
+ output: {
278
+ entry: entryFile,
279
+ chunks: jsFiles.filter((f) => f !== entryFile && !f.endsWith(".map")),
280
+ assets: allFiles.filter(
281
+ (f) => [".png", ".jpg", ".jpeg", ".svg", ".gif", ".webp"].some(
282
+ (ext) => f.endsWith(ext)
283
+ )
284
+ ),
285
+ stylesheets: cssFiles
286
+ },
287
+ external: ["react", "react-dom", "@onexapis/core"],
288
+ source: {
289
+ sections: sectionFiles,
290
+ blocks: blockFiles,
291
+ schemas: schemaFiles,
292
+ hasThemeConfig
56
293
  }
294
+ };
295
+ await fs6.writeFile(
296
+ path.join(outputDir, "manifest.json"),
297
+ JSON.stringify(manifest, null, 2)
298
+ );
299
+ }
300
+ async function compileStandaloneTheme(themePath, themeName) {
301
+ const outputDir = path.join(themePath, "dist");
302
+ const bundleEntry = path.join(themePath, "bundle-entry.ts");
303
+ const indexEntry = path.join(themePath, "index.ts");
304
+ let entryPoint = indexEntry;
305
+ try {
306
+ await fs6.access(bundleEntry);
307
+ entryPoint = bundleEntry;
308
+ } catch (e) {
309
+ }
310
+ const shimPath = path.join(outputDir, ".process-shim.js");
311
+ await fs6.mkdir(outputDir, { recursive: true });
312
+ await fs6.writeFile(shimPath, PROCESS_SHIM);
313
+ const buildOptions = {
314
+ entryPoints: [entryPoint],
315
+ bundle: true,
316
+ platform: "browser",
317
+ format: "esm",
318
+ outdir: outputDir,
319
+ splitting: false,
320
+ chunkNames: "[name]-[hash]",
321
+ banner: {
322
+ js: '"use client";'
323
+ },
324
+ plugins: [reactGlobalPlugin, createCoreGlobalPlugin(themePath)],
325
+ external: [],
326
+ alias: {
327
+ events: "events/",
328
+ buffer: "buffer/"
329
+ },
330
+ inject: [shimPath],
331
+ define: {
332
+ "process.env.NODE_ENV": JSON.stringify("production"),
333
+ global: "globalThis"
334
+ },
335
+ minify: true,
336
+ sourcemap: true,
337
+ logLevel: "warning",
338
+ target: "es2020",
339
+ jsx: "automatic",
340
+ jsxImportSource: "react",
341
+ loader: {
342
+ ".tsx": "tsx",
343
+ ".ts": "ts",
344
+ ".jpg": "file",
345
+ ".jpeg": "file",
346
+ ".png": "file",
347
+ ".gif": "file",
348
+ ".svg": "file",
349
+ ".webp": "file"
350
+ },
351
+ assetNames: "assets/[name]-[hash]",
352
+ publicPath: "./",
353
+ metafile: true
354
+ };
355
+ try {
356
+ const result = await esbuild.build(buildOptions);
357
+ try {
358
+ await fs6.unlink(shimPath);
359
+ } catch (e) {
360
+ }
361
+ await contentHashEntry(outputDir);
362
+ await generateManifest2(themeName, themePath, outputDir);
363
+ if (result.metafile) {
364
+ const outputs = result.metafile.outputs;
365
+ let totalSize = 0;
366
+ for (const output of Object.values(outputs)) {
367
+ totalSize += output.bytes;
368
+ }
369
+ const totalKB = (totalSize / 1024).toFixed(2);
370
+ logger.info(`Bundle size: ${totalKB} KB`);
371
+ }
372
+ return true;
373
+ } catch (error) {
374
+ try {
375
+ await fs6.unlink(shimPath);
376
+ } catch (e) {
377
+ }
378
+ logger.error(`esbuild compilation failed: ${error}`);
379
+ return false;
57
380
  }
58
- newLine() {
59
- console.log();
381
+ }
382
+ async function compileStandaloneThemeDev(themePath, themeName) {
383
+ const outputDir = path.join(themePath, "dist");
384
+ const bundleEntry = path.join(themePath, "bundle-entry.ts");
385
+ const indexEntry = path.join(themePath, "index.ts");
386
+ let entryPoint = indexEntry;
387
+ try {
388
+ await fs6.access(bundleEntry);
389
+ entryPoint = bundleEntry;
390
+ } catch (e) {
391
+ }
392
+ const shimPath = path.join(outputDir, ".process-shim.js");
393
+ await fs6.mkdir(outputDir, { recursive: true });
394
+ await fs6.writeFile(shimPath, PROCESS_SHIM);
395
+ const buildOptions = {
396
+ entryPoints: [entryPoint],
397
+ bundle: true,
398
+ platform: "browser",
399
+ format: "esm",
400
+ outdir: outputDir,
401
+ splitting: false,
402
+ banner: {
403
+ js: '"use client";'
404
+ },
405
+ plugins: [reactGlobalPlugin, createCoreGlobalPlugin(themePath)],
406
+ external: [],
407
+ alias: {
408
+ events: "events/",
409
+ buffer: "buffer/"
410
+ },
411
+ inject: [shimPath],
412
+ define: {
413
+ "process.env.NODE_ENV": JSON.stringify("development"),
414
+ global: "globalThis"
415
+ },
416
+ minify: false,
417
+ sourcemap: true,
418
+ logLevel: "warning",
419
+ target: "es2020",
420
+ jsx: "automatic",
421
+ jsxImportSource: "react",
422
+ loader: {
423
+ ".tsx": "tsx",
424
+ ".ts": "ts",
425
+ ".jpg": "file",
426
+ ".jpeg": "file",
427
+ ".png": "file",
428
+ ".gif": "file",
429
+ ".svg": "file",
430
+ ".webp": "file"
431
+ },
432
+ assetNames: "assets/[name]-[hash]",
433
+ publicPath: "./",
434
+ metafile: true
435
+ };
436
+ const context2 = await esbuild.context(buildOptions);
437
+ await context2.rebuild();
438
+ await generateManifest2(themeName, themePath, outputDir);
439
+ return { context: context2, outputDir };
440
+ }
441
+ async function compilePreviewRuntime(themePath) {
442
+ const outputDir = path.join(themePath, "dist");
443
+ await fs6.mkdir(outputDir, { recursive: true });
444
+ const outputPath = path.join(outputDir, "preview-runtime.js");
445
+ const locations = [
446
+ path.join(__dirname, "..", "preview", "preview-app.tsx"),
447
+ path.join(__dirname, "preview", "preview-app.tsx"),
448
+ path.join(__dirname, "..", "..", "src", "preview", "preview-app.tsx")
449
+ ];
450
+ let previewEntryPath = null;
451
+ for (const loc of locations) {
452
+ try {
453
+ await fs6.access(loc);
454
+ previewEntryPath = loc;
455
+ break;
456
+ } catch (e) {
457
+ }
60
458
  }
61
- header(message) {
62
- console.log();
63
- console.log(chalk4.bold.cyan(message));
64
- console.log(chalk4.cyan("=".repeat(message.length)));
65
- console.log();
459
+ if (!previewEntryPath) {
460
+ throw new Error(
461
+ `Preview app source not found. Searched:
462
+ ${locations.join("\n")}`
463
+ );
66
464
  }
67
- section(message) {
68
- console.log();
69
- console.log(chalk4.bold(message));
465
+ const serverStubPlugin = {
466
+ name: "server-stub",
467
+ setup(build2) {
468
+ build2.onResolve({ filter: /^server-only$/ }, () => ({
469
+ path: "server-only",
470
+ namespace: "server-stub"
471
+ }));
472
+ build2.onLoad({ filter: /.*/, namespace: "server-stub" }, () => ({
473
+ contents: "// server-only stub for browser",
474
+ loader: "js"
475
+ }));
476
+ const nodeBuiltins = [
477
+ "fs",
478
+ "fs/promises",
479
+ "path",
480
+ "os",
481
+ "crypto",
482
+ "stream",
483
+ "url",
484
+ "http",
485
+ "https",
486
+ "net",
487
+ "tls",
488
+ "child_process",
489
+ "util",
490
+ "events",
491
+ "buffer",
492
+ "querystring",
493
+ "zlib"
494
+ ];
495
+ for (const mod of nodeBuiltins) {
496
+ build2.onResolve({ filter: new RegExp(`^${mod.replace("/", "\\/")}$`) }, () => ({
497
+ path: mod,
498
+ namespace: "node-stub"
499
+ }));
500
+ }
501
+ build2.onLoad({ filter: /.*/, namespace: "node-stub" }, (args) => {
502
+ const stubs = {
503
+ events: "export class EventEmitter { on(){return this} off(){return this} emit(){return false} addListener(){return this} removeListener(){return this} } export default { EventEmitter };",
504
+ path: "export function join(){return ''} export function resolve(){return ''} export function dirname(){return ''} export function basename(){return ''} export function extname(){return ''} export default {};",
505
+ fs: "export const promises = {}; export function readFileSync(){return ''} export function existsSync(){return false} export default {};"
506
+ };
507
+ return {
508
+ contents: stubs[args.path] || "export default {};",
509
+ loader: "js"
510
+ };
511
+ });
512
+ }
513
+ };
514
+ await esbuild.build({
515
+ entryPoints: [previewEntryPath],
516
+ bundle: true,
517
+ platform: "browser",
518
+ format: "esm",
519
+ outfile: outputPath,
520
+ // Bundle React + core INTO the output (NOT externalized)
521
+ external: [],
522
+ plugins: [serverStubPlugin],
523
+ minify: false,
524
+ sourcemap: true,
525
+ target: "es2020",
526
+ jsx: "automatic",
527
+ jsxImportSource: "react",
528
+ define: {
529
+ "process.env.NODE_ENV": JSON.stringify("development"),
530
+ global: "globalThis"
531
+ },
532
+ loader: { ".tsx": "tsx", ".ts": "ts" },
533
+ // Force CJS resolution to avoid sideEffects:false dropping ESM chunk imports
534
+ conditions: ["require", "default"],
535
+ mainFields: ["main"],
536
+ logOverride: {
537
+ "ignored-bare-import": "silent"
538
+ }
539
+ });
540
+ return outputPath;
541
+ }
542
+ var PROCESS_SHIM, reactGlobalPlugin;
543
+ var init_compile_theme = __esm({
544
+ "src/utils/compile-theme.ts"() {
545
+ init_logger();
546
+ PROCESS_SHIM = `
547
+ if (typeof process === "undefined") {
548
+ globalThis.process = {
549
+ env: {},
550
+ browser: true,
551
+ };
552
+ }
553
+ `;
554
+ reactGlobalPlugin = {
555
+ name: "react-global",
556
+ setup(build2) {
557
+ build2.onResolve({ filter: /^react$/ }, () => ({
558
+ path: "react-external",
559
+ namespace: "react-global"
560
+ }));
561
+ build2.onResolve({ filter: /^react-dom$/ }, () => ({
562
+ path: "react-dom-external",
563
+ namespace: "react-global"
564
+ }));
565
+ build2.onResolve({ filter: /^react\/jsx-runtime$/ }, () => ({
566
+ path: "react-jsx-runtime-external",
567
+ namespace: "react-global"
568
+ }));
569
+ build2.onLoad({ filter: /.*/, namespace: "react-global" }, (args) => {
570
+ if (args.path === "react-external") {
571
+ return {
572
+ contents: `
573
+ if (!globalThis.__ONEX_REACT__) {
574
+ throw new Error('[Theme Bundle] React not initialized. Ensure globalThis.__ONEX_REACT__ is set before loading theme.');
575
+ }
576
+
577
+ const React = globalThis.__ONEX_REACT__;
578
+ export default React;
579
+
580
+ export const {
581
+ useState,
582
+ useEffect,
583
+ useContext,
584
+ useReducer,
585
+ useCallback,
586
+ useMemo,
587
+ useRef,
588
+ useImperativeHandle,
589
+ useLayoutEffect,
590
+ useDebugValue,
591
+ useDeferredValue,
592
+ useTransition,
593
+ useId,
594
+ useSyncExternalStore,
595
+ useInsertionEffect,
596
+ createContext,
597
+ forwardRef,
598
+ lazy,
599
+ memo,
600
+ startTransition,
601
+ createElement,
602
+ cloneElement,
603
+ isValidElement,
604
+ Children,
605
+ Fragment,
606
+ Profiler,
607
+ StrictMode,
608
+ Suspense,
609
+ Component,
610
+ PureComponent,
611
+ useActionState,
612
+ use,
613
+ } = React;
614
+ `.trim(),
615
+ loader: "js"
616
+ };
617
+ }
618
+ if (args.path === "react-dom-external") {
619
+ return {
620
+ contents: `
621
+ if (!globalThis.__ONEX_REACT_DOM__) {
622
+ throw new Error('[Theme Bundle] ReactDOM not initialized. Ensure globalThis.__ONEX_REACT_DOM__ is set before loading theme.');
623
+ }
624
+
625
+ const ReactDOM = globalThis.__ONEX_REACT_DOM__;
626
+ export default ReactDOM;
627
+
628
+ export const {
629
+ createRoot,
630
+ hydrateRoot,
631
+ flushSync,
632
+ createPortal,
633
+ findDOMNode,
634
+ render,
635
+ hydrate,
636
+ unmountComponentAtNode,
637
+ } = ReactDOM;
638
+ `.trim(),
639
+ loader: "js"
640
+ };
641
+ }
642
+ if (args.path === "react-jsx-runtime-external") {
643
+ return {
644
+ contents: `
645
+ if (!globalThis.__ONEX_JSX_RUNTIME__) {
646
+ throw new Error('[Theme Bundle] React JSX runtime not initialized. Ensure globalThis.__ONEX_JSX_RUNTIME__ is set before loading theme.');
647
+ }
648
+ const _jsxRuntime = globalThis.__ONEX_JSX_RUNTIME__;
649
+ export const jsx = _jsxRuntime.jsx;
650
+ export const jsxs = _jsxRuntime.jsxs;
651
+ export const Fragment = _jsxRuntime.Fragment;
652
+ `.trim(),
653
+ loader: "js"
654
+ };
655
+ }
656
+ return null;
657
+ });
658
+ }
659
+ };
70
660
  }
71
- };
72
- var logger = new Logger();
661
+ });
662
+
663
+ // src/commands/init.ts
664
+ init_logger();
73
665
 
74
666
  // src/utils/validators.ts
75
667
  function validateName(name) {
@@ -89,8 +681,8 @@ function validateThemeName(name) {
89
681
  return /^[a-z][a-z0-9-]*$/.test(name);
90
682
  }
91
683
  function pathExists(filePath) {
92
- const fs10 = __require("fs-extra");
93
- return fs10.existsSync(filePath);
684
+ const fs11 = __require("fs-extra");
685
+ return fs11.existsSync(filePath);
94
686
  }
95
687
  function validateCategory(category) {
96
688
  const validCategories = [
@@ -123,6 +715,9 @@ function getValidCategories() {
123
715
  "contact"
124
716
  ];
125
717
  }
718
+
719
+ // src/utils/file-helpers.ts
720
+ init_logger();
126
721
  async function renderTemplate(templatePath, data) {
127
722
  const template = await fs.readFile(templatePath, "utf-8");
128
723
  return ejs.render(template, data);
@@ -208,8 +803,10 @@ function getProjectRoot() {
208
803
  }
209
804
  function getThemesDir() {
210
805
  const root = getProjectRoot();
211
- if (fs.existsSync(path.join(root, "themes"))) return path.join(root, "themes");
212
- if (fs.existsSync(path.join(root, "src/themes"))) return path.join(root, "src/themes");
806
+ if (fs.existsSync(path.join(root, "themes")))
807
+ return path.join(root, "themes");
808
+ if (fs.existsSync(path.join(root, "src/themes")))
809
+ return path.join(root, "src/themes");
213
810
  return path.dirname(root);
214
811
  }
215
812
  function getFeaturesDir() {
@@ -679,6 +1276,9 @@ export const homePageConfig: PageConfig = {
679
1276
  };
680
1277
  `;
681
1278
  }
1279
+
1280
+ // src/commands/create-section.ts
1281
+ init_logger();
682
1282
  async function createSectionCommand(name, options) {
683
1283
  logger.header("Create New Section");
684
1284
  ensureOneXProject();
@@ -918,6 +1518,9 @@ export { ${data.sectionName}Schema } from "./${data.sectionName}.schema";
918
1518
  ${hasTemplate ? `export { ${data.sectionNamePascal}Default } from "./${data.sectionName}-default";` : ""}
919
1519
  `;
920
1520
  }
1521
+
1522
+ // src/commands/create-block.ts
1523
+ init_logger();
921
1524
  async function createBlockCommand(name, options) {
922
1525
  logger.header("Create New Block");
923
1526
  ensureOneXProject();
@@ -1142,6 +1745,9 @@ export { ${data.blockName}Definition } from "./${data.blockName}.schema";
1142
1745
  export { ${data.blockNamePascal} } from "./${data.blockName}";
1143
1746
  `;
1144
1747
  }
1748
+
1749
+ // src/commands/create-component.ts
1750
+ init_logger();
1145
1751
  async function createComponentCommand(name, options) {
1146
1752
  logger.header("Create New Component");
1147
1753
  ensureOneXProject();
@@ -1346,6 +1952,9 @@ export { ${data.componentName}Definition } from "./${data.componentName}.schema"
1346
1952
  export { ${data.componentNamePascal} } from "./${data.componentName}";
1347
1953
  `;
1348
1954
  }
1955
+
1956
+ // src/commands/list.ts
1957
+ init_logger();
1349
1958
  async function listCommand(options) {
1350
1959
  logger.header("OneX Project Inventory");
1351
1960
  ensureOneXProject();
@@ -1477,7 +2086,11 @@ async function listThemesInfo() {
1477
2086
  }
1478
2087
  logger.newLine();
1479
2088
  }
2089
+
2090
+ // src/commands/build.ts
2091
+ init_logger();
1480
2092
  async function buildCommand(options) {
2093
+ var _a;
1481
2094
  logger.header("Build Theme");
1482
2095
  let themePath;
1483
2096
  let themeName;
@@ -1498,7 +2111,11 @@ async function buildCommand(options) {
1498
2111
  process.exit(1);
1499
2112
  }
1500
2113
  } else {
1501
- const isThemeDir = ["theme.config.ts", "bundle-entry.ts", "manifest.ts"].some((f) => fs.existsSync(path.join(process.cwd(), f)));
2114
+ const isThemeDir = [
2115
+ "theme.config.ts",
2116
+ "bundle-entry.ts",
2117
+ "manifest.ts"
2118
+ ].some((f) => fs.existsSync(path.join(process.cwd(), f)));
1502
2119
  if (isThemeDir) {
1503
2120
  themePath = process.cwd();
1504
2121
  themeName = path.basename(themePath);
@@ -1542,11 +2159,20 @@ async function buildCommand(options) {
1542
2159
  process.exit(1);
1543
2160
  }
1544
2161
  logger.stopSpinner(true, "Lint passed");
1545
- const buildArgs = options.watch ? ["build", "--watch"] : ["build"];
2162
+ const pkgJson = fs.readJsonSync(packageJsonPath);
2163
+ const buildScript = ((_a = pkgJson.scripts) == null ? void 0 : _a.build) || "";
2164
+ const isRecursive = buildScript.includes("onex build") || buildScript.includes("onex-cli build");
1546
2165
  logger.startSpinner(
1547
2166
  options.watch ? "Building (watch mode)..." : "Building..."
1548
2167
  );
1549
- const buildSuccess = await runCommand("pnpm", buildArgs, themePath);
2168
+ let buildSuccess;
2169
+ if (isRecursive) {
2170
+ const { compileStandaloneTheme: compileStandaloneTheme2 } = await Promise.resolve().then(() => (init_compile_theme(), compile_theme_exports));
2171
+ buildSuccess = await compileStandaloneTheme2(themePath, themeName);
2172
+ } else {
2173
+ const buildArgs = options.watch ? ["build", "--watch"] : ["build"];
2174
+ buildSuccess = await runCommand("pnpm", buildArgs, themePath);
2175
+ }
1550
2176
  if (!buildSuccess && !options.watch) {
1551
2177
  logger.stopSpinner(false, "Build failed");
1552
2178
  process.exit(1);
@@ -1587,6 +2213,9 @@ function runCommand(command, args, cwd) {
1587
2213
  });
1588
2214
  });
1589
2215
  }
2216
+
2217
+ // src/commands/upload.ts
2218
+ init_logger();
1590
2219
  function getS3Client() {
1591
2220
  const adapterMode = (process.env.ADAPTER_MODE || "aws").trim().toLowerCase();
1592
2221
  if (adapterMode === "vps") {
@@ -1626,21 +2255,12 @@ function getBucketName(env) {
1626
2255
  return environment === "production" ? "onex-themes-prod" : "onex-themes-staging";
1627
2256
  }
1628
2257
  async function findCompiledThemeDir(themeId, version) {
1629
- const searchPaths = [
1630
- path.resolve(process.cwd(), "dist"),
1631
- path.resolve(
1632
- process.cwd(),
1633
- `../../apps/api-server/compiled-themes/${themeId}@${version}`
1634
- ),
1635
- path.resolve(
1636
- process.cwd(),
1637
- `../api-server/compiled-themes/${themeId}@${version}`
1638
- )
1639
- ];
2258
+ const searchPaths = [path.resolve(process.cwd(), "dist")];
1640
2259
  for (const dir of searchPaths) {
1641
2260
  if (await fs.pathExists(dir)) {
1642
- const manifestPath = path.join(dir, "manifest.json");
1643
- if (await fs.pathExists(manifestPath)) {
2261
+ const hasManifest = await fs.pathExists(path.join(dir, "manifest.json"));
2262
+ const hasThemeEntry = await fs.pathExists(path.join(dir, "bundle-entry.js")) || await fs.pathExists(path.join(dir, "theme.config.js")) || await fs.pathExists(path.join(dir, "index.js"));
2263
+ if (hasManifest || hasThemeEntry) {
1644
2264
  return dir;
1645
2265
  }
1646
2266
  }
@@ -1743,13 +2363,8 @@ async function uploadCommand(options) {
1743
2363
  `Compiled theme not found for ${themeId}@${version}. Run 'onex build' first.`
1744
2364
  )
1745
2365
  );
1746
- logger.info(
1747
- chalk4.gray(
1748
- `Expected locations:
1749
- - ./dist/
1750
- - ../../apps/api-server/compiled-themes/${themeId}@${version}/`
1751
- )
1752
- );
2366
+ logger.info(chalk4.gray(`Expected location:
2367
+ - ./dist/`));
1753
2368
  process.exit(1);
1754
2369
  }
1755
2370
  spinner.succeed(`Found compiled theme at: ${compiledDir}`);
@@ -1856,9 +2471,7 @@ async function uploadCommand(options) {
1856
2471
  );
1857
2472
  console.log(chalk4.cyan(" Bucket: ") + chalk4.white(bucket));
1858
2473
  console.log(
1859
- chalk4.cyan(" Files: ") + chalk4.white(
1860
- `bundle.zip${sourceUploaded ? " + source.zip" : ""}`
1861
- )
2474
+ chalk4.cyan(" Files: ") + chalk4.white(`bundle.zip${sourceUploaded ? " + source.zip" : ""}`)
1862
2475
  );
1863
2476
  console.log(
1864
2477
  chalk4.cyan(" Path: ") + chalk4.gray(`s3://${bucket}/themes/${themeId}/${version}/`)
@@ -1870,6 +2483,9 @@ async function uploadCommand(options) {
1870
2483
  process.exit(1);
1871
2484
  }
1872
2485
  }
2486
+
2487
+ // src/commands/download.ts
2488
+ init_logger();
1873
2489
  function getS3Client2() {
1874
2490
  const adapterMode = (process.env.ADAPTER_MODE || "aws").trim().toLowerCase();
1875
2491
  if (adapterMode === "vps") {
@@ -2017,11 +2633,7 @@ function showDownloadFailureHelp(themeId, bucket) {
2017
2633
  );
2018
2634
  console.log();
2019
2635
  console.log(chalk4.white("4. Verify theme exists in S3:"));
2020
- console.log(
2021
- chalk4.gray(
2022
- ` aws s3 ls s3://${bucket}/themes/${themeId}/`
2023
- )
2024
- );
2636
+ console.log(chalk4.gray(` aws s3 ls s3://${bucket}/themes/${themeId}/`));
2025
2637
  console.log();
2026
2638
  }
2027
2639
  async function downloadCommand(options) {
@@ -2097,6 +2709,9 @@ async function downloadCommand(options) {
2097
2709
  process.exit(1);
2098
2710
  }
2099
2711
  }
2712
+
2713
+ // src/commands/clone.ts
2714
+ init_logger();
2100
2715
  function getS3Client3() {
2101
2716
  const adapterMode = (process.env.ADAPTER_MODE || "aws").trim().toLowerCase();
2102
2717
  if (adapterMode === "vps") {
@@ -2200,17 +2815,100 @@ function runInstall(cwd) {
2200
2815
  proc.on("error", () => resolve(false));
2201
2816
  });
2202
2817
  }
2818
+ async function promptThemeName(originalName) {
2819
+ const { default: inquirer5 } = await import('inquirer');
2820
+ const { themeName } = await inquirer5.prompt([
2821
+ {
2822
+ type: "input",
2823
+ name: "themeName",
2824
+ message: "New theme name (kebab-case):",
2825
+ default: `my-${originalName}`,
2826
+ validate: (input) => {
2827
+ if (!/^[a-z][a-z0-9-]*$/.test(input)) {
2828
+ return "Theme name must be kebab-case (lowercase letters, numbers, hyphens)";
2829
+ }
2830
+ if (input === originalName) {
2831
+ return `Name must differ from the original theme "${originalName}"`;
2832
+ }
2833
+ return true;
2834
+ }
2835
+ }
2836
+ ]);
2837
+ return themeName;
2838
+ }
2839
+ async function renameTheme(themeDir, oldName, newName) {
2840
+ const oldPrefix = `${oldName}-`;
2841
+ const newPrefix = `${newName}-`;
2842
+ const newDisplayName = newName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
2843
+ const pkgPath = path.join(themeDir, "package.json");
2844
+ if (await fs.pathExists(pkgPath)) {
2845
+ const pkg = await fs.readJson(pkgPath);
2846
+ pkg.name = `@onex-themes/${newName}`;
2847
+ if (pkg.description) {
2848
+ pkg.description = pkg.description.replace(
2849
+ new RegExp(oldName, "gi"),
2850
+ newDisplayName
2851
+ );
2852
+ }
2853
+ pkg.version = "1.0.0";
2854
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
2855
+ }
2856
+ const configPath = path.join(themeDir, "theme.config.ts");
2857
+ if (await fs.pathExists(configPath)) {
2858
+ let content = await fs.readFile(configPath, "utf-8");
2859
+ content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
2860
+ content = content.replace(
2861
+ /name:\s*"[^"]*Theme"/,
2862
+ `name: "${newDisplayName} Theme"`
2863
+ );
2864
+ await fs.writeFile(configPath, content);
2865
+ }
2866
+ const layoutPath = path.join(themeDir, "theme.layout.ts");
2867
+ if (await fs.pathExists(layoutPath)) {
2868
+ let content = await fs.readFile(layoutPath, "utf-8");
2869
+ content = content.replace(/id:\s*"[^"]*"/, `id: "${newName}"`);
2870
+ content = content.replace(
2871
+ /name:\s*"[^"]*Theme"/,
2872
+ `name: "${newDisplayName} Theme"`
2873
+ );
2874
+ await fs.writeFile(layoutPath, content);
2875
+ }
2876
+ const oldDisplayName = oldName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
2877
+ const tsFiles = await glob("**/*.ts", { cwd: themeDir, nodir: true });
2878
+ for (const file of tsFiles) {
2879
+ const filePath = path.join(themeDir, file);
2880
+ let content = await fs.readFile(filePath, "utf-8");
2881
+ const original = content;
2882
+ content = content.replace(
2883
+ new RegExp(`"${oldPrefix}`, "g"),
2884
+ `"${newPrefix}`
2885
+ );
2886
+ content = content.replace(
2887
+ new RegExp(`themeId:\\s*"${oldName}"`, "g"),
2888
+ `themeId: "${newName}"`
2889
+ );
2890
+ content = content.replace(
2891
+ new RegExp(`${oldDisplayName} Theme`, "g"),
2892
+ `${newDisplayName} Theme`
2893
+ );
2894
+ if (content !== original) {
2895
+ await fs.writeFile(filePath, content);
2896
+ }
2897
+ }
2898
+ }
2203
2899
  async function cloneCommand(themeName, options) {
2204
2900
  logger.header("Clone Theme Source");
2901
+ let newName = options.name;
2902
+ if (!newName) {
2903
+ newName = await promptThemeName(themeName);
2904
+ }
2205
2905
  const spinner = ora("Initializing clone...").start();
2206
2906
  try {
2207
2907
  const bucket = options.bucket || getBucketName3(options.environment);
2208
- const outputDir = options.output || path.resolve(process.cwd(), themeName);
2908
+ const outputDir = options.output || path.resolve(process.cwd(), newName);
2209
2909
  const s3Client = getS3Client3();
2210
2910
  if (await fs.pathExists(outputDir)) {
2211
- spinner.fail(
2212
- chalk4.red(`Directory already exists: ${outputDir}`)
2213
- );
2911
+ spinner.fail(chalk4.red(`Directory already exists: ${outputDir}`));
2214
2912
  logger.info(
2215
2913
  chalk4.gray(
2216
2914
  "Use -o to specify a different output directory, or remove the existing directory."
@@ -2224,9 +2922,7 @@ async function cloneCommand(themeName, options) {
2224
2922
  version = await resolveLatestVersion2(s3Client, bucket, themeName);
2225
2923
  spinner.succeed(`Resolved latest version: ${chalk4.cyan(version)}`);
2226
2924
  }
2227
- spinner.start(
2228
- `Downloading source.zip for ${themeName}@${version}...`
2229
- );
2925
+ spinner.start(`Downloading source.zip for ${themeName}@${version}...`);
2230
2926
  const s3Key = `themes/${themeName}/${version}/source.zip`;
2231
2927
  let zipBuffer;
2232
2928
  try {
@@ -2244,9 +2940,7 @@ async function cloneCommand(themeName, options) {
2244
2940
  chalk4.yellow("The theme source may not have been uploaded yet.")
2245
2941
  );
2246
2942
  console.log(
2247
- chalk4.gray(
2248
- `Upload source with: onex upload --theme ${themeName}`
2249
- )
2943
+ chalk4.gray(`Upload source with: onex upload --theme ${themeName}`)
2250
2944
  );
2251
2945
  console.log();
2252
2946
  process.exit(1);
@@ -2259,6 +2953,13 @@ async function cloneCommand(themeName, options) {
2259
2953
  zip.extractAllTo(outputDir, true);
2260
2954
  const entries = zip.getEntries().filter((e) => !e.isDirectory);
2261
2955
  spinner.succeed(`Extracted ${entries.length} files`);
2956
+ spinner.start(
2957
+ `Renaming theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}...`
2958
+ );
2959
+ await renameTheme(outputDir, themeName, newName);
2960
+ spinner.succeed(
2961
+ `Renamed theme: ${chalk4.gray(themeName)} \u2192 ${chalk4.cyan(newName)}`
2962
+ );
2262
2963
  if (options.install !== false) {
2263
2964
  const hasPkgJson = await fs.pathExists(
2264
2965
  path.join(outputDir, "package.json")
@@ -2281,15 +2982,14 @@ async function cloneCommand(themeName, options) {
2281
2982
  logger.success(chalk4.green.bold("Theme cloned successfully!"));
2282
2983
  console.log();
2283
2984
  console.log(
2284
- chalk4.cyan(" Theme: ") + chalk4.white(`${themeName}@${version}`)
2985
+ chalk4.cyan(" Source: ") + chalk4.gray(`${themeName}@${version}`)
2285
2986
  );
2987
+ console.log(chalk4.cyan(" Theme: ") + chalk4.white(newName));
2286
2988
  console.log(chalk4.cyan(" Location: ") + chalk4.white(outputDir));
2287
2989
  console.log(chalk4.cyan(" Files: ") + chalk4.white(entries.length));
2288
2990
  console.log();
2289
2991
  console.log(chalk4.cyan("Next steps:"));
2290
- console.log(
2291
- chalk4.gray(` cd ${path.relative(process.cwd(), outputDir)}`)
2292
- );
2992
+ console.log(chalk4.gray(` cd ${path.relative(process.cwd(), outputDir)}`));
2293
2993
  if (options.install === false) {
2294
2994
  console.log(chalk4.gray(" pnpm install"));
2295
2995
  }
@@ -2302,6 +3002,9 @@ async function cloneCommand(themeName, options) {
2302
3002
  }
2303
3003
  }
2304
3004
 
3005
+ // src/index.ts
3006
+ init_logger();
3007
+
2305
3008
  export { Logger, buildCommand, cloneCommand, copyTemplate, createBlockCommand, createComponentCommand, createSectionCommand, detectPackageManager, downloadCommand, ensureOneXProject, getFeaturesDir, getProjectRoot, getThemesDir, getValidCategories, initCommand, installDependencies, isOneXProject, listCommand, listThemes, logger, pathExists, renderTemplate, themeExists, toCamelCase, toKebabCase, toPascalCase, uploadCommand, validateCategory, validateName, validateThemeName, writeFile };
2306
3009
  //# sourceMappingURL=index.mjs.map
2307
3010
  //# sourceMappingURL=index.mjs.map