@metacells/mcellui-cli 0.1.4 → 0.2.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.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/dist/index.js +537 -338
  3. package/package.json +9 -1
package/dist/index.js CHANGED
@@ -2,10 +2,84 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command as Command9 } from "commander";
5
+ import chalk11 from "chalk";
6
+
7
+ // src/utils/errors.ts
8
+ import chalk from "chalk";
9
+ function handleError(error) {
10
+ process.stderr.write("\n");
11
+ process.stderr.write(chalk.red(`Error: ${error.message}
12
+ `));
13
+ if (error.hint) {
14
+ process.stderr.write("\n");
15
+ process.stderr.write(chalk.dim(error.hint + "\n"));
16
+ }
17
+ process.stderr.write("\n");
18
+ process.exit(error.exitCode ?? 1);
19
+ }
20
+ var errors = {
21
+ /**
22
+ * Error when no valid project is found
23
+ */
24
+ noProject() {
25
+ return handleError({
26
+ message: "Could not find a valid Expo/React Native project",
27
+ hint: "Run this command from a project directory containing package.json",
28
+ code: "NO_PROJECT",
29
+ exitCode: 1
30
+ });
31
+ },
32
+ /**
33
+ * Error when project is not initialized with mcellui
34
+ */
35
+ notInitialized() {
36
+ return handleError({
37
+ message: "Project not initialized",
38
+ hint: "Run: npx mcellui init",
39
+ code: "NOT_INITIALIZED",
40
+ exitCode: 1
41
+ });
42
+ },
43
+ /**
44
+ * Error when component registry fetch fails
45
+ */
46
+ registryFetch(cause) {
47
+ return handleError({
48
+ message: "Failed to fetch component registry",
49
+ hint: cause ? `${cause}
50
+
51
+ Check your internet connection and try again` : "Check your internet connection and try again",
52
+ code: "REGISTRY_FETCH_FAILED",
53
+ exitCode: 1
54
+ });
55
+ },
56
+ /**
57
+ * Error when component is not found in registry
58
+ */
59
+ componentNotFound(name) {
60
+ return handleError({
61
+ message: `Component "${name}" not found in registry`,
62
+ hint: "Run: npx mcellui list",
63
+ code: "COMPONENT_NOT_FOUND",
64
+ exitCode: 1
65
+ });
66
+ },
67
+ /**
68
+ * Error when configuration is invalid
69
+ */
70
+ configInvalid(detail) {
71
+ return handleError({
72
+ message: "Invalid configuration",
73
+ hint: detail || "Check mcellui.config.ts",
74
+ code: "CONFIG_INVALID",
75
+ exitCode: 1
76
+ });
77
+ }
78
+ };
5
79
 
6
80
  // src/commands/init.ts
7
81
  import { Command } from "commander";
8
- import chalk2 from "chalk";
82
+ import chalk3 from "chalk";
9
83
  import ora from "ora";
10
84
  import prompts from "prompts";
11
85
  import fs2 from "fs-extra";
@@ -16,7 +90,7 @@ import fs from "fs-extra";
16
90
  import path from "path";
17
91
  import { fileURLToPath } from "url";
18
92
  import createJiti from "jiti";
19
- import chalk from "chalk";
93
+ import chalk2 from "chalk";
20
94
 
21
95
  // src/utils/config-schema.ts
22
96
  import { z } from "zod";
@@ -115,11 +189,11 @@ function validateConfig(config) {
115
189
  if (result.success) {
116
190
  return { success: true, data: result.data };
117
191
  }
118
- const errors = result.error.issues.map((issue) => {
192
+ const errors2 = result.error.issues.map((issue) => {
119
193
  const path12 = issue.path.join(".");
120
194
  return path12 ? `${path12}: ${issue.message}` : issue.message;
121
195
  });
122
- return { success: false, errors };
196
+ return { success: false, errors: errors2 };
123
197
  }
124
198
  function validateConfigOrThrow(config, configPath) {
125
199
  const result = validateConfig(config);
@@ -129,7 +203,7 @@ function validateConfigOrThrow(config, configPath) {
129
203
  `Invalid configuration in ${configPath}:
130
204
  ${errorList}
131
205
 
132
- See https://nativeui.dev/docs/config for valid options.`
206
+ See https://mcellui.dev/docs/config for valid options.`
133
207
  );
134
208
  }
135
209
  return result.data;
@@ -212,27 +286,38 @@ async function detectProjectType(projectRoot) {
212
286
  return "unknown";
213
287
  }
214
288
  }
289
+ var CONFIG_FILES = [
290
+ "mcellui.config.ts",
291
+ "mcellui.config.js",
292
+ "mcellui.config.json",
293
+ "nativeui.config.ts",
294
+ // Legacy
295
+ "nativeui.config.js",
296
+ // Legacy
297
+ "nativeui.config.json"
298
+ // Legacy
299
+ ];
215
300
  async function getConfig(projectRoot) {
216
- const tsConfigPath = path.join(projectRoot, "nativeui.config.ts");
217
- if (await fs.pathExists(tsConfigPath)) {
218
- return loadTsConfig(tsConfigPath);
219
- }
220
- const jsConfigPath = path.join(projectRoot, "nativeui.config.js");
221
- if (await fs.pathExists(jsConfigPath)) {
222
- return loadJsConfig(jsConfigPath);
223
- }
224
- const jsonConfigPath = path.join(projectRoot, "nativeui.config.json");
225
- if (await fs.pathExists(jsonConfigPath)) {
226
- try {
227
- const rawConfig = await fs.readJson(jsonConfigPath);
228
- const validatedConfig = validateConfigOrThrow(rawConfig, jsonConfigPath);
229
- return resolveConfig(validatedConfig);
230
- } catch (error) {
231
- if (error instanceof Error && error.message.includes("Invalid configuration")) {
232
- console.error(chalk.red(error.message));
233
- throw error;
301
+ for (const fileName of CONFIG_FILES) {
302
+ const configPath = path.join(projectRoot, fileName);
303
+ if (await fs.pathExists(configPath)) {
304
+ if (fileName.endsWith(".ts")) {
305
+ return loadTsConfig(configPath);
306
+ } else if (fileName.endsWith(".js")) {
307
+ return loadJsConfig(configPath);
308
+ } else if (fileName.endsWith(".json")) {
309
+ try {
310
+ const rawConfig = await fs.readJson(configPath);
311
+ const validatedConfig = validateConfigOrThrow(rawConfig, configPath);
312
+ return resolveConfig(validatedConfig);
313
+ } catch (error) {
314
+ if (error instanceof Error && error.message.includes("Invalid configuration")) {
315
+ console.error(chalk2.red(error.message));
316
+ throw error;
317
+ }
318
+ throw error;
319
+ }
234
320
  }
235
- throw error;
236
321
  }
237
322
  }
238
323
  return null;
@@ -248,10 +333,10 @@ async function loadTsConfig(configPath) {
248
333
  return resolveConfig(validatedConfig);
249
334
  } catch (error) {
250
335
  if (error instanceof Error && error.message.includes("Invalid configuration")) {
251
- console.error(chalk.red(error.message));
336
+ console.error(chalk2.red(error.message));
252
337
  throw error;
253
338
  }
254
- console.error(chalk.red("Failed to load config:"), error);
339
+ console.error(chalk2.red("Failed to load config:"), error);
255
340
  return getDefaultConfig();
256
341
  }
257
342
  }
@@ -263,10 +348,10 @@ async function loadJsConfig(configPath) {
263
348
  return resolveConfig(validatedConfig);
264
349
  } catch (error) {
265
350
  if (error instanceof Error && error.message.includes("Invalid configuration")) {
266
- console.error(chalk.red(error.message));
351
+ console.error(chalk2.red(error.message));
267
352
  throw error;
268
353
  }
269
- console.error(chalk.red("Failed to load config:"), error);
354
+ console.error(chalk2.red("Failed to load config:"), error);
270
355
  return getDefaultConfig();
271
356
  }
272
357
  }
@@ -294,26 +379,31 @@ async function detectPackageManager(projectRoot) {
294
379
  }
295
380
 
296
381
  // src/commands/init.ts
297
- var initCommand = new Command().name("init").description("Initialize nativeui in your project").option("-y, --yes", "Skip prompts and use defaults").option("--cwd <path>", "Working directory", process.cwd()).action(async (options) => {
382
+ var initCommand = new Command().name("init").description("Initialize mcellui in your project").option("-y, --yes", "Skip prompts and use defaults").option("--cwd <path>", "Working directory", process.cwd()).action(async (options) => {
298
383
  const spinner = ora();
299
384
  try {
300
385
  const cwd = path2.resolve(options.cwd);
301
386
  const projectRoot = await getProjectRoot(cwd);
302
387
  if (!projectRoot) {
303
- console.log(chalk2.red("Could not find a valid Expo/React Native project."));
304
- console.log(chalk2.dim("Make sure you run this command in a project with package.json"));
305
- process.exit(1);
388
+ errors.noProject();
306
389
  }
307
390
  console.log();
308
- console.log(chalk2.bold("Welcome to nativeui!"));
309
- console.log(chalk2.dim("The copy-paste component library for Expo/React Native"));
391
+ console.log(chalk3.bold("Welcome to mcellui!"));
392
+ console.log(chalk3.dim("The copy-paste component library for Expo/React Native"));
310
393
  console.log();
311
394
  const projectType = await detectProjectType(projectRoot);
312
- console.log(chalk2.dim(`Detected: ${projectType}`));
313
- const configPath = path2.join(projectRoot, "nativeui.config.ts");
395
+ console.log(chalk3.dim(`Detected: ${projectType}`));
396
+ const configPath = path2.join(projectRoot, "mcellui.config.ts");
397
+ const legacyConfigPath = path2.join(projectRoot, "nativeui.config.ts");
314
398
  if (await fs2.pathExists(configPath)) {
315
- console.log(chalk2.yellow("Project already initialized."));
316
- console.log(chalk2.dim(`Config found at: ${configPath}`));
399
+ console.log(chalk3.yellow("Project already initialized."));
400
+ console.log(chalk3.dim(`Config found at: ${configPath}`));
401
+ return;
402
+ }
403
+ if (await fs2.pathExists(legacyConfigPath)) {
404
+ console.log(chalk3.yellow("Project already initialized with legacy config."));
405
+ console.log(chalk3.dim(`Config found at: ${legacyConfigPath}`));
406
+ console.log(chalk3.dim("Consider renaming to mcellui.config.ts"));
317
407
  return;
318
408
  }
319
409
  let config = {
@@ -346,6 +436,9 @@ var initCommand = new Command().name("init").description("Initialize nativeui in
346
436
  ]
347
437
  }
348
438
  ]);
439
+ if (response.componentsPath === void 0) {
440
+ process.exit(0);
441
+ }
349
442
  config = { ...config, ...response };
350
443
  }
351
444
  spinner.start("Creating configuration...");
@@ -384,7 +477,7 @@ export default defineConfig({
384
477
  // },
385
478
 
386
479
  // ============================================
387
- // CLI Configuration (used by npx nativeui add)
480
+ // CLI Configuration (used by npx mcellui add)
388
481
  // ============================================
389
482
 
390
483
  // Path where components will be installed
@@ -454,25 +547,27 @@ export function cn(...inputs: StyleInput[]): Style {
454
547
  );
455
548
  spinner.succeed("Utilities installed");
456
549
  console.log();
457
- console.log(chalk2.green("Success!") + " nativeui initialized.");
550
+ console.log(chalk3.green("Success!") + " mcellui initialized.");
458
551
  console.log();
459
552
  console.log("Next steps:");
460
- console.log(chalk2.dim(" 1."), "Add your first component:");
461
- console.log(chalk2.cyan(" npx nativeui add button"));
553
+ console.log(chalk3.dim(" 1."), "Add your first component:");
554
+ console.log(chalk3.cyan(" npx mcellui add button"));
462
555
  console.log();
463
- console.log(chalk2.dim(" 2."), "Browse available components:");
464
- console.log(chalk2.cyan(" npx nativeui list"));
556
+ console.log(chalk3.dim(" 2."), "Browse available components:");
557
+ console.log(chalk3.cyan(" npx mcellui list"));
465
558
  console.log();
466
559
  } catch (error) {
467
560
  spinner.fail("Failed to initialize");
468
- console.error(error);
469
- process.exit(1);
561
+ handleError({
562
+ message: "Initialization failed",
563
+ hint: error instanceof Error ? error.message : "Check file permissions and try again"
564
+ });
470
565
  }
471
566
  });
472
567
 
473
568
  // src/commands/add.ts
474
569
  import { Command as Command2 } from "commander";
475
- import chalk3 from "chalk";
570
+ import chalk4 from "chalk";
476
571
  import ora2 from "ora";
477
572
  import prompts2 from "prompts";
478
573
  import fs5 from "fs-extra";
@@ -485,10 +580,59 @@ import { fileURLToPath as fileURLToPath2 } from "url";
485
580
  var __filename3 = fileURLToPath2(import.meta.url);
486
581
  var __dirname2 = path3.dirname(__filename3);
487
582
  var DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/metacells-development/mcellui/main/packages/registry";
488
- var REGISTRY_URL = process.env.MCELLUI_REGISTRY_URL || process.env.NATIVEUI_REGISTRY_URL || DEFAULT_REGISTRY_URL;
583
+ var hasEnvOverride = "MCELLUI_REGISTRY_URL" in process.env || "NATIVEUI_REGISTRY_URL" in process.env;
584
+ var REGISTRY_URL = hasEnvOverride ? process.env.MCELLUI_REGISTRY_URL || process.env.NATIVEUI_REGISTRY_URL || "" : DEFAULT_REGISTRY_URL;
489
585
  function getLocalRegistryPath() {
490
586
  return path3.resolve(__dirname2, "..", "..", "registry");
491
587
  }
588
+ function sleep(ms) {
589
+ return new Promise((resolve) => setTimeout(resolve, ms));
590
+ }
591
+ function isNetworkError(error) {
592
+ if (!error) return false;
593
+ if (error instanceof DOMException && error.name === "AbortError") {
594
+ return true;
595
+ }
596
+ const err = error;
597
+ const errorCodes = ["ECONNRESET", "ENOTFOUND", "ETIMEDOUT", "ECONNREFUSED", "ECONNABORTED"];
598
+ if (err.code && errorCodes.includes(err.code)) {
599
+ return true;
600
+ }
601
+ if (err.message && typeof err.message === "string") {
602
+ const message = err.message.toLowerCase();
603
+ if (errorCodes.some((code) => message.includes(code.toLowerCase()))) {
604
+ return true;
605
+ }
606
+ }
607
+ if (err.cause) {
608
+ return isNetworkError(err.cause);
609
+ }
610
+ return false;
611
+ }
612
+ async function fetchWithRetry(url, maxRetries = 3) {
613
+ let lastError;
614
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
615
+ try {
616
+ const controller = new AbortController();
617
+ const timeoutId = setTimeout(() => controller.abort(), 3e4);
618
+ const response = await fetch(url, {
619
+ signal: controller.signal
620
+ });
621
+ clearTimeout(timeoutId);
622
+ return response;
623
+ } catch (error) {
624
+ lastError = error;
625
+ if (!isNetworkError(error) || attempt === maxRetries) {
626
+ throw error;
627
+ }
628
+ const baseDelay = Math.min(1e3 * Math.pow(2, attempt - 1), 5e3);
629
+ const jitter = Math.random() * 200;
630
+ const delay = baseDelay + jitter;
631
+ await sleep(delay);
632
+ }
633
+ }
634
+ throw lastError;
635
+ }
492
636
  function isLocalMode() {
493
637
  if (REGISTRY_URL) return false;
494
638
  const localPath = getLocalRegistryPath();
@@ -506,18 +650,23 @@ async function getLocalRegistry() {
506
650
  const registry = await fs3.readJson(registryPath);
507
651
  return registry.components;
508
652
  } catch (error) {
509
- console.error("Failed to load local registry:", error);
510
- return [];
653
+ throw new Error(
654
+ "Failed to load local registry: " + (error instanceof Error ? error.message : String(error))
655
+ );
511
656
  }
512
657
  }
513
658
  async function getRemoteRegistry() {
514
659
  try {
515
- const response = await fetch(`${REGISTRY_URL}/registry.json`);
660
+ const response = await fetchWithRetry(`${REGISTRY_URL}/registry.json`);
661
+ if (!response.ok) {
662
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
663
+ }
516
664
  const registry = await response.json();
517
665
  return registry.components;
518
666
  } catch (error) {
519
- console.error("Failed to fetch remote registry:", error);
520
- return [];
667
+ throw new Error(
668
+ "Failed to fetch registry: " + (error instanceof Error ? error.message : String(error))
669
+ );
521
670
  }
522
671
  }
523
672
  async function fetchComponent(name) {
@@ -552,7 +701,12 @@ async function fetchLocalComponent(item) {
552
701
  async function fetchRemoteComponent(item) {
553
702
  const files = await Promise.all(
554
703
  item.files.map(async (filePath) => {
555
- const response = await fetch(`${REGISTRY_URL}/${filePath}`);
704
+ const response = await fetchWithRetry(`${REGISTRY_URL}/${filePath}`);
705
+ if (!response.ok) {
706
+ throw new Error(
707
+ `Failed to fetch ${filePath}: HTTP ${response.status} ${response.statusText}`
708
+ );
709
+ }
556
710
  const content = await response.text();
557
711
  const name = path3.basename(filePath);
558
712
  return { name, content };
@@ -621,6 +775,25 @@ function formatCircularError(chain) {
621
775
  // src/utils/installed.ts
622
776
  import fs4 from "fs-extra";
623
777
  import path4 from "path";
778
+
779
+ // src/utils/imports.ts
780
+ function transformToInstalled(code, config) {
781
+ if (!config) return code;
782
+ let result = code;
783
+ const utilsAlias = config.aliases?.utils || "@/lib/utils";
784
+ if (utilsAlias !== "@/lib/utils") {
785
+ result = result.replace(
786
+ /from ['"]@\/lib\/utils['"]/g,
787
+ `from '${utilsAlias}'`
788
+ );
789
+ }
790
+ return result;
791
+ }
792
+ function normalizeForComparison(content) {
793
+ return content.replace(/\r\n/g, "\n").replace(/\s+$/gm, "").trim();
794
+ }
795
+
796
+ // src/utils/installed.ts
624
797
  async function getInstalledFiles(componentsDir) {
625
798
  if (!await fs4.pathExists(componentsDir)) {
626
799
  return [];
@@ -637,24 +810,6 @@ async function getInstalledFiles(componentsDir) {
637
810
  }
638
811
  return componentFiles.sort();
639
812
  }
640
- function normalizeContent(content) {
641
- return content.replace(/\r\n/g, "\n").replace(/\s+$/gm, "").trim();
642
- }
643
- function transformImports(code, config) {
644
- let transformed = code;
645
- transformed = transformed.replace(
646
- /from ['"]@nativeui\/core['"]/g,
647
- `from '@metacells/mcellui-core'`
648
- );
649
- const utilsAlias = config.aliases?.utils || "@/lib/utils";
650
- if (utilsAlias !== "@/lib/utils") {
651
- transformed = transformed.replace(
652
- /from ['"]@\/lib\/utils['"]/g,
653
- `from '${utilsAlias}'`
654
- );
655
- }
656
- return transformed;
657
- }
658
813
  async function getInstallStatus(installedFiles, registry, config) {
659
814
  const results = [];
660
815
  const registryMap = /* @__PURE__ */ new Map();
@@ -700,10 +855,8 @@ async function getInstallStatus(installedFiles, registry, config) {
700
855
  continue;
701
856
  }
702
857
  const localContent = await fs4.readFile(localFile, "utf-8");
703
- const normalizedLocal = normalizeContent(localContent);
704
- const normalizedRegistry = normalizeContent(
705
- transformImports(registryFile.content, config)
706
- );
858
+ const normalizedLocal = normalizeForComparison(localContent);
859
+ const normalizedRegistry = normalizeForComparison(registryFile.content);
707
860
  results.push({
708
861
  name: registryItem.name,
709
862
  fileName,
@@ -736,35 +889,36 @@ var addCommand = new Command2().name("add").description("Add a component to your
736
889
  const cwd = path5.resolve(options.cwd);
737
890
  const projectRoot = await getProjectRoot(cwd);
738
891
  if (!projectRoot) {
739
- console.log(chalk3.red("Could not find a valid project."));
740
- console.log(chalk3.dim("Run `npx nativeui init` first."));
741
- process.exit(1);
892
+ errors.noProject();
742
893
  }
743
894
  const config = await getConfig(projectRoot);
744
895
  if (!config) {
745
- console.log(chalk3.red("Project not initialized."));
746
- console.log(chalk3.dim("Run `npx nativeui init` first."));
747
- process.exit(1);
896
+ errors.notInitialized();
748
897
  }
749
898
  if (!components.length) {
750
899
  const registry2 = await getRegistry();
751
900
  if (!registry2.length) {
752
- console.log(chalk3.red("No components found in registry."));
753
- process.exit(1);
901
+ handleError({
902
+ message: "No components found in registry",
903
+ hint: "Check your internet connection or try again later"
904
+ });
754
905
  }
755
906
  const { selected } = await prompts2({
756
907
  type: "multiselect",
757
908
  name: "selected",
758
909
  message: "Which components would you like to add?",
759
910
  choices: registry2.map((item) => ({
760
- title: `${item.name} ${chalk3.dim(`(${item.status})`)}`,
911
+ title: `${item.name} ${chalk4.dim(`(${item.status})`)}`,
761
912
  value: item.name,
762
913
  description: item.description
763
914
  })),
764
915
  hint: "- Space to select, Enter to confirm"
765
916
  });
917
+ if (selected === void 0) {
918
+ process.exit(0);
919
+ }
766
920
  if (!selected?.length) {
767
- console.log(chalk3.dim("No components selected."));
921
+ console.log(chalk4.dim("No components selected."));
768
922
  return;
769
923
  }
770
924
  components = selected;
@@ -774,8 +928,11 @@ var addCommand = new Command2().name("add").description("Add a component to your
774
928
  const { resolved, circular } = resolveDependencies(components, registry);
775
929
  if (circular) {
776
930
  spinner.fail("Circular dependency detected");
777
- console.log(chalk3.red(` ${formatCircularError(circular)}`));
778
- process.exit(1);
931
+ handleError({
932
+ message: `Circular dependency: ${formatCircularError(circular)}`,
933
+ hint: "Check component dependencies for cycles",
934
+ code: "CIRCULAR_DEPENDENCY"
935
+ });
779
936
  }
780
937
  spinner.stop();
781
938
  const componentsDir = path5.join(projectRoot, config.componentsPath);
@@ -783,19 +940,19 @@ var addCommand = new Command2().name("add").description("Add a component to your
783
940
  const installedNames = new Set(getInstalledNames(installedFiles));
784
941
  const toInstall = options.overwrite ? resolved : resolved.filter((name) => !installedNames.has(name));
785
942
  if (toInstall.length === 0) {
786
- console.log(chalk3.yellow("All components are already installed."));
787
- console.log(chalk3.dim("Use --overwrite to reinstall."));
943
+ console.log(chalk4.yellow("All components are already installed."));
944
+ console.log(chalk4.dim("Use --overwrite to reinstall."));
788
945
  return;
789
946
  }
790
947
  const requested = new Set(components);
791
948
  const dependencies = toInstall.filter((name) => !requested.has(name));
792
949
  console.log();
793
- console.log(chalk3.bold("Adding components:"));
950
+ console.log(chalk4.bold("Adding components:"));
794
951
  for (const name of toInstall) {
795
952
  if (requested.has(name)) {
796
- console.log(chalk3.dim(` - ${name}`));
953
+ console.log(chalk4.dim(` - ${name}`));
797
954
  } else {
798
- console.log(chalk3.dim(` - ${name} ${chalk3.cyan("(dependency)")}`));
955
+ console.log(chalk4.dim(` - ${name} ${chalk4.cyan("(dependency)")}`));
799
956
  }
800
957
  }
801
958
  console.log();
@@ -806,19 +963,24 @@ var addCommand = new Command2().name("add").description("Add a component to your
806
963
  message: `Add ${dependencies.length} additional dependencies?`,
807
964
  initial: true
808
965
  });
966
+ if (confirm === void 0) {
967
+ process.exit(0);
968
+ }
809
969
  if (!confirm) {
810
- console.log(chalk3.dim("Cancelled."));
970
+ console.log(chalk4.dim("Cancelled."));
811
971
  return;
812
972
  }
813
973
  }
814
974
  const allDependencies = [];
815
975
  const allDevDependencies = [];
976
+ let failCount = 0;
816
977
  for (const componentName of toInstall) {
817
978
  spinner.start(`Fetching ${componentName}...`);
818
979
  try {
819
980
  const component = await fetchComponent(componentName);
820
981
  if (!component) {
821
982
  spinner.fail(`Component "${componentName}" not found`);
983
+ failCount++;
822
984
  continue;
823
985
  }
824
986
  const targetDir = path5.join(projectRoot, config.componentsPath);
@@ -829,7 +991,7 @@ var addCommand = new Command2().name("add").description("Add a component to your
829
991
  continue;
830
992
  }
831
993
  await fs5.ensureDir(targetDir);
832
- const transformedContent = transformImports2(file.content, config);
994
+ const transformedContent = transformToInstalled(file.content, config);
833
995
  await fs5.writeFile(targetPath, transformedContent);
834
996
  }
835
997
  spinner.succeed(`Added ${componentName}`);
@@ -841,48 +1003,42 @@ var addCommand = new Command2().name("add").description("Add a component to your
841
1003
  }
842
1004
  } catch (error) {
843
1005
  spinner.fail(`Failed to add ${componentName}`);
844
- console.error(chalk3.dim(String(error)));
1006
+ console.error(chalk4.dim(String(error)));
1007
+ failCount++;
845
1008
  }
846
1009
  }
1010
+ if (failCount > 0) {
1011
+ process.exit(1);
1012
+ }
847
1013
  const uniqueDeps = [...new Set(allDependencies)];
848
1014
  const uniqueDevDeps = [...new Set(allDevDependencies)];
849
1015
  if (uniqueDeps.length || uniqueDevDeps.length) {
850
1016
  console.log();
851
- console.log(chalk3.bold("Install dependencies:"));
1017
+ console.log(chalk4.bold("Install dependencies:"));
852
1018
  if (uniqueDeps.length) {
853
- console.log(chalk3.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
1019
+ console.log(chalk4.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
854
1020
  }
855
1021
  if (uniqueDevDeps.length) {
856
- console.log(chalk3.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
1022
+ console.log(chalk4.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
857
1023
  }
858
1024
  }
859
1025
  console.log();
860
- console.log(chalk3.green("Done!"));
1026
+ console.log(chalk4.green("Done!"));
861
1027
  } catch (error) {
862
1028
  spinner.fail("Failed");
863
- console.error(error);
864
- process.exit(1);
1029
+ handleError({
1030
+ message: "Failed to add components",
1031
+ hint: error instanceof Error ? error.message : "Check your network connection and try again"
1032
+ });
865
1033
  }
866
1034
  });
867
- function transformImports2(code, config) {
868
- let transformed = code;
869
- const utilsAlias = config.aliases?.utils || "@/lib/utils";
870
- if (utilsAlias === "@/lib/utils") {
871
- return transformed;
872
- }
873
- transformed = transformed.replace(
874
- /from ['"]@\/lib\/utils['"]/g,
875
- `from '${utilsAlias}'`
876
- );
877
- return transformed;
878
- }
879
1035
 
880
1036
  // src/commands/list.ts
881
1037
  import { Command as Command3 } from "commander";
882
- import chalk4 from "chalk";
1038
+ import chalk5 from "chalk";
883
1039
  import ora3 from "ora";
884
1040
  import path6 from "path";
885
- var listCommand = new Command3().name("list").description("List available or installed components").option("-c, --category <category>", "Filter by category").option("-i, --installed", "Show installed components and their sync status").option("--cwd <path>", "Working directory", process.cwd()).action(async (options) => {
1041
+ var listCommand = new Command3().name("list").description("List available or installed components").option("-c, --category <category>", "Filter by category").option("-i, --installed", "Show installed components and their sync status").option("--json", "Output as JSON").option("--cwd <path>", "Working directory", process.cwd()).action(async (options) => {
886
1042
  if (options.installed) {
887
1043
  await listInstalledComponents(options);
888
1044
  } else {
@@ -894,8 +1050,13 @@ async function listAvailableComponents(options) {
894
1050
  try {
895
1051
  const registry = await getRegistry();
896
1052
  spinner.stop();
1053
+ if (options.json) {
1054
+ const items = options.category ? registry.filter((item) => (item.category || "Other").toLowerCase() === options.category.toLowerCase()) : registry;
1055
+ console.log(JSON.stringify(items, null, 2));
1056
+ return;
1057
+ }
897
1058
  console.log();
898
- console.log(chalk4.bold("Available Components"));
1059
+ console.log(chalk5.bold("Available Components"));
899
1060
  console.log();
900
1061
  const categories = /* @__PURE__ */ new Map();
901
1062
  for (const item of registry) {
@@ -909,20 +1070,22 @@ async function listAvailableComponents(options) {
909
1070
  categories.get(category).push(item);
910
1071
  }
911
1072
  for (const [category, items] of categories) {
912
- console.log(chalk4.cyan.bold(`${category}`));
1073
+ console.log(chalk5.cyan.bold(`${category}`));
913
1074
  for (const item of items) {
914
- const status = item.status === "stable" ? "" : chalk4.yellow(` [${item.status}]`);
915
- console.log(` ${chalk4.white(item.name)}${status}`);
916
- console.log(chalk4.dim(` ${item.description}`));
1075
+ const status = item.status === "stable" ? "" : chalk5.yellow(` [${item.status}]`);
1076
+ console.log(` ${chalk5.white(item.name)}${status}`);
1077
+ console.log(chalk5.dim(` ${item.description}`));
917
1078
  }
918
1079
  console.log();
919
1080
  }
920
- console.log(chalk4.dim("Add a component: npx mcellui add <component>"));
1081
+ console.log(chalk5.dim("Add a component: npx mcellui add <component>"));
921
1082
  console.log();
922
1083
  } catch (error) {
923
1084
  spinner.fail("Failed to fetch components");
924
- console.error(error);
925
- process.exit(1);
1085
+ handleError({
1086
+ message: "Failed to fetch components",
1087
+ hint: error instanceof Error ? error.message : "Check your network connection and try again"
1088
+ });
926
1089
  }
927
1090
  }
928
1091
  async function listInstalledComponents(options) {
@@ -931,22 +1094,23 @@ async function listInstalledComponents(options) {
931
1094
  const cwd = path6.resolve(options.cwd || process.cwd());
932
1095
  const projectRoot = await getProjectRoot(cwd);
933
1096
  if (!projectRoot) {
934
- console.log(chalk4.red("Could not find a valid project."));
935
- console.log(chalk4.dim("Run `npx mcellui init` first."));
936
- process.exit(1);
1097
+ errors.noProject();
937
1098
  }
938
1099
  const config = await getConfig(projectRoot);
939
1100
  if (!config) {
940
- console.log(chalk4.red("Project not initialized."));
941
- console.log(chalk4.dim("Run `npx mcellui init` first."));
942
- process.exit(1);
1101
+ errors.notInitialized();
943
1102
  }
944
1103
  spinner.start("Scanning installed components...");
945
1104
  const componentsDir = path6.join(projectRoot, config.componentsPath);
946
1105
  const installedFiles = await getInstalledFiles(componentsDir);
947
1106
  if (installedFiles.length === 0) {
1107
+ spinner.stop();
1108
+ if (options.json) {
1109
+ console.log(JSON.stringify([], null, 2));
1110
+ return;
1111
+ }
948
1112
  spinner.info("No components installed yet.");
949
- console.log(chalk4.dim("\nAdd components with: npx mcellui add <component>"));
1113
+ console.log(chalk5.dim("\nAdd components with: npx mcellui add <component>"));
950
1114
  return;
951
1115
  }
952
1116
  spinner.text = "Fetching registry...";
@@ -954,13 +1118,17 @@ async function listInstalledComponents(options) {
954
1118
  spinner.text = "Comparing components...";
955
1119
  const installed = await getInstallStatus(installedFiles, registry, config);
956
1120
  spinner.stop();
1121
+ if (options.json) {
1122
+ console.log(JSON.stringify(installed, null, 2));
1123
+ return;
1124
+ }
957
1125
  const identical = installed.filter((c) => c.status === "identical");
958
1126
  const modified = installed.filter((c) => c.status === "modified");
959
1127
  const localOnly = installed.filter((c) => c.status === "local-only");
960
1128
  const installedNames = new Set(installed.map((c) => c.name));
961
1129
  const notInstalled = registry.filter((item) => !installedNames.has(item.name));
962
1130
  console.log();
963
- console.log(chalk4.bold(`Installed Components (${installed.length})`));
1131
+ console.log(chalk5.bold(`Installed Components (${installed.length})`));
964
1132
  console.log();
965
1133
  const categories = /* @__PURE__ */ new Map();
966
1134
  for (const comp of installed) {
@@ -972,56 +1140,58 @@ async function listInstalledComponents(options) {
972
1140
  categories.get(category).push(comp);
973
1141
  }
974
1142
  for (const [category, components] of categories) {
975
- console.log(chalk4.cyan.bold(category));
1143
+ console.log(chalk5.cyan.bold(category));
976
1144
  for (const comp of components) {
977
1145
  let statusIcon;
978
1146
  let statusText;
979
1147
  switch (comp.status) {
980
1148
  case "identical":
981
- statusIcon = chalk4.green("\u2713");
982
- statusText = chalk4.dim("(up to date)");
1149
+ statusIcon = chalk5.green("\u2713");
1150
+ statusText = chalk5.dim("(up to date)");
983
1151
  break;
984
1152
  case "modified":
985
- statusIcon = chalk4.yellow("\u26A0");
986
- statusText = chalk4.yellow("(modified locally)");
1153
+ statusIcon = chalk5.yellow("\u26A0");
1154
+ statusText = chalk5.yellow("(modified locally)");
987
1155
  break;
988
1156
  case "local-only":
989
- statusIcon = chalk4.blue("?");
990
- statusText = chalk4.dim("(custom component)");
1157
+ statusIcon = chalk5.blue("?");
1158
+ statusText = chalk5.dim("(custom component)");
991
1159
  break;
992
1160
  }
993
- console.log(` ${statusIcon} ${chalk4.white(comp.name)} ${statusText}`);
1161
+ console.log(` ${statusIcon} ${chalk5.white(comp.name)} ${statusText}`);
994
1162
  }
995
1163
  console.log();
996
1164
  }
997
1165
  if (notInstalled.length > 0) {
998
- console.log(chalk4.dim("Not Installed"));
1166
+ console.log(chalk5.dim("Not Installed"));
999
1167
  const notInstalledNames = notInstalled.map((c) => c.name).slice(0, 10);
1000
1168
  const remaining = notInstalled.length - 10;
1001
- console.log(chalk4.dim(` ${notInstalledNames.join(", ")}${remaining > 0 ? `, ... +${remaining} more` : ""}`));
1169
+ console.log(chalk5.dim(` ${notInstalledNames.join(", ")}${remaining > 0 ? `, ... +${remaining} more` : ""}`));
1002
1170
  console.log();
1003
1171
  }
1004
- console.log(chalk4.dim("\u2500".repeat(50)));
1172
+ console.log(chalk5.dim("\u2500".repeat(50)));
1005
1173
  const parts = [];
1006
- if (identical.length > 0) parts.push(chalk4.green(`${identical.length} up to date`));
1007
- if (modified.length > 0) parts.push(chalk4.yellow(`${modified.length} modified`));
1008
- if (localOnly.length > 0) parts.push(chalk4.blue(`${localOnly.length} custom`));
1174
+ if (identical.length > 0) parts.push(chalk5.green(`${identical.length} up to date`));
1175
+ if (modified.length > 0) parts.push(chalk5.yellow(`${modified.length} modified`));
1176
+ if (localOnly.length > 0) parts.push(chalk5.blue(`${localOnly.length} custom`));
1009
1177
  console.log(parts.join(" \u2022 "));
1010
1178
  if (modified.length > 0) {
1011
1179
  console.log();
1012
- console.log(chalk4.dim("Sync modified components:"));
1013
- console.log(chalk4.cyan(` npx mcellui diff`));
1180
+ console.log(chalk5.dim("Sync modified components:"));
1181
+ console.log(chalk5.cyan(` npx mcellui diff`));
1014
1182
  }
1015
1183
  } catch (error) {
1016
1184
  spinner.fail("Failed to list installed components");
1017
- console.error(error);
1018
- process.exit(1);
1185
+ handleError({
1186
+ message: "Failed to list installed components",
1187
+ hint: error instanceof Error ? error.message : "Check your network connection and try again"
1188
+ });
1019
1189
  }
1020
1190
  }
1021
1191
 
1022
1192
  // src/commands/doctor.ts
1023
1193
  import { Command as Command4 } from "commander";
1024
- import chalk5 from "chalk";
1194
+ import chalk6 from "chalk";
1025
1195
  import fs6 from "fs-extra";
1026
1196
  import path7 from "path";
1027
1197
  var REQUIRED_PEER_DEPS = [
@@ -1030,7 +1200,7 @@ var REQUIRED_PEER_DEPS = [
1030
1200
  { name: "react-native-safe-area-context", minVersion: "4.0.0" }
1031
1201
  ];
1032
1202
  var RECOMMENDED_DEPS = [
1033
- { name: "@nativeui/core", reason: "Theme system and utilities" }
1203
+ { name: "@metacells/mcellui-core", reason: "Theme system and utilities" }
1034
1204
  ];
1035
1205
  function parseVersion(version) {
1036
1206
  const cleaned = version.replace(/^[\^~>=<]+/, "").replace(/^workspace:\*?/, "");
@@ -1075,7 +1245,7 @@ async function checkProjectType(projectRoot) {
1075
1245
  name: "Project Type",
1076
1246
  status: "fail",
1077
1247
  message: "Not an Expo or React Native project",
1078
- fix: "nativeui requires Expo or React Native"
1248
+ fix: "mcellui requires Expo or React Native"
1079
1249
  };
1080
1250
  }
1081
1251
  return {
@@ -1086,23 +1256,39 @@ async function checkProjectType(projectRoot) {
1086
1256
  }
1087
1257
  async function checkInitialized(projectRoot) {
1088
1258
  const configFiles = [
1259
+ "mcellui.config.ts",
1260
+ "mcellui.config.js",
1261
+ "mcellui.config.json",
1089
1262
  "nativeui.config.ts",
1263
+ // Legacy
1090
1264
  "nativeui.config.js",
1265
+ // Legacy
1091
1266
  "nativeui.config.json"
1267
+ // Legacy
1092
1268
  ];
1093
1269
  let foundConfig = null;
1270
+ let isLegacy = false;
1094
1271
  for (const file of configFiles) {
1095
1272
  if (await fs6.pathExists(path7.join(projectRoot, file))) {
1096
1273
  foundConfig = file;
1274
+ isLegacy = file.startsWith("nativeui.");
1097
1275
  break;
1098
1276
  }
1099
1277
  }
1100
1278
  if (!foundConfig) {
1101
1279
  return {
1102
- name: "NativeUI Config",
1280
+ name: "mcellui Config",
1103
1281
  status: "fail",
1104
- message: "nativeui.config.ts not found",
1105
- fix: "Run: npx nativeui init"
1282
+ message: "mcellui.config.ts not found",
1283
+ fix: "Run: npx mcellui init"
1284
+ };
1285
+ }
1286
+ if (isLegacy) {
1287
+ return {
1288
+ name: "mcellui Config",
1289
+ status: "warn",
1290
+ message: `Found legacy config: ${foundConfig}`,
1291
+ fix: "Consider renaming to mcellui.config.ts"
1106
1292
  };
1107
1293
  }
1108
1294
  try {
@@ -1113,7 +1299,7 @@ async function checkInitialized(projectRoot) {
1113
1299
  const hasExport = content.includes("export default");
1114
1300
  if (!hasExport) {
1115
1301
  return {
1116
- name: "NativeUI Config",
1302
+ name: "mcellui Config",
1117
1303
  status: "warn",
1118
1304
  message: "Config file missing default export",
1119
1305
  fix: "Add: export default defineConfig({ ... })"
@@ -1121,7 +1307,7 @@ async function checkInitialized(projectRoot) {
1121
1307
  }
1122
1308
  if (!hasDefineConfig) {
1123
1309
  return {
1124
- name: "NativeUI Config",
1310
+ name: "mcellui Config",
1125
1311
  status: "warn",
1126
1312
  message: "Config not using defineConfig helper",
1127
1313
  fix: "Wrap config with: defineConfig({ ... })"
@@ -1133,21 +1319,21 @@ async function checkInitialized(projectRoot) {
1133
1319
  JSON.parse(content);
1134
1320
  } catch {
1135
1321
  return {
1136
- name: "NativeUI Config",
1322
+ name: "mcellui Config",
1137
1323
  status: "fail",
1138
1324
  message: "Invalid JSON in config file",
1139
- fix: "Check JSON syntax in nativeui.config.json"
1325
+ fix: "Check JSON syntax in mcellui.config.json"
1140
1326
  };
1141
1327
  }
1142
1328
  }
1143
1329
  return {
1144
- name: "NativeUI Config",
1330
+ name: "mcellui Config",
1145
1331
  status: "pass",
1146
1332
  message: `Found ${foundConfig}`
1147
1333
  };
1148
1334
  } catch (error) {
1149
1335
  return {
1150
- name: "NativeUI Config",
1336
+ name: "mcellui Config",
1151
1337
  status: "fail",
1152
1338
  message: "Could not read config file",
1153
1339
  fix: error instanceof Error ? error.message : "Check file permissions"
@@ -1159,7 +1345,14 @@ async function checkPaths(projectRoot) {
1159
1345
  const defaultUtilsPath = "./lib/utils";
1160
1346
  let componentsPathValue = defaultComponentsPath;
1161
1347
  let utilsPathValue = defaultUtilsPath;
1162
- const configFiles = ["nativeui.config.ts", "nativeui.config.js", "nativeui.config.json"];
1348
+ const configFiles = [
1349
+ "mcellui.config.ts",
1350
+ "mcellui.config.js",
1351
+ "mcellui.config.json",
1352
+ "nativeui.config.ts",
1353
+ "nativeui.config.js",
1354
+ "nativeui.config.json"
1355
+ ];
1163
1356
  for (const file of configFiles) {
1164
1357
  const configPath = path7.join(projectRoot, file);
1165
1358
  if (await fs6.pathExists(configPath)) {
@@ -1183,7 +1376,7 @@ async function checkPaths(projectRoot) {
1183
1376
  name: "Component Paths",
1184
1377
  status: "warn",
1185
1378
  message: "Component and utils directories not created yet",
1186
- fix: `Add a component: npx nativeui add button`
1379
+ fix: `Add a component: npx mcellui add button`
1187
1380
  };
1188
1381
  }
1189
1382
  if (!componentsExist) {
@@ -1191,7 +1384,7 @@ async function checkPaths(projectRoot) {
1191
1384
  name: "Component Paths",
1192
1385
  status: "warn",
1193
1386
  message: `Components directory not found: ${componentsPathValue}`,
1194
- fix: "Add a component to create it: npx nativeui add button"
1387
+ fix: "Add a component to create it: npx mcellui add button"
1195
1388
  };
1196
1389
  }
1197
1390
  return {
@@ -1379,43 +1572,43 @@ async function checkExpoGo(projectRoot) {
1379
1572
  }
1380
1573
  function printReport(report) {
1381
1574
  console.log();
1382
- console.log(chalk5.bold("NativeUI Doctor"));
1383
- console.log(chalk5.dim("Checking your project setup..."));
1575
+ console.log(chalk6.bold("mcellui Doctor"));
1576
+ console.log(chalk6.dim("Checking your project setup..."));
1384
1577
  console.log();
1385
- console.log(chalk5.dim("Project:"), report.projectRoot);
1386
- console.log(chalk5.dim("Type:"), report.projectType);
1387
- console.log(chalk5.dim("Package Manager:"), report.packageManager);
1578
+ console.log(chalk6.dim("Project:"), report.projectRoot);
1579
+ console.log(chalk6.dim("Type:"), report.projectType);
1580
+ console.log(chalk6.dim("Package Manager:"), report.packageManager);
1388
1581
  console.log();
1389
- console.log(chalk5.bold("Checks"));
1582
+ console.log(chalk6.bold("Checks"));
1390
1583
  console.log();
1391
1584
  for (const check of report.checks) {
1392
- const icon = check.status === "pass" ? chalk5.green("\u2713") : check.status === "warn" ? chalk5.yellow("!") : chalk5.red("\u2717");
1393
- const statusColor = check.status === "pass" ? chalk5.green : check.status === "warn" ? chalk5.yellow : chalk5.red;
1394
- console.log(` ${icon} ${chalk5.white(check.name)}`);
1585
+ const icon = check.status === "pass" ? chalk6.green("\u2713") : check.status === "warn" ? chalk6.yellow("!") : chalk6.red("\u2717");
1586
+ const statusColor = check.status === "pass" ? chalk6.green : check.status === "warn" ? chalk6.yellow : chalk6.red;
1587
+ console.log(` ${icon} ${chalk6.white(check.name)}`);
1395
1588
  console.log(` ${statusColor(check.message)}`);
1396
1589
  if (check.fix && check.status !== "pass") {
1397
- console.log(chalk5.dim(` Fix: ${check.fix}`));
1590
+ console.log(chalk6.dim(` Fix: ${check.fix}`));
1398
1591
  }
1399
1592
  }
1400
1593
  console.log();
1401
1594
  const summaryParts = [];
1402
1595
  if (report.passed > 0) {
1403
- summaryParts.push(chalk5.green(`${report.passed} passed`));
1596
+ summaryParts.push(chalk6.green(`${report.passed} passed`));
1404
1597
  }
1405
1598
  if (report.warnings > 0) {
1406
- summaryParts.push(chalk5.yellow(`${report.warnings} warnings`));
1599
+ summaryParts.push(chalk6.yellow(`${report.warnings} warnings`));
1407
1600
  }
1408
1601
  if (report.failed > 0) {
1409
- summaryParts.push(chalk5.red(`${report.failed} failed`));
1602
+ summaryParts.push(chalk6.red(`${report.failed} failed`));
1410
1603
  }
1411
- console.log(chalk5.bold("Summary:"), summaryParts.join(", "));
1604
+ console.log(chalk6.bold("Summary:"), summaryParts.join(", "));
1412
1605
  console.log();
1413
1606
  if (report.failed > 0) {
1414
- console.log(chalk5.red("Some checks failed. Please fix the issues above."));
1607
+ console.log(chalk6.red("Some checks failed. Please fix the issues above."));
1415
1608
  } else if (report.warnings > 0) {
1416
- console.log(chalk5.yellow("Your project has some warnings but should work."));
1609
+ console.log(chalk6.yellow("Your project has some warnings but should work."));
1417
1610
  } else {
1418
- console.log(chalk5.green("Your project is properly configured!"));
1611
+ console.log(chalk6.green("Your project is properly configured!"));
1419
1612
  }
1420
1613
  console.log();
1421
1614
  }
@@ -1424,9 +1617,7 @@ var doctorCommand = new Command4().name("doctor").description("Check project set
1424
1617
  const cwd = path7.resolve(options.cwd);
1425
1618
  const projectRoot = await getProjectRoot(cwd);
1426
1619
  if (!projectRoot) {
1427
- console.log(chalk5.red("Could not find a valid project."));
1428
- console.log(chalk5.dim("Make sure you run this command in a project directory."));
1429
- process.exit(1);
1620
+ errors.noProject();
1430
1621
  }
1431
1622
  const projectType = await detectProjectType(projectRoot);
1432
1623
  const packageManager = await detectPackageManager(projectRoot);
@@ -1464,14 +1655,16 @@ var doctorCommand = new Command4().name("doctor").description("Check project set
1464
1655
  process.exit(1);
1465
1656
  }
1466
1657
  } catch (error) {
1467
- console.error(chalk5.red("Doctor check failed:"), error);
1468
- process.exit(1);
1658
+ handleError({
1659
+ message: "Doctor check failed",
1660
+ hint: error instanceof Error ? error.message : "Run again with --json for details"
1661
+ });
1469
1662
  }
1470
1663
  });
1471
1664
 
1472
1665
  // src/commands/diff.ts
1473
1666
  import { Command as Command5 } from "commander";
1474
- import chalk6 from "chalk";
1667
+ import chalk7 from "chalk";
1475
1668
  import ora4 from "ora";
1476
1669
  import fs7 from "fs-extra";
1477
1670
  import path8 from "path";
@@ -1482,22 +1675,18 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
1482
1675
  const cwd = path8.resolve(options.cwd);
1483
1676
  const projectRoot = await getProjectRoot(cwd);
1484
1677
  if (!projectRoot) {
1485
- console.log(chalk6.red("Could not find a valid project."));
1486
- console.log(chalk6.dim("Run `npx mcellui init` first."));
1487
- process.exit(1);
1678
+ errors.noProject();
1488
1679
  }
1489
1680
  const config = await getConfig(projectRoot);
1490
1681
  if (!config) {
1491
- console.log(chalk6.red("Project not initialized."));
1492
- console.log(chalk6.dim("Run `npx mcellui init` first."));
1493
- process.exit(1);
1682
+ errors.notInitialized();
1494
1683
  }
1495
1684
  spinner.start("Scanning installed components...");
1496
1685
  const componentsDir = path8.join(projectRoot, config.componentsPath);
1497
1686
  const installedFiles = await getInstalledFiles(componentsDir);
1498
1687
  if (installedFiles.length === 0) {
1499
1688
  spinner.info("No components installed yet.");
1500
- console.log(chalk6.dim("\nAdd components with: npx mcellui add <component>"));
1689
+ console.log(chalk7.dim("\nAdd components with: npx mcellui add <component>"));
1501
1690
  return;
1502
1691
  }
1503
1692
  spinner.text = "Fetching registry...";
@@ -1519,8 +1708,11 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
1519
1708
  return componentFileNames.includes(fileName);
1520
1709
  });
1521
1710
  if (filesToCompare.length === 0) {
1522
- spinner.fail(`None of the specified components found: ${components.join(", ")}`);
1523
- process.exit(1);
1711
+ spinner.stop();
1712
+ handleError({
1713
+ message: "None of the specified components are installed",
1714
+ hint: "Check component names: npx mcellui list --installed"
1715
+ });
1524
1716
  }
1525
1717
  }
1526
1718
  spinner.text = "Comparing components...";
@@ -1560,10 +1752,8 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
1560
1752
  continue;
1561
1753
  }
1562
1754
  const localContent = await fs7.readFile(localFile, "utf-8");
1563
- const normalizedLocal = normalizeContent(localContent);
1564
- const normalizedRegistry = normalizeContent(
1565
- transformImports(registryFile.content, config)
1566
- );
1755
+ const normalizedLocal = normalizeForComparison(localContent);
1756
+ const normalizedRegistry = normalizeForComparison(registryFile.content);
1567
1757
  if (normalizedLocal === normalizedRegistry) {
1568
1758
  results.push({
1569
1759
  name: registryItem.name,
@@ -1606,35 +1796,37 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
1606
1796
  const hasChanges = results.some((r) => r.status === "modified");
1607
1797
  process.exit(hasChanges ? 1 : 0);
1608
1798
  } catch (error) {
1609
- spinner.fail("Failed to diff components");
1610
- console.error(error);
1611
- process.exit(1);
1799
+ spinner.stop();
1800
+ handleError({
1801
+ message: "Failed to diff components",
1802
+ hint: error instanceof Error ? error.message : "Check your network connection"
1803
+ });
1612
1804
  }
1613
1805
  });
1614
1806
  function printResults(results, listOnly) {
1615
1807
  const identical = results.filter((r) => r.status === "identical");
1616
1808
  const modified = results.filter((r) => r.status === "modified");
1617
1809
  const localOnly = results.filter((r) => r.status === "local-only");
1618
- const errors = results.filter((r) => r.status === "error");
1810
+ const errors2 = results.filter((r) => r.status === "error");
1619
1811
  console.log();
1620
- console.log(chalk6.bold("Comparing components..."));
1812
+ console.log(chalk7.bold("Comparing components..."));
1621
1813
  console.log();
1622
1814
  for (const result of results) {
1623
1815
  switch (result.status) {
1624
1816
  case "identical":
1625
- console.log(`${chalk6.green("\u2713")} ${result.fileName} ${chalk6.dim("(identical)")}`);
1817
+ console.log(`${chalk7.green("\u2713")} ${result.fileName} ${chalk7.dim("(identical)")}`);
1626
1818
  break;
1627
1819
  case "modified":
1628
- console.log(`${chalk6.red("\u2717")} ${result.fileName} ${chalk6.yellow("(modified)")}`);
1820
+ console.log(`${chalk7.red("\u2717")} ${result.fileName} ${chalk7.yellow("(modified)")}`);
1629
1821
  if (!listOnly && result.diff) {
1630
1822
  printColoredDiff(result.diff);
1631
1823
  }
1632
1824
  break;
1633
1825
  case "local-only":
1634
- console.log(`${chalk6.yellow("\u26A0")} ${result.fileName} ${chalk6.dim("(not in registry)")}`);
1826
+ console.log(`${chalk7.yellow("\u26A0")} ${result.fileName} ${chalk7.dim("(not in registry)")}`);
1635
1827
  break;
1636
1828
  case "error":
1637
- console.log(`${chalk6.red("!")} ${result.fileName} ${chalk6.red(`(error: ${result.error})`)}`);
1829
+ console.log(`${chalk7.red("!")} ${result.fileName} ${chalk7.red(`(error: ${result.error})`)}`);
1638
1830
  break;
1639
1831
  }
1640
1832
  }
@@ -1643,12 +1835,12 @@ function printResults(results, listOnly) {
1643
1835
  if (identical.length > 0) parts.push(`${identical.length} identical`);
1644
1836
  if (modified.length > 0) parts.push(`${modified.length} modified`);
1645
1837
  if (localOnly.length > 0) parts.push(`${localOnly.length} custom`);
1646
- if (errors.length > 0) parts.push(`${errors.length} errors`);
1647
- console.log(chalk6.dim(`Summary: ${parts.join(", ")}`));
1838
+ if (errors2.length > 0) parts.push(`${errors2.length} errors`);
1839
+ console.log(chalk7.dim(`Summary: ${parts.join(", ")}`));
1648
1840
  if (modified.length > 0) {
1649
1841
  console.log();
1650
- console.log(chalk6.dim("Update modified components with:"));
1651
- console.log(chalk6.cyan(` npx mcellui add ${modified.map((m) => m.name).join(" ")} --overwrite`));
1842
+ console.log(chalk7.dim("Update modified components with:"));
1843
+ console.log(chalk7.cyan(` npx mcellui add ${modified.map((m) => m.name).join(" ")} --overwrite`));
1652
1844
  }
1653
1845
  }
1654
1846
  function printColoredDiff(diffOutput) {
@@ -1656,47 +1848,42 @@ function printColoredDiff(diffOutput) {
1656
1848
  const contentLines = lines.slice(4);
1657
1849
  for (const line of contentLines) {
1658
1850
  if (line.startsWith("+") && !line.startsWith("+++")) {
1659
- console.log(chalk6.green(` ${line}`));
1851
+ console.log(chalk7.green(` ${line}`));
1660
1852
  } else if (line.startsWith("-") && !line.startsWith("---")) {
1661
- console.log(chalk6.red(` ${line}`));
1853
+ console.log(chalk7.red(` ${line}`));
1662
1854
  } else if (line.startsWith("@@")) {
1663
- console.log(chalk6.cyan(` ${line}`));
1855
+ console.log(chalk7.cyan(` ${line}`));
1664
1856
  } else if (line.trim()) {
1665
- console.log(chalk6.dim(` ${line}`));
1857
+ console.log(chalk7.dim(` ${line}`));
1666
1858
  }
1667
1859
  }
1668
1860
  }
1669
1861
 
1670
1862
  // src/commands/update.ts
1671
1863
  import { Command as Command6 } from "commander";
1672
- import chalk7 from "chalk";
1864
+ import chalk8 from "chalk";
1673
1865
  import ora5 from "ora";
1674
1866
  import prompts3 from "prompts";
1675
1867
  import fs8 from "fs-extra";
1676
1868
  import path9 from "path";
1677
- import crypto from "crypto";
1678
1869
  var updateCommand = new Command6().name("update").description("Update installed components to latest registry versions").argument("[components...]", "Specific components to update (default: all outdated)").option("-y, --yes", "Skip confirmation prompt").option("--all", "Update all components (including up-to-date)").option("--dry-run", "Show what would be updated without making changes").option("--cwd <path>", "Working directory", process.cwd()).action(async (components, options) => {
1679
1870
  const spinner = ora5();
1680
1871
  try {
1681
1872
  const cwd = path9.resolve(options.cwd);
1682
1873
  const projectRoot = await getProjectRoot(cwd);
1683
1874
  if (!projectRoot) {
1684
- console.log(chalk7.red("Could not find a valid project."));
1685
- console.log(chalk7.dim("Run `npx nativeui init` first."));
1686
- process.exit(1);
1875
+ errors.noProject();
1687
1876
  }
1688
1877
  const config = await getConfig(projectRoot);
1689
1878
  if (!config) {
1690
- console.log(chalk7.red("Project not initialized."));
1691
- console.log(chalk7.dim("Run `npx nativeui init` first."));
1692
- process.exit(1);
1879
+ errors.notInitialized();
1693
1880
  }
1694
1881
  spinner.start("Checking for updates...");
1695
1882
  const componentsDir = path9.join(projectRoot, config.componentsPath);
1696
1883
  const diffs = await getComponentDiffs(componentsDir, config);
1697
1884
  if (diffs.length === 0) {
1698
1885
  spinner.info("No components installed yet.");
1699
- console.log(chalk7.dim("\nAdd components with: npx nativeui add <component>"));
1886
+ console.log(chalk8.dim("\nAdd components with: npx mcellui add <component>"));
1700
1887
  return;
1701
1888
  }
1702
1889
  spinner.stop();
@@ -1705,7 +1892,7 @@ var updateCommand = new Command6().name("update").description("Update installed
1705
1892
  toUpdate = diffs.filter((d) => components.includes(d.name));
1706
1893
  const notFound = components.filter((c) => !diffs.some((d) => d.name === c));
1707
1894
  if (notFound.length > 0) {
1708
- console.log(chalk7.yellow(`Components not found: ${notFound.join(", ")}`));
1895
+ console.log(chalk8.yellow(`Components not found: ${notFound.join(", ")}`));
1709
1896
  }
1710
1897
  } else if (options.all) {
1711
1898
  toUpdate = diffs;
@@ -1713,19 +1900,19 @@ var updateCommand = new Command6().name("update").description("Update installed
1713
1900
  toUpdate = diffs.filter((d) => d.hasUpdate);
1714
1901
  }
1715
1902
  if (toUpdate.length === 0) {
1716
- console.log(chalk7.green("\n\u2713 All components are up to date!"));
1903
+ console.log(chalk8.green("\n\u2713 All components are up to date!"));
1717
1904
  return;
1718
1905
  }
1719
1906
  console.log();
1720
- console.log(chalk7.bold(`Components to update (${toUpdate.length}):`));
1907
+ console.log(chalk8.bold(`Components to update (${toUpdate.length}):`));
1721
1908
  for (const comp of toUpdate) {
1722
- const status = comp.hasUpdate ? chalk7.yellow("\u25CF") : chalk7.green("\u25CF");
1723
- const label = comp.hasUpdate ? chalk7.dim("(update available)") : chalk7.dim("(re-sync)");
1909
+ const status = comp.hasUpdate ? chalk8.yellow("\u25CF") : chalk8.green("\u25CF");
1910
+ const label = comp.hasUpdate ? chalk8.dim("(update available)") : chalk8.dim("(re-sync)");
1724
1911
  console.log(` ${status} ${comp.name} ${label}`);
1725
1912
  }
1726
1913
  console.log();
1727
1914
  if (options.dryRun) {
1728
- console.log(chalk7.dim("Dry run mode - no changes made."));
1915
+ console.log(chalk8.dim("Dry run mode - no changes made."));
1729
1916
  return;
1730
1917
  }
1731
1918
  if (!options.yes) {
@@ -1735,8 +1922,11 @@ var updateCommand = new Command6().name("update").description("Update installed
1735
1922
  message: `Update ${toUpdate.length} component${toUpdate.length !== 1 ? "s" : ""}?`,
1736
1923
  initial: true
1737
1924
  });
1925
+ if (confirm === void 0) {
1926
+ process.exit(0);
1927
+ }
1738
1928
  if (!confirm) {
1739
- console.log(chalk7.dim("Cancelled."));
1929
+ console.log(chalk8.dim("Cancelled."));
1740
1930
  return;
1741
1931
  }
1742
1932
  }
@@ -1758,7 +1948,7 @@ var updateCommand = new Command6().name("update").description("Update installed
1758
1948
  for (const file of component.files) {
1759
1949
  const targetPath = path9.join(targetDir, file.name);
1760
1950
  await fs8.ensureDir(targetDir);
1761
- const transformedContent = transformImports3(file.content, config);
1951
+ const transformedContent = transformToInstalled(file.content, config);
1762
1952
  await fs8.writeFile(targetPath, transformedContent);
1763
1953
  }
1764
1954
  spinner.succeed(`Updated ${comp.name}`);
@@ -1776,27 +1966,32 @@ var updateCommand = new Command6().name("update").description("Update installed
1776
1966
  }
1777
1967
  console.log();
1778
1968
  if (successCount > 0) {
1779
- console.log(chalk7.green(`\u2713 Updated ${successCount} component${successCount !== 1 ? "s" : ""}`));
1969
+ console.log(chalk8.green(`\u2713 Updated ${successCount} component${successCount !== 1 ? "s" : ""}`));
1780
1970
  }
1781
1971
  if (failCount > 0) {
1782
- console.log(chalk7.red(`\u2717 Failed to update ${failCount} component${failCount !== 1 ? "s" : ""}`));
1972
+ console.log(chalk8.red(`\u2717 Failed to update ${failCount} component${failCount !== 1 ? "s" : ""}`));
1783
1973
  }
1784
1974
  const uniqueDeps = [...new Set(allDependencies)];
1785
1975
  const uniqueDevDeps = [...new Set(allDevDependencies)];
1786
1976
  if (uniqueDeps.length || uniqueDevDeps.length) {
1787
1977
  console.log();
1788
- console.log(chalk7.bold("Install/update dependencies:"));
1978
+ console.log(chalk8.bold("Install/update dependencies:"));
1789
1979
  if (uniqueDeps.length) {
1790
- console.log(chalk7.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
1980
+ console.log(chalk8.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
1791
1981
  }
1792
1982
  if (uniqueDevDeps.length) {
1793
- console.log(chalk7.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
1983
+ console.log(chalk8.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
1794
1984
  }
1795
1985
  }
1986
+ if (failCount > 0) {
1987
+ process.exit(1);
1988
+ }
1796
1989
  } catch (error) {
1797
1990
  spinner.fail("Failed to update");
1798
- console.error(error);
1799
- process.exit(1);
1991
+ handleError({
1992
+ message: "Failed to update components",
1993
+ hint: error instanceof Error ? error.message : "Check your network connection and try again"
1994
+ });
1800
1995
  }
1801
1996
  });
1802
1997
  async function getComponentDiffs(componentsDir, config) {
@@ -1842,34 +2037,17 @@ async function checkForUpdate(localFile, registryItem, config) {
1842
2037
  const registryFile = component.files.find((f) => f.name === fileName);
1843
2038
  if (!registryFile) return false;
1844
2039
  const localContent = await fs8.readFile(localFile, "utf-8");
1845
- const transformedRegistryContent = transformImports3(registryFile.content, config);
1846
- const localHash = hashContent(localContent);
1847
- const registryHash = hashContent(transformedRegistryContent);
1848
- return localHash !== registryHash;
2040
+ const normalizedLocal = normalizeForComparison(localContent);
2041
+ const normalizedRegistry = normalizeForComparison(registryFile.content);
2042
+ return normalizedLocal !== normalizedRegistry;
1849
2043
  } catch {
1850
2044
  return false;
1851
2045
  }
1852
2046
  }
1853
- function hashContent(content) {
1854
- const normalized = content.replace(/\r\n/g, "\n").replace(/\s+$/gm, "").trim();
1855
- return crypto.createHash("md5").update(normalized).digest("hex");
1856
- }
1857
- function transformImports3(code, config) {
1858
- let transformed = code;
1859
- const utilsAlias = config.aliases?.utils || "@/lib/utils";
1860
- if (utilsAlias === "@/lib/utils") {
1861
- return transformed;
1862
- }
1863
- transformed = transformed.replace(
1864
- /from ['"]@\/lib\/utils['"]/g,
1865
- `from '${utilsAlias}'`
1866
- );
1867
- return transformed;
1868
- }
1869
2047
 
1870
2048
  // src/commands/create.ts
1871
2049
  import { Command as Command7 } from "commander";
1872
- import chalk8 from "chalk";
2050
+ import chalk9 from "chalk";
1873
2051
  import ora6 from "ora";
1874
2052
  import prompts4 from "prompts";
1875
2053
  import fs9 from "fs-extra";
@@ -1880,33 +2058,31 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
1880
2058
  const cwd = path10.resolve(options.cwd);
1881
2059
  const projectRoot = await getProjectRoot(cwd);
1882
2060
  if (!projectRoot) {
1883
- console.log(chalk8.red("Could not find a valid project."));
1884
- console.log(chalk8.dim("Run `npx nativeui init` first."));
1885
- process.exit(1);
2061
+ errors.noProject();
1886
2062
  }
1887
2063
  const config = await getConfig(projectRoot);
1888
2064
  if (!config) {
1889
- console.log(chalk8.red("Project not initialized."));
1890
- console.log(chalk8.dim("Run `npx nativeui init` first."));
1891
- process.exit(1);
2065
+ errors.notInitialized();
1892
2066
  }
1893
2067
  const componentName = toPascalCase(name);
1894
2068
  const fileName = toKebabCase(name) + ".tsx";
1895
2069
  const targetDir = path10.join(projectRoot, config.componentsPath);
1896
2070
  const targetPath = path10.join(targetDir, fileName);
1897
2071
  if (await fs9.pathExists(targetPath)) {
1898
- console.log(chalk8.red(`Component already exists: ${fileName}`));
1899
- console.log(chalk8.dim(`Path: ${targetPath}`));
1900
- process.exit(1);
2072
+ handleError({
2073
+ message: `Component already exists: ${fileName}`,
2074
+ hint: "Choose a different name or delete the existing file",
2075
+ code: "COMPONENT_EXISTS"
2076
+ });
1901
2077
  }
1902
2078
  if (!options.yes) {
1903
2079
  console.log();
1904
- console.log(chalk8.bold("Create new component:"));
1905
- console.log(` Name: ${chalk8.cyan(componentName)}`);
1906
- console.log(` File: ${chalk8.dim(fileName)}`);
1907
- console.log(` Path: ${chalk8.dim(targetPath)}`);
1908
- console.log(` Template: ${chalk8.dim(options.template)}`);
1909
- console.log(` ForwardRef: ${chalk8.dim(options.forwardRef ? "Yes" : "No")}`);
2080
+ console.log(chalk9.bold("Create new component:"));
2081
+ console.log(` Name: ${chalk9.cyan(componentName)}`);
2082
+ console.log(` File: ${chalk9.dim(fileName)}`);
2083
+ console.log(` Path: ${chalk9.dim(targetPath)}`);
2084
+ console.log(` Template: ${chalk9.dim(options.template)}`);
2085
+ console.log(` ForwardRef: ${chalk9.dim(options.forwardRef ? "Yes" : "No")}`);
1910
2086
  console.log();
1911
2087
  const { confirm } = await prompts4({
1912
2088
  type: "confirm",
@@ -1914,8 +2090,11 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
1914
2090
  message: "Create this component?",
1915
2091
  initial: true
1916
2092
  });
2093
+ if (confirm === void 0) {
2094
+ process.exit(0);
2095
+ }
1917
2096
  if (!confirm) {
1918
- console.log(chalk8.dim("Cancelled."));
2097
+ console.log(chalk9.dim("Cancelled."));
1919
2098
  return;
1920
2099
  }
1921
2100
  }
@@ -1925,15 +2104,17 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
1925
2104
  await fs9.writeFile(targetPath, code);
1926
2105
  spinner.succeed(`Created ${fileName}`);
1927
2106
  console.log();
1928
- console.log(chalk8.bold("Next steps:"));
1929
- console.log(` 1. Edit your component: ${chalk8.cyan(targetPath)}`);
2107
+ console.log(chalk9.bold("Next steps:"));
2108
+ console.log(` 1. Edit your component: ${chalk9.cyan(targetPath)}`);
1930
2109
  console.log(` 2. Import it in your app:`);
1931
- console.log(chalk8.dim(` import { ${componentName} } from '${config.aliases?.components || "@/components"}/ui/${toKebabCase(name)}';`));
2110
+ console.log(chalk9.dim(` import { ${componentName} } from '${config.aliases?.components || "@/components"}/ui/${toKebabCase(name)}';`));
1932
2111
  console.log();
1933
2112
  } catch (error) {
1934
2113
  spinner.fail("Failed to create component");
1935
- console.error(error);
1936
- process.exit(1);
2114
+ handleError({
2115
+ message: "Failed to create component",
2116
+ hint: error instanceof Error ? error.message : "Check file permissions and try again"
2117
+ });
1937
2118
  }
1938
2119
  });
1939
2120
  function toPascalCase(str) {
@@ -1955,7 +2136,7 @@ function generateBasicComponent(name, forwardRef) {
1955
2136
  if (forwardRef) {
1956
2137
  return `import React, { forwardRef } from 'react';
1957
2138
  import { View, Text, StyleSheet, ViewProps } from 'react-native';
1958
- import { useTheme } from '@nativeui/core';
2139
+ import { useTheme } from '@metacells/mcellui-core';
1959
2140
 
1960
2141
  export interface ${name}Props extends ViewProps {
1961
2142
  /**
@@ -1967,7 +2148,7 @@ export interface ${name}Props extends ViewProps {
1967
2148
  /**
1968
2149
  * ${name}
1969
2150
  *
1970
- * A custom component created with nativeui create.
2151
+ * A custom component created with mcellui create.
1971
2152
  *
1972
2153
  * @example
1973
2154
  * \`\`\`tsx
@@ -2015,7 +2196,7 @@ const styles = StyleSheet.create({
2015
2196
  }
2016
2197
  return `import React from 'react';
2017
2198
  import { View, Text, StyleSheet, ViewProps } from 'react-native';
2018
- import { useTheme } from '@nativeui/core';
2199
+ import { useTheme } from '@metacells/mcellui-core';
2019
2200
 
2020
2201
  export interface ${name}Props extends ViewProps {
2021
2202
  /**
@@ -2027,7 +2208,7 @@ export interface ${name}Props extends ViewProps {
2027
2208
  /**
2028
2209
  * ${name}
2029
2210
  *
2030
- * A custom component created with nativeui create.
2211
+ * A custom component created with mcellui create.
2031
2212
  *
2032
2213
  * @example
2033
2214
  * \`\`\`tsx
@@ -2082,7 +2263,7 @@ import Animated, {
2082
2263
  useSharedValue,
2083
2264
  withSpring,
2084
2265
  } from 'react-native-reanimated';
2085
- import { useTheme } from '@nativeui/core';
2266
+ import { useTheme } from '@metacells/mcellui-core';
2086
2267
 
2087
2268
  export interface ${name}Props extends ViewProps {
2088
2269
  /**
@@ -2094,7 +2275,7 @@ export interface ${name}Props extends ViewProps {
2094
2275
  /**
2095
2276
  * ${name}
2096
2277
  *
2097
- * An animated component created with nativeui create.
2278
+ * An animated component created with mcellui create.
2098
2279
  *
2099
2280
  * @example
2100
2281
  * \`\`\`tsx
@@ -2151,7 +2332,7 @@ import Animated, {
2151
2332
  useSharedValue,
2152
2333
  withTiming,
2153
2334
  } from 'react-native-reanimated';
2154
- import { useTheme } from '@nativeui/core';
2335
+ import { useTheme } from '@metacells/mcellui-core';
2155
2336
 
2156
2337
  const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
2157
2338
 
@@ -2169,7 +2350,7 @@ export interface ${name}Props extends Omit<PressableProps, 'style'> {
2169
2350
  /**
2170
2351
  * ${name}
2171
2352
  *
2172
- * A pressable component created with nativeui create.
2353
+ * A pressable component created with mcellui create.
2173
2354
  *
2174
2355
  * @example
2175
2356
  * \`\`\`tsx
@@ -2244,7 +2425,7 @@ import Animated, {
2244
2425
  useSharedValue,
2245
2426
  withTiming,
2246
2427
  } from 'react-native-reanimated';
2247
- import { useTheme } from '@nativeui/core';
2428
+ import { useTheme } from '@metacells/mcellui-core';
2248
2429
 
2249
2430
  const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
2250
2431
 
@@ -2262,7 +2443,7 @@ export interface ${name}Props extends Omit<PressableProps, 'style'> {
2262
2443
  /**
2263
2444
  * ${name}
2264
2445
  *
2265
- * A pressable component created with nativeui create.
2446
+ * A pressable component created with mcellui create.
2266
2447
  *
2267
2448
  * @example
2268
2449
  * \`\`\`tsx
@@ -2334,7 +2515,7 @@ import Animated, {
2334
2515
  useSharedValue,
2335
2516
  withTiming,
2336
2517
  } from 'react-native-reanimated';
2337
- import { useTheme } from '@nativeui/core';
2518
+ import { useTheme } from '@metacells/mcellui-core';
2338
2519
 
2339
2520
  export interface ${name}Props extends TextInputProps {
2340
2521
  /**
@@ -2350,7 +2531,7 @@ export interface ${name}Props extends TextInputProps {
2350
2531
  /**
2351
2532
  * ${name}
2352
2533
  *
2353
- * A custom input component created with nativeui create.
2534
+ * A custom input component created with mcellui create.
2354
2535
  *
2355
2536
  * @example
2356
2537
  * \`\`\`tsx
@@ -2459,7 +2640,7 @@ import Animated, {
2459
2640
  useSharedValue,
2460
2641
  withTiming,
2461
2642
  } from 'react-native-reanimated';
2462
- import { useTheme } from '@nativeui/core';
2643
+ import { useTheme } from '@metacells/mcellui-core';
2463
2644
 
2464
2645
  export interface ${name}Props extends TextInputProps {
2465
2646
  /**
@@ -2475,7 +2656,7 @@ export interface ${name}Props extends TextInputProps {
2475
2656
  /**
2476
2657
  * ${name}
2477
2658
  *
2478
- * A custom input component created with nativeui create.
2659
+ * A custom input component created with mcellui create.
2479
2660
  *
2480
2661
  * @example
2481
2662
  * \`\`\`tsx
@@ -2575,7 +2756,7 @@ const styles = StyleSheet.create({
2575
2756
 
2576
2757
  // src/commands/pick.ts
2577
2758
  import { Command as Command8 } from "commander";
2578
- import chalk9 from "chalk";
2759
+ import chalk10 from "chalk";
2579
2760
  import prompts5 from "prompts";
2580
2761
  import ora7 from "ora";
2581
2762
  import fs10 from "fs-extra";
@@ -2627,7 +2808,7 @@ function formatCategoryName(category) {
2627
2808
  }
2628
2809
  function formatComponentChoice(item, installed) {
2629
2810
  const isInstalled = installed.has(item.name);
2630
- const status = isInstalled ? chalk9.green(" \u2713") : "";
2811
+ const status = isInstalled ? chalk10.green(" \u2713") : "";
2631
2812
  const description = item.description || "";
2632
2813
  return {
2633
2814
  title: `${item.name}${status}`,
@@ -2636,37 +2817,25 @@ function formatComponentChoice(item, installed) {
2636
2817
  disabled: isInstalled
2637
2818
  };
2638
2819
  }
2639
- function transformImports4(code, config) {
2640
- let transformed = code;
2641
- const utilsAlias = config.aliases?.utils || "@/lib/utils";
2642
- if (utilsAlias === "@/lib/utils") {
2643
- return transformed;
2644
- }
2645
- transformed = transformed.replace(
2646
- /from ['"]@\/lib\/utils['"]/g,
2647
- `from '${utilsAlias}'`
2648
- );
2649
- return transformed;
2650
- }
2651
2820
  var pickCommand = new Command8().name("pick").description("Interactively browse and select components to add").option("--all", "Show all components without category selection").option("-o, --overwrite", "Overwrite existing files").option("--cwd <path>", "Working directory", process.cwd()).action(async (options) => {
2652
- console.log(chalk9.bold("\n\u{1F3A8} nativeui Component Picker\n"));
2821
+ console.log(chalk10.bold("\n\u{1F3A8} mcellui Component Picker\n"));
2653
2822
  const cwd = path11.resolve(options.cwd);
2654
2823
  const projectRoot = await getProjectRoot(cwd);
2655
2824
  if (!projectRoot) {
2656
- console.log(chalk9.red("Could not find a valid project."));
2657
- console.log(chalk9.dim("Run `npx nativeui init` first.\n"));
2658
- return;
2825
+ errors.noProject();
2659
2826
  }
2660
2827
  const config = await getConfig(projectRoot);
2661
2828
  if (!config) {
2662
- console.log(chalk9.yellow("No nativeui.config.ts found. Run `npx nativeui init` first.\n"));
2663
- return;
2829
+ errors.notInitialized();
2664
2830
  }
2665
2831
  const spinner = ora7("Loading component registry...").start();
2666
2832
  const registry = await getRegistry();
2667
2833
  if (!registry.length) {
2668
- spinner.fail("Could not load registry");
2669
- return;
2834
+ spinner.stop();
2835
+ handleError({
2836
+ message: "Could not load component registry",
2837
+ hint: "Check your internet connection and try again"
2838
+ });
2670
2839
  }
2671
2840
  spinner.succeed(`Loaded ${registry.length} components`);
2672
2841
  const componentsDir = path11.join(projectRoot, config.componentsPath);
@@ -2696,8 +2865,11 @@ var pickCommand = new Command8().name("pick").description("Interactively browse
2696
2865
  message: "Select a category",
2697
2866
  choices: categoryChoices
2698
2867
  });
2868
+ if (categoryResponse.category === void 0) {
2869
+ process.exit(0);
2870
+ }
2699
2871
  if (!categoryResponse.category) {
2700
- console.log(chalk9.yellow("\nCancelled.\n"));
2872
+ console.log(chalk10.yellow("\nCancelled.\n"));
2701
2873
  return;
2702
2874
  }
2703
2875
  selectedCategory = categoryResponse.category;
@@ -2710,10 +2882,10 @@ var pickCommand = new Command8().name("pick").description("Interactively browse
2710
2882
  );
2711
2883
  const availableCount = componentChoices.filter((c) => !c.disabled).length;
2712
2884
  if (availableCount === 0) {
2713
- console.log(chalk9.green("\n\u2713 All components in this category are already installed!\n"));
2885
+ console.log(chalk10.green("\n\u2713 All components in this category are already installed!\n"));
2714
2886
  return;
2715
2887
  }
2716
- console.log(chalk9.dim(`
2888
+ console.log(chalk10.dim(`
2717
2889
  ${installed.size} already installed, ${availableCount} available
2718
2890
  `));
2719
2891
  const componentResponse = await prompts5({
@@ -2724,14 +2896,17 @@ ${installed.size} already installed, ${availableCount} available
2724
2896
  hint: "- Space to select. Return to submit",
2725
2897
  instructions: false
2726
2898
  });
2899
+ if (componentResponse.components === void 0) {
2900
+ process.exit(0);
2901
+ }
2727
2902
  if (!componentResponse.components || componentResponse.components.length === 0) {
2728
- console.log(chalk9.yellow("\nNo components selected.\n"));
2903
+ console.log(chalk10.yellow("\nNo components selected.\n"));
2729
2904
  return;
2730
2905
  }
2731
2906
  const selectedComponents = componentResponse.components;
2732
- console.log(chalk9.bold("\nComponents to install:"));
2907
+ console.log(chalk10.bold("\nComponents to install:"));
2733
2908
  for (const name of selectedComponents) {
2734
- console.log(chalk9.cyan(` \u2022 ${name}`));
2909
+ console.log(chalk10.cyan(` \u2022 ${name}`));
2735
2910
  }
2736
2911
  const confirmResponse = await prompts5({
2737
2912
  type: "confirm",
@@ -2739,12 +2914,16 @@ ${installed.size} already installed, ${availableCount} available
2739
2914
  message: `Install ${selectedComponents.length} component(s)?`,
2740
2915
  initial: true
2741
2916
  });
2917
+ if (confirmResponse.proceed === void 0) {
2918
+ process.exit(0);
2919
+ }
2742
2920
  if (!confirmResponse.proceed) {
2743
- console.log(chalk9.yellow("\nCancelled.\n"));
2921
+ console.log(chalk10.yellow("\nCancelled.\n"));
2744
2922
  return;
2745
2923
  }
2746
2924
  console.log("");
2747
2925
  let successCount = 0;
2926
+ let failCount = 0;
2748
2927
  const allDependencies = [];
2749
2928
  const allDevDependencies = [];
2750
2929
  for (const name of selectedComponents) {
@@ -2753,6 +2932,7 @@ ${installed.size} already installed, ${availableCount} available
2753
2932
  const component = await fetchComponent(name);
2754
2933
  if (!component) {
2755
2934
  installSpinner.fail(`Component "${name}" not found`);
2935
+ failCount++;
2756
2936
  continue;
2757
2937
  }
2758
2938
  const targetDir = path11.join(projectRoot, config.componentsPath);
@@ -2763,10 +2943,10 @@ ${installed.size} already installed, ${availableCount} available
2763
2943
  continue;
2764
2944
  }
2765
2945
  await fs10.ensureDir(targetDir);
2766
- const transformedContent = transformImports4(file.content, config);
2946
+ const transformedContent = transformToInstalled(file.content, config);
2767
2947
  await fs10.writeFile(targetPath, transformedContent);
2768
2948
  }
2769
- installSpinner.succeed(`Installed ${chalk9.green(name)}`);
2949
+ installSpinner.succeed(`Installed ${chalk10.green(name)}`);
2770
2950
  successCount++;
2771
2951
  if (component.dependencies?.length) {
2772
2952
  allDependencies.push(...component.dependencies);
@@ -2775,42 +2955,51 @@ ${installed.size} already installed, ${availableCount} available
2775
2955
  allDevDependencies.push(...component.devDependencies);
2776
2956
  }
2777
2957
  if (component.registryDependencies?.length) {
2778
- console.log(chalk9.dim(` Requires: ${component.registryDependencies.join(", ")}`));
2958
+ console.log(chalk10.dim(` Requires: ${component.registryDependencies.join(", ")}`));
2779
2959
  }
2780
2960
  } catch (error) {
2781
2961
  installSpinner.fail(`Failed to install ${name}: ${error}`);
2962
+ failCount++;
2782
2963
  }
2783
2964
  }
2965
+ if (failCount > 0) {
2966
+ process.exit(1);
2967
+ }
2784
2968
  console.log(
2785
- chalk9.bold.green(`
2969
+ chalk10.bold.green(`
2786
2970
  \u2713 Successfully installed ${successCount}/${selectedComponents.length} components
2787
2971
  `)
2788
2972
  );
2789
2973
  const uniqueDeps = [...new Set(allDependencies)];
2790
2974
  const uniqueDevDeps = [...new Set(allDevDependencies)];
2791
2975
  if (uniqueDeps.length || uniqueDevDeps.length) {
2792
- console.log(chalk9.bold("Install dependencies:"));
2976
+ console.log(chalk10.bold("Install dependencies:"));
2793
2977
  if (uniqueDeps.length) {
2794
- console.log(chalk9.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
2978
+ console.log(chalk10.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
2795
2979
  }
2796
2980
  if (uniqueDevDeps.length) {
2797
- console.log(chalk9.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
2981
+ console.log(chalk10.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
2798
2982
  }
2799
2983
  console.log("");
2800
2984
  }
2801
2985
  if (successCount > 0) {
2802
- console.log(chalk9.dim("Import example:"));
2986
+ console.log(chalk10.dim("Import example:"));
2803
2987
  const firstComponent = selectedComponents[0];
2804
2988
  const pascalName = firstComponent.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
2805
2989
  const alias = config.aliases?.components || "@/components/ui";
2806
- console.log(chalk9.dim(` import { ${pascalName} } from '${alias}/${firstComponent}';
2990
+ console.log(chalk10.dim(` import { ${pascalName} } from '${alias}/${firstComponent}';
2807
2991
  `));
2808
2992
  }
2809
2993
  });
2810
2994
 
2811
2995
  // src/index.ts
2812
2996
  var program = new Command9();
2813
- program.name("nativeui").description("Add beautiful UI components to your Expo/React Native project").version("0.0.1");
2997
+ program.name("mcellui").description("Add beautiful UI components to your Expo/React Native project").version("0.1.4");
2998
+ program.configureOutput({
2999
+ writeOut: (str) => process.stdout.write(str),
3000
+ writeErr: (str) => process.stderr.write(str),
3001
+ outputError: (str, write) => write(chalk11.red(str))
3002
+ });
2814
3003
  program.addCommand(initCommand);
2815
3004
  program.addCommand(addCommand);
2816
3005
  program.addCommand(listCommand);
@@ -2819,4 +3008,14 @@ program.addCommand(diffCommand);
2819
3008
  program.addCommand(updateCommand);
2820
3009
  program.addCommand(createCommand);
2821
3010
  program.addCommand(pickCommand);
2822
- program.parse();
3011
+ async function main() {
3012
+ try {
3013
+ await program.parseAsync(process.argv);
3014
+ } catch (error) {
3015
+ handleError({
3016
+ message: error instanceof Error ? error.message : "An unexpected error occurred",
3017
+ hint: "If this persists, run: npx mcellui doctor"
3018
+ });
3019
+ }
3020
+ }
3021
+ main();