@metacells/mcellui-cli 0.1.5 → 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.
- package/dist/index.js +426 -224
- 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
|
|
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
|
|
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
|
|
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://
|
|
206
|
+
See https://mcellui.dev/docs/config for valid options.`
|
|
133
207
|
);
|
|
134
208
|
}
|
|
135
209
|
return result.data;
|
|
@@ -238,7 +312,7 @@ async function getConfig(projectRoot) {
|
|
|
238
312
|
return resolveConfig(validatedConfig);
|
|
239
313
|
} catch (error) {
|
|
240
314
|
if (error instanceof Error && error.message.includes("Invalid configuration")) {
|
|
241
|
-
console.error(
|
|
315
|
+
console.error(chalk2.red(error.message));
|
|
242
316
|
throw error;
|
|
243
317
|
}
|
|
244
318
|
throw error;
|
|
@@ -259,10 +333,10 @@ async function loadTsConfig(configPath) {
|
|
|
259
333
|
return resolveConfig(validatedConfig);
|
|
260
334
|
} catch (error) {
|
|
261
335
|
if (error instanceof Error && error.message.includes("Invalid configuration")) {
|
|
262
|
-
console.error(
|
|
336
|
+
console.error(chalk2.red(error.message));
|
|
263
337
|
throw error;
|
|
264
338
|
}
|
|
265
|
-
console.error(
|
|
339
|
+
console.error(chalk2.red("Failed to load config:"), error);
|
|
266
340
|
return getDefaultConfig();
|
|
267
341
|
}
|
|
268
342
|
}
|
|
@@ -274,10 +348,10 @@ async function loadJsConfig(configPath) {
|
|
|
274
348
|
return resolveConfig(validatedConfig);
|
|
275
349
|
} catch (error) {
|
|
276
350
|
if (error instanceof Error && error.message.includes("Invalid configuration")) {
|
|
277
|
-
console.error(
|
|
351
|
+
console.error(chalk2.red(error.message));
|
|
278
352
|
throw error;
|
|
279
353
|
}
|
|
280
|
-
console.error(
|
|
354
|
+
console.error(chalk2.red("Failed to load config:"), error);
|
|
281
355
|
return getDefaultConfig();
|
|
282
356
|
}
|
|
283
357
|
}
|
|
@@ -311,27 +385,25 @@ var initCommand = new Command().name("init").description("Initialize mcellui in
|
|
|
311
385
|
const cwd = path2.resolve(options.cwd);
|
|
312
386
|
const projectRoot = await getProjectRoot(cwd);
|
|
313
387
|
if (!projectRoot) {
|
|
314
|
-
|
|
315
|
-
console.log(chalk2.dim("Make sure you run this command in a project with package.json"));
|
|
316
|
-
process.exit(1);
|
|
388
|
+
errors.noProject();
|
|
317
389
|
}
|
|
318
390
|
console.log();
|
|
319
|
-
console.log(
|
|
320
|
-
console.log(
|
|
391
|
+
console.log(chalk3.bold("Welcome to mcellui!"));
|
|
392
|
+
console.log(chalk3.dim("The copy-paste component library for Expo/React Native"));
|
|
321
393
|
console.log();
|
|
322
394
|
const projectType = await detectProjectType(projectRoot);
|
|
323
|
-
console.log(
|
|
395
|
+
console.log(chalk3.dim(`Detected: ${projectType}`));
|
|
324
396
|
const configPath = path2.join(projectRoot, "mcellui.config.ts");
|
|
325
397
|
const legacyConfigPath = path2.join(projectRoot, "nativeui.config.ts");
|
|
326
398
|
if (await fs2.pathExists(configPath)) {
|
|
327
|
-
console.log(
|
|
328
|
-
console.log(
|
|
399
|
+
console.log(chalk3.yellow("Project already initialized."));
|
|
400
|
+
console.log(chalk3.dim(`Config found at: ${configPath}`));
|
|
329
401
|
return;
|
|
330
402
|
}
|
|
331
403
|
if (await fs2.pathExists(legacyConfigPath)) {
|
|
332
|
-
console.log(
|
|
333
|
-
console.log(
|
|
334
|
-
console.log(
|
|
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"));
|
|
335
407
|
return;
|
|
336
408
|
}
|
|
337
409
|
let config = {
|
|
@@ -364,6 +436,9 @@ var initCommand = new Command().name("init").description("Initialize mcellui in
|
|
|
364
436
|
]
|
|
365
437
|
}
|
|
366
438
|
]);
|
|
439
|
+
if (response.componentsPath === void 0) {
|
|
440
|
+
process.exit(0);
|
|
441
|
+
}
|
|
367
442
|
config = { ...config, ...response };
|
|
368
443
|
}
|
|
369
444
|
spinner.start("Creating configuration...");
|
|
@@ -402,7 +477,7 @@ export default defineConfig({
|
|
|
402
477
|
// },
|
|
403
478
|
|
|
404
479
|
// ============================================
|
|
405
|
-
// CLI Configuration (used by npx
|
|
480
|
+
// CLI Configuration (used by npx mcellui add)
|
|
406
481
|
// ============================================
|
|
407
482
|
|
|
408
483
|
// Path where components will be installed
|
|
@@ -472,25 +547,27 @@ export function cn(...inputs: StyleInput[]): Style {
|
|
|
472
547
|
);
|
|
473
548
|
spinner.succeed("Utilities installed");
|
|
474
549
|
console.log();
|
|
475
|
-
console.log(
|
|
550
|
+
console.log(chalk3.green("Success!") + " mcellui initialized.");
|
|
476
551
|
console.log();
|
|
477
552
|
console.log("Next steps:");
|
|
478
|
-
console.log(
|
|
479
|
-
console.log(
|
|
553
|
+
console.log(chalk3.dim(" 1."), "Add your first component:");
|
|
554
|
+
console.log(chalk3.cyan(" npx mcellui add button"));
|
|
480
555
|
console.log();
|
|
481
|
-
console.log(
|
|
482
|
-
console.log(
|
|
556
|
+
console.log(chalk3.dim(" 2."), "Browse available components:");
|
|
557
|
+
console.log(chalk3.cyan(" npx mcellui list"));
|
|
483
558
|
console.log();
|
|
484
559
|
} catch (error) {
|
|
485
560
|
spinner.fail("Failed to initialize");
|
|
486
|
-
|
|
487
|
-
|
|
561
|
+
handleError({
|
|
562
|
+
message: "Initialization failed",
|
|
563
|
+
hint: error instanceof Error ? error.message : "Check file permissions and try again"
|
|
564
|
+
});
|
|
488
565
|
}
|
|
489
566
|
});
|
|
490
567
|
|
|
491
568
|
// src/commands/add.ts
|
|
492
569
|
import { Command as Command2 } from "commander";
|
|
493
|
-
import
|
|
570
|
+
import chalk4 from "chalk";
|
|
494
571
|
import ora2 from "ora";
|
|
495
572
|
import prompts2 from "prompts";
|
|
496
573
|
import fs5 from "fs-extra";
|
|
@@ -508,6 +585,54 @@ var REGISTRY_URL = hasEnvOverride ? process.env.MCELLUI_REGISTRY_URL || process.
|
|
|
508
585
|
function getLocalRegistryPath() {
|
|
509
586
|
return path3.resolve(__dirname2, "..", "..", "registry");
|
|
510
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
|
+
}
|
|
511
636
|
function isLocalMode() {
|
|
512
637
|
if (REGISTRY_URL) return false;
|
|
513
638
|
const localPath = getLocalRegistryPath();
|
|
@@ -525,18 +650,23 @@ async function getLocalRegistry() {
|
|
|
525
650
|
const registry = await fs3.readJson(registryPath);
|
|
526
651
|
return registry.components;
|
|
527
652
|
} catch (error) {
|
|
528
|
-
|
|
529
|
-
|
|
653
|
+
throw new Error(
|
|
654
|
+
"Failed to load local registry: " + (error instanceof Error ? error.message : String(error))
|
|
655
|
+
);
|
|
530
656
|
}
|
|
531
657
|
}
|
|
532
658
|
async function getRemoteRegistry() {
|
|
533
659
|
try {
|
|
534
|
-
const response = await
|
|
660
|
+
const response = await fetchWithRetry(`${REGISTRY_URL}/registry.json`);
|
|
661
|
+
if (!response.ok) {
|
|
662
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
663
|
+
}
|
|
535
664
|
const registry = await response.json();
|
|
536
665
|
return registry.components;
|
|
537
666
|
} catch (error) {
|
|
538
|
-
|
|
539
|
-
|
|
667
|
+
throw new Error(
|
|
668
|
+
"Failed to fetch registry: " + (error instanceof Error ? error.message : String(error))
|
|
669
|
+
);
|
|
540
670
|
}
|
|
541
671
|
}
|
|
542
672
|
async function fetchComponent(name) {
|
|
@@ -571,7 +701,12 @@ async function fetchLocalComponent(item) {
|
|
|
571
701
|
async function fetchRemoteComponent(item) {
|
|
572
702
|
const files = await Promise.all(
|
|
573
703
|
item.files.map(async (filePath) => {
|
|
574
|
-
const response = await
|
|
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
|
+
}
|
|
575
710
|
const content = await response.text();
|
|
576
711
|
const name = path3.basename(filePath);
|
|
577
712
|
return { name, content };
|
|
@@ -754,35 +889,36 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
754
889
|
const cwd = path5.resolve(options.cwd);
|
|
755
890
|
const projectRoot = await getProjectRoot(cwd);
|
|
756
891
|
if (!projectRoot) {
|
|
757
|
-
|
|
758
|
-
console.log(chalk3.dim("Run `npx nativeui init` first."));
|
|
759
|
-
process.exit(1);
|
|
892
|
+
errors.noProject();
|
|
760
893
|
}
|
|
761
894
|
const config = await getConfig(projectRoot);
|
|
762
895
|
if (!config) {
|
|
763
|
-
|
|
764
|
-
console.log(chalk3.dim("Run `npx nativeui init` first."));
|
|
765
|
-
process.exit(1);
|
|
896
|
+
errors.notInitialized();
|
|
766
897
|
}
|
|
767
898
|
if (!components.length) {
|
|
768
899
|
const registry2 = await getRegistry();
|
|
769
900
|
if (!registry2.length) {
|
|
770
|
-
|
|
771
|
-
|
|
901
|
+
handleError({
|
|
902
|
+
message: "No components found in registry",
|
|
903
|
+
hint: "Check your internet connection or try again later"
|
|
904
|
+
});
|
|
772
905
|
}
|
|
773
906
|
const { selected } = await prompts2({
|
|
774
907
|
type: "multiselect",
|
|
775
908
|
name: "selected",
|
|
776
909
|
message: "Which components would you like to add?",
|
|
777
910
|
choices: registry2.map((item) => ({
|
|
778
|
-
title: `${item.name} ${
|
|
911
|
+
title: `${item.name} ${chalk4.dim(`(${item.status})`)}`,
|
|
779
912
|
value: item.name,
|
|
780
913
|
description: item.description
|
|
781
914
|
})),
|
|
782
915
|
hint: "- Space to select, Enter to confirm"
|
|
783
916
|
});
|
|
917
|
+
if (selected === void 0) {
|
|
918
|
+
process.exit(0);
|
|
919
|
+
}
|
|
784
920
|
if (!selected?.length) {
|
|
785
|
-
console.log(
|
|
921
|
+
console.log(chalk4.dim("No components selected."));
|
|
786
922
|
return;
|
|
787
923
|
}
|
|
788
924
|
components = selected;
|
|
@@ -792,8 +928,11 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
792
928
|
const { resolved, circular } = resolveDependencies(components, registry);
|
|
793
929
|
if (circular) {
|
|
794
930
|
spinner.fail("Circular dependency detected");
|
|
795
|
-
|
|
796
|
-
|
|
931
|
+
handleError({
|
|
932
|
+
message: `Circular dependency: ${formatCircularError(circular)}`,
|
|
933
|
+
hint: "Check component dependencies for cycles",
|
|
934
|
+
code: "CIRCULAR_DEPENDENCY"
|
|
935
|
+
});
|
|
797
936
|
}
|
|
798
937
|
spinner.stop();
|
|
799
938
|
const componentsDir = path5.join(projectRoot, config.componentsPath);
|
|
@@ -801,19 +940,19 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
801
940
|
const installedNames = new Set(getInstalledNames(installedFiles));
|
|
802
941
|
const toInstall = options.overwrite ? resolved : resolved.filter((name) => !installedNames.has(name));
|
|
803
942
|
if (toInstall.length === 0) {
|
|
804
|
-
console.log(
|
|
805
|
-
console.log(
|
|
943
|
+
console.log(chalk4.yellow("All components are already installed."));
|
|
944
|
+
console.log(chalk4.dim("Use --overwrite to reinstall."));
|
|
806
945
|
return;
|
|
807
946
|
}
|
|
808
947
|
const requested = new Set(components);
|
|
809
948
|
const dependencies = toInstall.filter((name) => !requested.has(name));
|
|
810
949
|
console.log();
|
|
811
|
-
console.log(
|
|
950
|
+
console.log(chalk4.bold("Adding components:"));
|
|
812
951
|
for (const name of toInstall) {
|
|
813
952
|
if (requested.has(name)) {
|
|
814
|
-
console.log(
|
|
953
|
+
console.log(chalk4.dim(` - ${name}`));
|
|
815
954
|
} else {
|
|
816
|
-
console.log(
|
|
955
|
+
console.log(chalk4.dim(` - ${name} ${chalk4.cyan("(dependency)")}`));
|
|
817
956
|
}
|
|
818
957
|
}
|
|
819
958
|
console.log();
|
|
@@ -824,19 +963,24 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
824
963
|
message: `Add ${dependencies.length} additional dependencies?`,
|
|
825
964
|
initial: true
|
|
826
965
|
});
|
|
966
|
+
if (confirm === void 0) {
|
|
967
|
+
process.exit(0);
|
|
968
|
+
}
|
|
827
969
|
if (!confirm) {
|
|
828
|
-
console.log(
|
|
970
|
+
console.log(chalk4.dim("Cancelled."));
|
|
829
971
|
return;
|
|
830
972
|
}
|
|
831
973
|
}
|
|
832
974
|
const allDependencies = [];
|
|
833
975
|
const allDevDependencies = [];
|
|
976
|
+
let failCount = 0;
|
|
834
977
|
for (const componentName of toInstall) {
|
|
835
978
|
spinner.start(`Fetching ${componentName}...`);
|
|
836
979
|
try {
|
|
837
980
|
const component = await fetchComponent(componentName);
|
|
838
981
|
if (!component) {
|
|
839
982
|
spinner.fail(`Component "${componentName}" not found`);
|
|
983
|
+
failCount++;
|
|
840
984
|
continue;
|
|
841
985
|
}
|
|
842
986
|
const targetDir = path5.join(projectRoot, config.componentsPath);
|
|
@@ -859,36 +1003,42 @@ var addCommand = new Command2().name("add").description("Add a component to your
|
|
|
859
1003
|
}
|
|
860
1004
|
} catch (error) {
|
|
861
1005
|
spinner.fail(`Failed to add ${componentName}`);
|
|
862
|
-
console.error(
|
|
1006
|
+
console.error(chalk4.dim(String(error)));
|
|
1007
|
+
failCount++;
|
|
863
1008
|
}
|
|
864
1009
|
}
|
|
1010
|
+
if (failCount > 0) {
|
|
1011
|
+
process.exit(1);
|
|
1012
|
+
}
|
|
865
1013
|
const uniqueDeps = [...new Set(allDependencies)];
|
|
866
1014
|
const uniqueDevDeps = [...new Set(allDevDependencies)];
|
|
867
1015
|
if (uniqueDeps.length || uniqueDevDeps.length) {
|
|
868
1016
|
console.log();
|
|
869
|
-
console.log(
|
|
1017
|
+
console.log(chalk4.bold("Install dependencies:"));
|
|
870
1018
|
if (uniqueDeps.length) {
|
|
871
|
-
console.log(
|
|
1019
|
+
console.log(chalk4.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
|
|
872
1020
|
}
|
|
873
1021
|
if (uniqueDevDeps.length) {
|
|
874
|
-
console.log(
|
|
1022
|
+
console.log(chalk4.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
|
|
875
1023
|
}
|
|
876
1024
|
}
|
|
877
1025
|
console.log();
|
|
878
|
-
console.log(
|
|
1026
|
+
console.log(chalk4.green("Done!"));
|
|
879
1027
|
} catch (error) {
|
|
880
1028
|
spinner.fail("Failed");
|
|
881
|
-
|
|
882
|
-
|
|
1029
|
+
handleError({
|
|
1030
|
+
message: "Failed to add components",
|
|
1031
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1032
|
+
});
|
|
883
1033
|
}
|
|
884
1034
|
});
|
|
885
1035
|
|
|
886
1036
|
// src/commands/list.ts
|
|
887
1037
|
import { Command as Command3 } from "commander";
|
|
888
|
-
import
|
|
1038
|
+
import chalk5 from "chalk";
|
|
889
1039
|
import ora3 from "ora";
|
|
890
1040
|
import path6 from "path";
|
|
891
|
-
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) => {
|
|
892
1042
|
if (options.installed) {
|
|
893
1043
|
await listInstalledComponents(options);
|
|
894
1044
|
} else {
|
|
@@ -900,8 +1050,13 @@ async function listAvailableComponents(options) {
|
|
|
900
1050
|
try {
|
|
901
1051
|
const registry = await getRegistry();
|
|
902
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
|
+
}
|
|
903
1058
|
console.log();
|
|
904
|
-
console.log(
|
|
1059
|
+
console.log(chalk5.bold("Available Components"));
|
|
905
1060
|
console.log();
|
|
906
1061
|
const categories = /* @__PURE__ */ new Map();
|
|
907
1062
|
for (const item of registry) {
|
|
@@ -915,20 +1070,22 @@ async function listAvailableComponents(options) {
|
|
|
915
1070
|
categories.get(category).push(item);
|
|
916
1071
|
}
|
|
917
1072
|
for (const [category, items] of categories) {
|
|
918
|
-
console.log(
|
|
1073
|
+
console.log(chalk5.cyan.bold(`${category}`));
|
|
919
1074
|
for (const item of items) {
|
|
920
|
-
const status = item.status === "stable" ? "" :
|
|
921
|
-
console.log(` ${
|
|
922
|
-
console.log(
|
|
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}`));
|
|
923
1078
|
}
|
|
924
1079
|
console.log();
|
|
925
1080
|
}
|
|
926
|
-
console.log(
|
|
1081
|
+
console.log(chalk5.dim("Add a component: npx mcellui add <component>"));
|
|
927
1082
|
console.log();
|
|
928
1083
|
} catch (error) {
|
|
929
1084
|
spinner.fail("Failed to fetch components");
|
|
930
|
-
|
|
931
|
-
|
|
1085
|
+
handleError({
|
|
1086
|
+
message: "Failed to fetch components",
|
|
1087
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1088
|
+
});
|
|
932
1089
|
}
|
|
933
1090
|
}
|
|
934
1091
|
async function listInstalledComponents(options) {
|
|
@@ -937,22 +1094,23 @@ async function listInstalledComponents(options) {
|
|
|
937
1094
|
const cwd = path6.resolve(options.cwd || process.cwd());
|
|
938
1095
|
const projectRoot = await getProjectRoot(cwd);
|
|
939
1096
|
if (!projectRoot) {
|
|
940
|
-
|
|
941
|
-
console.log(chalk4.dim("Run `npx mcellui init` first."));
|
|
942
|
-
process.exit(1);
|
|
1097
|
+
errors.noProject();
|
|
943
1098
|
}
|
|
944
1099
|
const config = await getConfig(projectRoot);
|
|
945
1100
|
if (!config) {
|
|
946
|
-
|
|
947
|
-
console.log(chalk4.dim("Run `npx mcellui init` first."));
|
|
948
|
-
process.exit(1);
|
|
1101
|
+
errors.notInitialized();
|
|
949
1102
|
}
|
|
950
1103
|
spinner.start("Scanning installed components...");
|
|
951
1104
|
const componentsDir = path6.join(projectRoot, config.componentsPath);
|
|
952
1105
|
const installedFiles = await getInstalledFiles(componentsDir);
|
|
953
1106
|
if (installedFiles.length === 0) {
|
|
1107
|
+
spinner.stop();
|
|
1108
|
+
if (options.json) {
|
|
1109
|
+
console.log(JSON.stringify([], null, 2));
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
954
1112
|
spinner.info("No components installed yet.");
|
|
955
|
-
console.log(
|
|
1113
|
+
console.log(chalk5.dim("\nAdd components with: npx mcellui add <component>"));
|
|
956
1114
|
return;
|
|
957
1115
|
}
|
|
958
1116
|
spinner.text = "Fetching registry...";
|
|
@@ -960,13 +1118,17 @@ async function listInstalledComponents(options) {
|
|
|
960
1118
|
spinner.text = "Comparing components...";
|
|
961
1119
|
const installed = await getInstallStatus(installedFiles, registry, config);
|
|
962
1120
|
spinner.stop();
|
|
1121
|
+
if (options.json) {
|
|
1122
|
+
console.log(JSON.stringify(installed, null, 2));
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
963
1125
|
const identical = installed.filter((c) => c.status === "identical");
|
|
964
1126
|
const modified = installed.filter((c) => c.status === "modified");
|
|
965
1127
|
const localOnly = installed.filter((c) => c.status === "local-only");
|
|
966
1128
|
const installedNames = new Set(installed.map((c) => c.name));
|
|
967
1129
|
const notInstalled = registry.filter((item) => !installedNames.has(item.name));
|
|
968
1130
|
console.log();
|
|
969
|
-
console.log(
|
|
1131
|
+
console.log(chalk5.bold(`Installed Components (${installed.length})`));
|
|
970
1132
|
console.log();
|
|
971
1133
|
const categories = /* @__PURE__ */ new Map();
|
|
972
1134
|
for (const comp of installed) {
|
|
@@ -978,56 +1140,58 @@ async function listInstalledComponents(options) {
|
|
|
978
1140
|
categories.get(category).push(comp);
|
|
979
1141
|
}
|
|
980
1142
|
for (const [category, components] of categories) {
|
|
981
|
-
console.log(
|
|
1143
|
+
console.log(chalk5.cyan.bold(category));
|
|
982
1144
|
for (const comp of components) {
|
|
983
1145
|
let statusIcon;
|
|
984
1146
|
let statusText;
|
|
985
1147
|
switch (comp.status) {
|
|
986
1148
|
case "identical":
|
|
987
|
-
statusIcon =
|
|
988
|
-
statusText =
|
|
1149
|
+
statusIcon = chalk5.green("\u2713");
|
|
1150
|
+
statusText = chalk5.dim("(up to date)");
|
|
989
1151
|
break;
|
|
990
1152
|
case "modified":
|
|
991
|
-
statusIcon =
|
|
992
|
-
statusText =
|
|
1153
|
+
statusIcon = chalk5.yellow("\u26A0");
|
|
1154
|
+
statusText = chalk5.yellow("(modified locally)");
|
|
993
1155
|
break;
|
|
994
1156
|
case "local-only":
|
|
995
|
-
statusIcon =
|
|
996
|
-
statusText =
|
|
1157
|
+
statusIcon = chalk5.blue("?");
|
|
1158
|
+
statusText = chalk5.dim("(custom component)");
|
|
997
1159
|
break;
|
|
998
1160
|
}
|
|
999
|
-
console.log(` ${statusIcon} ${
|
|
1161
|
+
console.log(` ${statusIcon} ${chalk5.white(comp.name)} ${statusText}`);
|
|
1000
1162
|
}
|
|
1001
1163
|
console.log();
|
|
1002
1164
|
}
|
|
1003
1165
|
if (notInstalled.length > 0) {
|
|
1004
|
-
console.log(
|
|
1166
|
+
console.log(chalk5.dim("Not Installed"));
|
|
1005
1167
|
const notInstalledNames = notInstalled.map((c) => c.name).slice(0, 10);
|
|
1006
1168
|
const remaining = notInstalled.length - 10;
|
|
1007
|
-
console.log(
|
|
1169
|
+
console.log(chalk5.dim(` ${notInstalledNames.join(", ")}${remaining > 0 ? `, ... +${remaining} more` : ""}`));
|
|
1008
1170
|
console.log();
|
|
1009
1171
|
}
|
|
1010
|
-
console.log(
|
|
1172
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
1011
1173
|
const parts = [];
|
|
1012
|
-
if (identical.length > 0) parts.push(
|
|
1013
|
-
if (modified.length > 0) parts.push(
|
|
1014
|
-
if (localOnly.length > 0) parts.push(
|
|
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`));
|
|
1015
1177
|
console.log(parts.join(" \u2022 "));
|
|
1016
1178
|
if (modified.length > 0) {
|
|
1017
1179
|
console.log();
|
|
1018
|
-
console.log(
|
|
1019
|
-
console.log(
|
|
1180
|
+
console.log(chalk5.dim("Sync modified components:"));
|
|
1181
|
+
console.log(chalk5.cyan(` npx mcellui diff`));
|
|
1020
1182
|
}
|
|
1021
1183
|
} catch (error) {
|
|
1022
1184
|
spinner.fail("Failed to list installed components");
|
|
1023
|
-
|
|
1024
|
-
|
|
1185
|
+
handleError({
|
|
1186
|
+
message: "Failed to list installed components",
|
|
1187
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1188
|
+
});
|
|
1025
1189
|
}
|
|
1026
1190
|
}
|
|
1027
1191
|
|
|
1028
1192
|
// src/commands/doctor.ts
|
|
1029
1193
|
import { Command as Command4 } from "commander";
|
|
1030
|
-
import
|
|
1194
|
+
import chalk6 from "chalk";
|
|
1031
1195
|
import fs6 from "fs-extra";
|
|
1032
1196
|
import path7 from "path";
|
|
1033
1197
|
var REQUIRED_PEER_DEPS = [
|
|
@@ -1408,43 +1572,43 @@ async function checkExpoGo(projectRoot) {
|
|
|
1408
1572
|
}
|
|
1409
1573
|
function printReport(report) {
|
|
1410
1574
|
console.log();
|
|
1411
|
-
console.log(
|
|
1412
|
-
console.log(
|
|
1575
|
+
console.log(chalk6.bold("mcellui Doctor"));
|
|
1576
|
+
console.log(chalk6.dim("Checking your project setup..."));
|
|
1413
1577
|
console.log();
|
|
1414
|
-
console.log(
|
|
1415
|
-
console.log(
|
|
1416
|
-
console.log(
|
|
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);
|
|
1417
1581
|
console.log();
|
|
1418
|
-
console.log(
|
|
1582
|
+
console.log(chalk6.bold("Checks"));
|
|
1419
1583
|
console.log();
|
|
1420
1584
|
for (const check of report.checks) {
|
|
1421
|
-
const icon = check.status === "pass" ?
|
|
1422
|
-
const statusColor = check.status === "pass" ?
|
|
1423
|
-
console.log(` ${icon} ${
|
|
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)}`);
|
|
1424
1588
|
console.log(` ${statusColor(check.message)}`);
|
|
1425
1589
|
if (check.fix && check.status !== "pass") {
|
|
1426
|
-
console.log(
|
|
1590
|
+
console.log(chalk6.dim(` Fix: ${check.fix}`));
|
|
1427
1591
|
}
|
|
1428
1592
|
}
|
|
1429
1593
|
console.log();
|
|
1430
1594
|
const summaryParts = [];
|
|
1431
1595
|
if (report.passed > 0) {
|
|
1432
|
-
summaryParts.push(
|
|
1596
|
+
summaryParts.push(chalk6.green(`${report.passed} passed`));
|
|
1433
1597
|
}
|
|
1434
1598
|
if (report.warnings > 0) {
|
|
1435
|
-
summaryParts.push(
|
|
1599
|
+
summaryParts.push(chalk6.yellow(`${report.warnings} warnings`));
|
|
1436
1600
|
}
|
|
1437
1601
|
if (report.failed > 0) {
|
|
1438
|
-
summaryParts.push(
|
|
1602
|
+
summaryParts.push(chalk6.red(`${report.failed} failed`));
|
|
1439
1603
|
}
|
|
1440
|
-
console.log(
|
|
1604
|
+
console.log(chalk6.bold("Summary:"), summaryParts.join(", "));
|
|
1441
1605
|
console.log();
|
|
1442
1606
|
if (report.failed > 0) {
|
|
1443
|
-
console.log(
|
|
1607
|
+
console.log(chalk6.red("Some checks failed. Please fix the issues above."));
|
|
1444
1608
|
} else if (report.warnings > 0) {
|
|
1445
|
-
console.log(
|
|
1609
|
+
console.log(chalk6.yellow("Your project has some warnings but should work."));
|
|
1446
1610
|
} else {
|
|
1447
|
-
console.log(
|
|
1611
|
+
console.log(chalk6.green("Your project is properly configured!"));
|
|
1448
1612
|
}
|
|
1449
1613
|
console.log();
|
|
1450
1614
|
}
|
|
@@ -1453,9 +1617,7 @@ var doctorCommand = new Command4().name("doctor").description("Check project set
|
|
|
1453
1617
|
const cwd = path7.resolve(options.cwd);
|
|
1454
1618
|
const projectRoot = await getProjectRoot(cwd);
|
|
1455
1619
|
if (!projectRoot) {
|
|
1456
|
-
|
|
1457
|
-
console.log(chalk5.dim("Make sure you run this command in a project directory."));
|
|
1458
|
-
process.exit(1);
|
|
1620
|
+
errors.noProject();
|
|
1459
1621
|
}
|
|
1460
1622
|
const projectType = await detectProjectType(projectRoot);
|
|
1461
1623
|
const packageManager = await detectPackageManager(projectRoot);
|
|
@@ -1493,14 +1655,16 @@ var doctorCommand = new Command4().name("doctor").description("Check project set
|
|
|
1493
1655
|
process.exit(1);
|
|
1494
1656
|
}
|
|
1495
1657
|
} catch (error) {
|
|
1496
|
-
|
|
1497
|
-
|
|
1658
|
+
handleError({
|
|
1659
|
+
message: "Doctor check failed",
|
|
1660
|
+
hint: error instanceof Error ? error.message : "Run again with --json for details"
|
|
1661
|
+
});
|
|
1498
1662
|
}
|
|
1499
1663
|
});
|
|
1500
1664
|
|
|
1501
1665
|
// src/commands/diff.ts
|
|
1502
1666
|
import { Command as Command5 } from "commander";
|
|
1503
|
-
import
|
|
1667
|
+
import chalk7 from "chalk";
|
|
1504
1668
|
import ora4 from "ora";
|
|
1505
1669
|
import fs7 from "fs-extra";
|
|
1506
1670
|
import path8 from "path";
|
|
@@ -1511,22 +1675,18 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1511
1675
|
const cwd = path8.resolve(options.cwd);
|
|
1512
1676
|
const projectRoot = await getProjectRoot(cwd);
|
|
1513
1677
|
if (!projectRoot) {
|
|
1514
|
-
|
|
1515
|
-
console.log(chalk6.dim("Run `npx mcellui init` first."));
|
|
1516
|
-
process.exit(1);
|
|
1678
|
+
errors.noProject();
|
|
1517
1679
|
}
|
|
1518
1680
|
const config = await getConfig(projectRoot);
|
|
1519
1681
|
if (!config) {
|
|
1520
|
-
|
|
1521
|
-
console.log(chalk6.dim("Run `npx mcellui init` first."));
|
|
1522
|
-
process.exit(1);
|
|
1682
|
+
errors.notInitialized();
|
|
1523
1683
|
}
|
|
1524
1684
|
spinner.start("Scanning installed components...");
|
|
1525
1685
|
const componentsDir = path8.join(projectRoot, config.componentsPath);
|
|
1526
1686
|
const installedFiles = await getInstalledFiles(componentsDir);
|
|
1527
1687
|
if (installedFiles.length === 0) {
|
|
1528
1688
|
spinner.info("No components installed yet.");
|
|
1529
|
-
console.log(
|
|
1689
|
+
console.log(chalk7.dim("\nAdd components with: npx mcellui add <component>"));
|
|
1530
1690
|
return;
|
|
1531
1691
|
}
|
|
1532
1692
|
spinner.text = "Fetching registry...";
|
|
@@ -1548,8 +1708,11 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1548
1708
|
return componentFileNames.includes(fileName);
|
|
1549
1709
|
});
|
|
1550
1710
|
if (filesToCompare.length === 0) {
|
|
1551
|
-
spinner.
|
|
1552
|
-
|
|
1711
|
+
spinner.stop();
|
|
1712
|
+
handleError({
|
|
1713
|
+
message: "None of the specified components are installed",
|
|
1714
|
+
hint: "Check component names: npx mcellui list --installed"
|
|
1715
|
+
});
|
|
1553
1716
|
}
|
|
1554
1717
|
}
|
|
1555
1718
|
spinner.text = "Comparing components...";
|
|
@@ -1633,35 +1796,37 @@ var diffCommand = new Command5().name("diff").description("Compare locally insta
|
|
|
1633
1796
|
const hasChanges = results.some((r) => r.status === "modified");
|
|
1634
1797
|
process.exit(hasChanges ? 1 : 0);
|
|
1635
1798
|
} catch (error) {
|
|
1636
|
-
spinner.
|
|
1637
|
-
|
|
1638
|
-
|
|
1799
|
+
spinner.stop();
|
|
1800
|
+
handleError({
|
|
1801
|
+
message: "Failed to diff components",
|
|
1802
|
+
hint: error instanceof Error ? error.message : "Check your network connection"
|
|
1803
|
+
});
|
|
1639
1804
|
}
|
|
1640
1805
|
});
|
|
1641
1806
|
function printResults(results, listOnly) {
|
|
1642
1807
|
const identical = results.filter((r) => r.status === "identical");
|
|
1643
1808
|
const modified = results.filter((r) => r.status === "modified");
|
|
1644
1809
|
const localOnly = results.filter((r) => r.status === "local-only");
|
|
1645
|
-
const
|
|
1810
|
+
const errors2 = results.filter((r) => r.status === "error");
|
|
1646
1811
|
console.log();
|
|
1647
|
-
console.log(
|
|
1812
|
+
console.log(chalk7.bold("Comparing components..."));
|
|
1648
1813
|
console.log();
|
|
1649
1814
|
for (const result of results) {
|
|
1650
1815
|
switch (result.status) {
|
|
1651
1816
|
case "identical":
|
|
1652
|
-
console.log(`${
|
|
1817
|
+
console.log(`${chalk7.green("\u2713")} ${result.fileName} ${chalk7.dim("(identical)")}`);
|
|
1653
1818
|
break;
|
|
1654
1819
|
case "modified":
|
|
1655
|
-
console.log(`${
|
|
1820
|
+
console.log(`${chalk7.red("\u2717")} ${result.fileName} ${chalk7.yellow("(modified)")}`);
|
|
1656
1821
|
if (!listOnly && result.diff) {
|
|
1657
1822
|
printColoredDiff(result.diff);
|
|
1658
1823
|
}
|
|
1659
1824
|
break;
|
|
1660
1825
|
case "local-only":
|
|
1661
|
-
console.log(`${
|
|
1826
|
+
console.log(`${chalk7.yellow("\u26A0")} ${result.fileName} ${chalk7.dim("(not in registry)")}`);
|
|
1662
1827
|
break;
|
|
1663
1828
|
case "error":
|
|
1664
|
-
console.log(`${
|
|
1829
|
+
console.log(`${chalk7.red("!")} ${result.fileName} ${chalk7.red(`(error: ${result.error})`)}`);
|
|
1665
1830
|
break;
|
|
1666
1831
|
}
|
|
1667
1832
|
}
|
|
@@ -1670,12 +1835,12 @@ function printResults(results, listOnly) {
|
|
|
1670
1835
|
if (identical.length > 0) parts.push(`${identical.length} identical`);
|
|
1671
1836
|
if (modified.length > 0) parts.push(`${modified.length} modified`);
|
|
1672
1837
|
if (localOnly.length > 0) parts.push(`${localOnly.length} custom`);
|
|
1673
|
-
if (
|
|
1674
|
-
console.log(
|
|
1838
|
+
if (errors2.length > 0) parts.push(`${errors2.length} errors`);
|
|
1839
|
+
console.log(chalk7.dim(`Summary: ${parts.join(", ")}`));
|
|
1675
1840
|
if (modified.length > 0) {
|
|
1676
1841
|
console.log();
|
|
1677
|
-
console.log(
|
|
1678
|
-
console.log(
|
|
1842
|
+
console.log(chalk7.dim("Update modified components with:"));
|
|
1843
|
+
console.log(chalk7.cyan(` npx mcellui add ${modified.map((m) => m.name).join(" ")} --overwrite`));
|
|
1679
1844
|
}
|
|
1680
1845
|
}
|
|
1681
1846
|
function printColoredDiff(diffOutput) {
|
|
@@ -1683,20 +1848,20 @@ function printColoredDiff(diffOutput) {
|
|
|
1683
1848
|
const contentLines = lines.slice(4);
|
|
1684
1849
|
for (const line of contentLines) {
|
|
1685
1850
|
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
1686
|
-
console.log(
|
|
1851
|
+
console.log(chalk7.green(` ${line}`));
|
|
1687
1852
|
} else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
1688
|
-
console.log(
|
|
1853
|
+
console.log(chalk7.red(` ${line}`));
|
|
1689
1854
|
} else if (line.startsWith("@@")) {
|
|
1690
|
-
console.log(
|
|
1855
|
+
console.log(chalk7.cyan(` ${line}`));
|
|
1691
1856
|
} else if (line.trim()) {
|
|
1692
|
-
console.log(
|
|
1857
|
+
console.log(chalk7.dim(` ${line}`));
|
|
1693
1858
|
}
|
|
1694
1859
|
}
|
|
1695
1860
|
}
|
|
1696
1861
|
|
|
1697
1862
|
// src/commands/update.ts
|
|
1698
1863
|
import { Command as Command6 } from "commander";
|
|
1699
|
-
import
|
|
1864
|
+
import chalk8 from "chalk";
|
|
1700
1865
|
import ora5 from "ora";
|
|
1701
1866
|
import prompts3 from "prompts";
|
|
1702
1867
|
import fs8 from "fs-extra";
|
|
@@ -1707,22 +1872,18 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1707
1872
|
const cwd = path9.resolve(options.cwd);
|
|
1708
1873
|
const projectRoot = await getProjectRoot(cwd);
|
|
1709
1874
|
if (!projectRoot) {
|
|
1710
|
-
|
|
1711
|
-
console.log(chalk7.dim("Run `npx nativeui init` first."));
|
|
1712
|
-
process.exit(1);
|
|
1875
|
+
errors.noProject();
|
|
1713
1876
|
}
|
|
1714
1877
|
const config = await getConfig(projectRoot);
|
|
1715
1878
|
if (!config) {
|
|
1716
|
-
|
|
1717
|
-
console.log(chalk7.dim("Run `npx nativeui init` first."));
|
|
1718
|
-
process.exit(1);
|
|
1879
|
+
errors.notInitialized();
|
|
1719
1880
|
}
|
|
1720
1881
|
spinner.start("Checking for updates...");
|
|
1721
1882
|
const componentsDir = path9.join(projectRoot, config.componentsPath);
|
|
1722
1883
|
const diffs = await getComponentDiffs(componentsDir, config);
|
|
1723
1884
|
if (diffs.length === 0) {
|
|
1724
1885
|
spinner.info("No components installed yet.");
|
|
1725
|
-
console.log(
|
|
1886
|
+
console.log(chalk8.dim("\nAdd components with: npx mcellui add <component>"));
|
|
1726
1887
|
return;
|
|
1727
1888
|
}
|
|
1728
1889
|
spinner.stop();
|
|
@@ -1731,7 +1892,7 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1731
1892
|
toUpdate = diffs.filter((d) => components.includes(d.name));
|
|
1732
1893
|
const notFound = components.filter((c) => !diffs.some((d) => d.name === c));
|
|
1733
1894
|
if (notFound.length > 0) {
|
|
1734
|
-
console.log(
|
|
1895
|
+
console.log(chalk8.yellow(`Components not found: ${notFound.join(", ")}`));
|
|
1735
1896
|
}
|
|
1736
1897
|
} else if (options.all) {
|
|
1737
1898
|
toUpdate = diffs;
|
|
@@ -1739,19 +1900,19 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1739
1900
|
toUpdate = diffs.filter((d) => d.hasUpdate);
|
|
1740
1901
|
}
|
|
1741
1902
|
if (toUpdate.length === 0) {
|
|
1742
|
-
console.log(
|
|
1903
|
+
console.log(chalk8.green("\n\u2713 All components are up to date!"));
|
|
1743
1904
|
return;
|
|
1744
1905
|
}
|
|
1745
1906
|
console.log();
|
|
1746
|
-
console.log(
|
|
1907
|
+
console.log(chalk8.bold(`Components to update (${toUpdate.length}):`));
|
|
1747
1908
|
for (const comp of toUpdate) {
|
|
1748
|
-
const status = comp.hasUpdate ?
|
|
1749
|
-
const label = comp.hasUpdate ?
|
|
1909
|
+
const status = comp.hasUpdate ? chalk8.yellow("\u25CF") : chalk8.green("\u25CF");
|
|
1910
|
+
const label = comp.hasUpdate ? chalk8.dim("(update available)") : chalk8.dim("(re-sync)");
|
|
1750
1911
|
console.log(` ${status} ${comp.name} ${label}`);
|
|
1751
1912
|
}
|
|
1752
1913
|
console.log();
|
|
1753
1914
|
if (options.dryRun) {
|
|
1754
|
-
console.log(
|
|
1915
|
+
console.log(chalk8.dim("Dry run mode - no changes made."));
|
|
1755
1916
|
return;
|
|
1756
1917
|
}
|
|
1757
1918
|
if (!options.yes) {
|
|
@@ -1761,8 +1922,11 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1761
1922
|
message: `Update ${toUpdate.length} component${toUpdate.length !== 1 ? "s" : ""}?`,
|
|
1762
1923
|
initial: true
|
|
1763
1924
|
});
|
|
1925
|
+
if (confirm === void 0) {
|
|
1926
|
+
process.exit(0);
|
|
1927
|
+
}
|
|
1764
1928
|
if (!confirm) {
|
|
1765
|
-
console.log(
|
|
1929
|
+
console.log(chalk8.dim("Cancelled."));
|
|
1766
1930
|
return;
|
|
1767
1931
|
}
|
|
1768
1932
|
}
|
|
@@ -1802,27 +1966,32 @@ var updateCommand = new Command6().name("update").description("Update installed
|
|
|
1802
1966
|
}
|
|
1803
1967
|
console.log();
|
|
1804
1968
|
if (successCount > 0) {
|
|
1805
|
-
console.log(
|
|
1969
|
+
console.log(chalk8.green(`\u2713 Updated ${successCount} component${successCount !== 1 ? "s" : ""}`));
|
|
1806
1970
|
}
|
|
1807
1971
|
if (failCount > 0) {
|
|
1808
|
-
console.log(
|
|
1972
|
+
console.log(chalk8.red(`\u2717 Failed to update ${failCount} component${failCount !== 1 ? "s" : ""}`));
|
|
1809
1973
|
}
|
|
1810
1974
|
const uniqueDeps = [...new Set(allDependencies)];
|
|
1811
1975
|
const uniqueDevDeps = [...new Set(allDevDependencies)];
|
|
1812
1976
|
if (uniqueDeps.length || uniqueDevDeps.length) {
|
|
1813
1977
|
console.log();
|
|
1814
|
-
console.log(
|
|
1978
|
+
console.log(chalk8.bold("Install/update dependencies:"));
|
|
1815
1979
|
if (uniqueDeps.length) {
|
|
1816
|
-
console.log(
|
|
1980
|
+
console.log(chalk8.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
|
|
1817
1981
|
}
|
|
1818
1982
|
if (uniqueDevDeps.length) {
|
|
1819
|
-
console.log(
|
|
1983
|
+
console.log(chalk8.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
|
|
1820
1984
|
}
|
|
1821
1985
|
}
|
|
1986
|
+
if (failCount > 0) {
|
|
1987
|
+
process.exit(1);
|
|
1988
|
+
}
|
|
1822
1989
|
} catch (error) {
|
|
1823
1990
|
spinner.fail("Failed to update");
|
|
1824
|
-
|
|
1825
|
-
|
|
1991
|
+
handleError({
|
|
1992
|
+
message: "Failed to update components",
|
|
1993
|
+
hint: error instanceof Error ? error.message : "Check your network connection and try again"
|
|
1994
|
+
});
|
|
1826
1995
|
}
|
|
1827
1996
|
});
|
|
1828
1997
|
async function getComponentDiffs(componentsDir, config) {
|
|
@@ -1878,7 +2047,7 @@ async function checkForUpdate(localFile, registryItem, config) {
|
|
|
1878
2047
|
|
|
1879
2048
|
// src/commands/create.ts
|
|
1880
2049
|
import { Command as Command7 } from "commander";
|
|
1881
|
-
import
|
|
2050
|
+
import chalk9 from "chalk";
|
|
1882
2051
|
import ora6 from "ora";
|
|
1883
2052
|
import prompts4 from "prompts";
|
|
1884
2053
|
import fs9 from "fs-extra";
|
|
@@ -1889,33 +2058,31 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
|
|
|
1889
2058
|
const cwd = path10.resolve(options.cwd);
|
|
1890
2059
|
const projectRoot = await getProjectRoot(cwd);
|
|
1891
2060
|
if (!projectRoot) {
|
|
1892
|
-
|
|
1893
|
-
console.log(chalk8.dim("Run `npx nativeui init` first."));
|
|
1894
|
-
process.exit(1);
|
|
2061
|
+
errors.noProject();
|
|
1895
2062
|
}
|
|
1896
2063
|
const config = await getConfig(projectRoot);
|
|
1897
2064
|
if (!config) {
|
|
1898
|
-
|
|
1899
|
-
console.log(chalk8.dim("Run `npx nativeui init` first."));
|
|
1900
|
-
process.exit(1);
|
|
2065
|
+
errors.notInitialized();
|
|
1901
2066
|
}
|
|
1902
2067
|
const componentName = toPascalCase(name);
|
|
1903
2068
|
const fileName = toKebabCase(name) + ".tsx";
|
|
1904
2069
|
const targetDir = path10.join(projectRoot, config.componentsPath);
|
|
1905
2070
|
const targetPath = path10.join(targetDir, fileName);
|
|
1906
2071
|
if (await fs9.pathExists(targetPath)) {
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
2072
|
+
handleError({
|
|
2073
|
+
message: `Component already exists: ${fileName}`,
|
|
2074
|
+
hint: "Choose a different name or delete the existing file",
|
|
2075
|
+
code: "COMPONENT_EXISTS"
|
|
2076
|
+
});
|
|
1910
2077
|
}
|
|
1911
2078
|
if (!options.yes) {
|
|
1912
2079
|
console.log();
|
|
1913
|
-
console.log(
|
|
1914
|
-
console.log(` Name: ${
|
|
1915
|
-
console.log(` File: ${
|
|
1916
|
-
console.log(` Path: ${
|
|
1917
|
-
console.log(` Template: ${
|
|
1918
|
-
console.log(` ForwardRef: ${
|
|
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")}`);
|
|
1919
2086
|
console.log();
|
|
1920
2087
|
const { confirm } = await prompts4({
|
|
1921
2088
|
type: "confirm",
|
|
@@ -1923,8 +2090,11 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
|
|
|
1923
2090
|
message: "Create this component?",
|
|
1924
2091
|
initial: true
|
|
1925
2092
|
});
|
|
2093
|
+
if (confirm === void 0) {
|
|
2094
|
+
process.exit(0);
|
|
2095
|
+
}
|
|
1926
2096
|
if (!confirm) {
|
|
1927
|
-
console.log(
|
|
2097
|
+
console.log(chalk9.dim("Cancelled."));
|
|
1928
2098
|
return;
|
|
1929
2099
|
}
|
|
1930
2100
|
}
|
|
@@ -1934,15 +2104,17 @@ var createCommand = new Command7().name("create").description("Scaffold a new cu
|
|
|
1934
2104
|
await fs9.writeFile(targetPath, code);
|
|
1935
2105
|
spinner.succeed(`Created ${fileName}`);
|
|
1936
2106
|
console.log();
|
|
1937
|
-
console.log(
|
|
1938
|
-
console.log(` 1. Edit your component: ${
|
|
2107
|
+
console.log(chalk9.bold("Next steps:"));
|
|
2108
|
+
console.log(` 1. Edit your component: ${chalk9.cyan(targetPath)}`);
|
|
1939
2109
|
console.log(` 2. Import it in your app:`);
|
|
1940
|
-
console.log(
|
|
2110
|
+
console.log(chalk9.dim(` import { ${componentName} } from '${config.aliases?.components || "@/components"}/ui/${toKebabCase(name)}';`));
|
|
1941
2111
|
console.log();
|
|
1942
2112
|
} catch (error) {
|
|
1943
2113
|
spinner.fail("Failed to create component");
|
|
1944
|
-
|
|
1945
|
-
|
|
2114
|
+
handleError({
|
|
2115
|
+
message: "Failed to create component",
|
|
2116
|
+
hint: error instanceof Error ? error.message : "Check file permissions and try again"
|
|
2117
|
+
});
|
|
1946
2118
|
}
|
|
1947
2119
|
});
|
|
1948
2120
|
function toPascalCase(str) {
|
|
@@ -1976,7 +2148,7 @@ export interface ${name}Props extends ViewProps {
|
|
|
1976
2148
|
/**
|
|
1977
2149
|
* ${name}
|
|
1978
2150
|
*
|
|
1979
|
-
* A custom component created with
|
|
2151
|
+
* A custom component created with mcellui create.
|
|
1980
2152
|
*
|
|
1981
2153
|
* @example
|
|
1982
2154
|
* \`\`\`tsx
|
|
@@ -2036,7 +2208,7 @@ export interface ${name}Props extends ViewProps {
|
|
|
2036
2208
|
/**
|
|
2037
2209
|
* ${name}
|
|
2038
2210
|
*
|
|
2039
|
-
* A custom component created with
|
|
2211
|
+
* A custom component created with mcellui create.
|
|
2040
2212
|
*
|
|
2041
2213
|
* @example
|
|
2042
2214
|
* \`\`\`tsx
|
|
@@ -2103,7 +2275,7 @@ export interface ${name}Props extends ViewProps {
|
|
|
2103
2275
|
/**
|
|
2104
2276
|
* ${name}
|
|
2105
2277
|
*
|
|
2106
|
-
* An animated component created with
|
|
2278
|
+
* An animated component created with mcellui create.
|
|
2107
2279
|
*
|
|
2108
2280
|
* @example
|
|
2109
2281
|
* \`\`\`tsx
|
|
@@ -2178,7 +2350,7 @@ export interface ${name}Props extends Omit<PressableProps, 'style'> {
|
|
|
2178
2350
|
/**
|
|
2179
2351
|
* ${name}
|
|
2180
2352
|
*
|
|
2181
|
-
* A pressable component created with
|
|
2353
|
+
* A pressable component created with mcellui create.
|
|
2182
2354
|
*
|
|
2183
2355
|
* @example
|
|
2184
2356
|
* \`\`\`tsx
|
|
@@ -2271,7 +2443,7 @@ export interface ${name}Props extends Omit<PressableProps, 'style'> {
|
|
|
2271
2443
|
/**
|
|
2272
2444
|
* ${name}
|
|
2273
2445
|
*
|
|
2274
|
-
* A pressable component created with
|
|
2446
|
+
* A pressable component created with mcellui create.
|
|
2275
2447
|
*
|
|
2276
2448
|
* @example
|
|
2277
2449
|
* \`\`\`tsx
|
|
@@ -2359,7 +2531,7 @@ export interface ${name}Props extends TextInputProps {
|
|
|
2359
2531
|
/**
|
|
2360
2532
|
* ${name}
|
|
2361
2533
|
*
|
|
2362
|
-
* A custom input component created with
|
|
2534
|
+
* A custom input component created with mcellui create.
|
|
2363
2535
|
*
|
|
2364
2536
|
* @example
|
|
2365
2537
|
* \`\`\`tsx
|
|
@@ -2484,7 +2656,7 @@ export interface ${name}Props extends TextInputProps {
|
|
|
2484
2656
|
/**
|
|
2485
2657
|
* ${name}
|
|
2486
2658
|
*
|
|
2487
|
-
* A custom input component created with
|
|
2659
|
+
* A custom input component created with mcellui create.
|
|
2488
2660
|
*
|
|
2489
2661
|
* @example
|
|
2490
2662
|
* \`\`\`tsx
|
|
@@ -2584,7 +2756,7 @@ const styles = StyleSheet.create({
|
|
|
2584
2756
|
|
|
2585
2757
|
// src/commands/pick.ts
|
|
2586
2758
|
import { Command as Command8 } from "commander";
|
|
2587
|
-
import
|
|
2759
|
+
import chalk10 from "chalk";
|
|
2588
2760
|
import prompts5 from "prompts";
|
|
2589
2761
|
import ora7 from "ora";
|
|
2590
2762
|
import fs10 from "fs-extra";
|
|
@@ -2636,7 +2808,7 @@ function formatCategoryName(category) {
|
|
|
2636
2808
|
}
|
|
2637
2809
|
function formatComponentChoice(item, installed) {
|
|
2638
2810
|
const isInstalled = installed.has(item.name);
|
|
2639
|
-
const status = isInstalled ?
|
|
2811
|
+
const status = isInstalled ? chalk10.green(" \u2713") : "";
|
|
2640
2812
|
const description = item.description || "";
|
|
2641
2813
|
return {
|
|
2642
2814
|
title: `${item.name}${status}`,
|
|
@@ -2646,24 +2818,24 @@ function formatComponentChoice(item, installed) {
|
|
|
2646
2818
|
};
|
|
2647
2819
|
}
|
|
2648
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) => {
|
|
2649
|
-
console.log(
|
|
2821
|
+
console.log(chalk10.bold("\n\u{1F3A8} mcellui Component Picker\n"));
|
|
2650
2822
|
const cwd = path11.resolve(options.cwd);
|
|
2651
2823
|
const projectRoot = await getProjectRoot(cwd);
|
|
2652
2824
|
if (!projectRoot) {
|
|
2653
|
-
|
|
2654
|
-
console.log(chalk9.dim("Run `npx nativeui init` first.\n"));
|
|
2655
|
-
return;
|
|
2825
|
+
errors.noProject();
|
|
2656
2826
|
}
|
|
2657
2827
|
const config = await getConfig(projectRoot);
|
|
2658
2828
|
if (!config) {
|
|
2659
|
-
|
|
2660
|
-
return;
|
|
2829
|
+
errors.notInitialized();
|
|
2661
2830
|
}
|
|
2662
2831
|
const spinner = ora7("Loading component registry...").start();
|
|
2663
2832
|
const registry = await getRegistry();
|
|
2664
2833
|
if (!registry.length) {
|
|
2665
|
-
spinner.
|
|
2666
|
-
|
|
2834
|
+
spinner.stop();
|
|
2835
|
+
handleError({
|
|
2836
|
+
message: "Could not load component registry",
|
|
2837
|
+
hint: "Check your internet connection and try again"
|
|
2838
|
+
});
|
|
2667
2839
|
}
|
|
2668
2840
|
spinner.succeed(`Loaded ${registry.length} components`);
|
|
2669
2841
|
const componentsDir = path11.join(projectRoot, config.componentsPath);
|
|
@@ -2693,8 +2865,11 @@ var pickCommand = new Command8().name("pick").description("Interactively browse
|
|
|
2693
2865
|
message: "Select a category",
|
|
2694
2866
|
choices: categoryChoices
|
|
2695
2867
|
});
|
|
2868
|
+
if (categoryResponse.category === void 0) {
|
|
2869
|
+
process.exit(0);
|
|
2870
|
+
}
|
|
2696
2871
|
if (!categoryResponse.category) {
|
|
2697
|
-
console.log(
|
|
2872
|
+
console.log(chalk10.yellow("\nCancelled.\n"));
|
|
2698
2873
|
return;
|
|
2699
2874
|
}
|
|
2700
2875
|
selectedCategory = categoryResponse.category;
|
|
@@ -2707,10 +2882,10 @@ var pickCommand = new Command8().name("pick").description("Interactively browse
|
|
|
2707
2882
|
);
|
|
2708
2883
|
const availableCount = componentChoices.filter((c) => !c.disabled).length;
|
|
2709
2884
|
if (availableCount === 0) {
|
|
2710
|
-
console.log(
|
|
2885
|
+
console.log(chalk10.green("\n\u2713 All components in this category are already installed!\n"));
|
|
2711
2886
|
return;
|
|
2712
2887
|
}
|
|
2713
|
-
console.log(
|
|
2888
|
+
console.log(chalk10.dim(`
|
|
2714
2889
|
${installed.size} already installed, ${availableCount} available
|
|
2715
2890
|
`));
|
|
2716
2891
|
const componentResponse = await prompts5({
|
|
@@ -2721,14 +2896,17 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2721
2896
|
hint: "- Space to select. Return to submit",
|
|
2722
2897
|
instructions: false
|
|
2723
2898
|
});
|
|
2899
|
+
if (componentResponse.components === void 0) {
|
|
2900
|
+
process.exit(0);
|
|
2901
|
+
}
|
|
2724
2902
|
if (!componentResponse.components || componentResponse.components.length === 0) {
|
|
2725
|
-
console.log(
|
|
2903
|
+
console.log(chalk10.yellow("\nNo components selected.\n"));
|
|
2726
2904
|
return;
|
|
2727
2905
|
}
|
|
2728
2906
|
const selectedComponents = componentResponse.components;
|
|
2729
|
-
console.log(
|
|
2907
|
+
console.log(chalk10.bold("\nComponents to install:"));
|
|
2730
2908
|
for (const name of selectedComponents) {
|
|
2731
|
-
console.log(
|
|
2909
|
+
console.log(chalk10.cyan(` \u2022 ${name}`));
|
|
2732
2910
|
}
|
|
2733
2911
|
const confirmResponse = await prompts5({
|
|
2734
2912
|
type: "confirm",
|
|
@@ -2736,12 +2914,16 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2736
2914
|
message: `Install ${selectedComponents.length} component(s)?`,
|
|
2737
2915
|
initial: true
|
|
2738
2916
|
});
|
|
2917
|
+
if (confirmResponse.proceed === void 0) {
|
|
2918
|
+
process.exit(0);
|
|
2919
|
+
}
|
|
2739
2920
|
if (!confirmResponse.proceed) {
|
|
2740
|
-
console.log(
|
|
2921
|
+
console.log(chalk10.yellow("\nCancelled.\n"));
|
|
2741
2922
|
return;
|
|
2742
2923
|
}
|
|
2743
2924
|
console.log("");
|
|
2744
2925
|
let successCount = 0;
|
|
2926
|
+
let failCount = 0;
|
|
2745
2927
|
const allDependencies = [];
|
|
2746
2928
|
const allDevDependencies = [];
|
|
2747
2929
|
for (const name of selectedComponents) {
|
|
@@ -2750,6 +2932,7 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2750
2932
|
const component = await fetchComponent(name);
|
|
2751
2933
|
if (!component) {
|
|
2752
2934
|
installSpinner.fail(`Component "${name}" not found`);
|
|
2935
|
+
failCount++;
|
|
2753
2936
|
continue;
|
|
2754
2937
|
}
|
|
2755
2938
|
const targetDir = path11.join(projectRoot, config.componentsPath);
|
|
@@ -2763,7 +2946,7 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2763
2946
|
const transformedContent = transformToInstalled(file.content, config);
|
|
2764
2947
|
await fs10.writeFile(targetPath, transformedContent);
|
|
2765
2948
|
}
|
|
2766
|
-
installSpinner.succeed(`Installed ${
|
|
2949
|
+
installSpinner.succeed(`Installed ${chalk10.green(name)}`);
|
|
2767
2950
|
successCount++;
|
|
2768
2951
|
if (component.dependencies?.length) {
|
|
2769
2952
|
allDependencies.push(...component.dependencies);
|
|
@@ -2772,35 +2955,39 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2772
2955
|
allDevDependencies.push(...component.devDependencies);
|
|
2773
2956
|
}
|
|
2774
2957
|
if (component.registryDependencies?.length) {
|
|
2775
|
-
console.log(
|
|
2958
|
+
console.log(chalk10.dim(` Requires: ${component.registryDependencies.join(", ")}`));
|
|
2776
2959
|
}
|
|
2777
2960
|
} catch (error) {
|
|
2778
2961
|
installSpinner.fail(`Failed to install ${name}: ${error}`);
|
|
2962
|
+
failCount++;
|
|
2779
2963
|
}
|
|
2780
2964
|
}
|
|
2965
|
+
if (failCount > 0) {
|
|
2966
|
+
process.exit(1);
|
|
2967
|
+
}
|
|
2781
2968
|
console.log(
|
|
2782
|
-
|
|
2969
|
+
chalk10.bold.green(`
|
|
2783
2970
|
\u2713 Successfully installed ${successCount}/${selectedComponents.length} components
|
|
2784
2971
|
`)
|
|
2785
2972
|
);
|
|
2786
2973
|
const uniqueDeps = [...new Set(allDependencies)];
|
|
2787
2974
|
const uniqueDevDeps = [...new Set(allDevDependencies)];
|
|
2788
2975
|
if (uniqueDeps.length || uniqueDevDeps.length) {
|
|
2789
|
-
console.log(
|
|
2976
|
+
console.log(chalk10.bold("Install dependencies:"));
|
|
2790
2977
|
if (uniqueDeps.length) {
|
|
2791
|
-
console.log(
|
|
2978
|
+
console.log(chalk10.cyan(` npx expo install ${uniqueDeps.join(" ")}`));
|
|
2792
2979
|
}
|
|
2793
2980
|
if (uniqueDevDeps.length) {
|
|
2794
|
-
console.log(
|
|
2981
|
+
console.log(chalk10.cyan(` npm install -D ${uniqueDevDeps.join(" ")}`));
|
|
2795
2982
|
}
|
|
2796
2983
|
console.log("");
|
|
2797
2984
|
}
|
|
2798
2985
|
if (successCount > 0) {
|
|
2799
|
-
console.log(
|
|
2986
|
+
console.log(chalk10.dim("Import example:"));
|
|
2800
2987
|
const firstComponent = selectedComponents[0];
|
|
2801
2988
|
const pascalName = firstComponent.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
2802
2989
|
const alias = config.aliases?.components || "@/components/ui";
|
|
2803
|
-
console.log(
|
|
2990
|
+
console.log(chalk10.dim(` import { ${pascalName} } from '${alias}/${firstComponent}';
|
|
2804
2991
|
`));
|
|
2805
2992
|
}
|
|
2806
2993
|
});
|
|
@@ -2808,6 +2995,11 @@ ${installed.size} already installed, ${availableCount} available
|
|
|
2808
2995
|
// src/index.ts
|
|
2809
2996
|
var program = new Command9();
|
|
2810
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
|
+
});
|
|
2811
3003
|
program.addCommand(initCommand);
|
|
2812
3004
|
program.addCommand(addCommand);
|
|
2813
3005
|
program.addCommand(listCommand);
|
|
@@ -2816,4 +3008,14 @@ program.addCommand(diffCommand);
|
|
|
2816
3008
|
program.addCommand(updateCommand);
|
|
2817
3009
|
program.addCommand(createCommand);
|
|
2818
3010
|
program.addCommand(pickCommand);
|
|
2819
|
-
|
|
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();
|